《着色器和屏幕特效》读书笔记第二章-表面着色器和纹理映射
2017-10-02 21:35
375 查看
本书版本为“占红来 译”版,笔记会持续更新,有错误的地方欢迎指正,谢谢!
给材质的物理属性赋值(比如漫反射颜色、光滑度等)。这些物理属性会在表面函数(surf())中赋值,之后,存储在表面输出(surface output)的结构中;
表面输出(负责属性和光照模型之间的通信)会传递给光照模型。光照模型也是一个函数,该函数还依赖于场景中的光照信息。所以,光照函数决定了光线在材质上的最终表现。
创建漫反射着色器最快的一种方式:修改标准着色器。
漫反射着色:
标准着色:
Cg中有两种类型的变量:单一变量和包装数组。float3就属于包装数组,尽管它不是数组,而类似于结构体。
包装数组元素的访问:用x、y、z、w或r、g、b、a(这两种是完全等价的)。其实着色器是处理一些位置和颜色的计算,选择合适的名字访问元素会让代码更加表义。
包装数组可以处理类型转换:比如:Albedo是fixed3类型,而_Color是fixed4类型。
包装数组可以对元素重新排序,比如:
补充:
float:32位高精度浮点数
half:16位中精度浮点数
fixed:11位低精度浮点数
操作就是在Unity中赋一个纹理图。着色器知道如何通过UV数据将二维图像映射到三维模型上。
部分代码说明:
有图有真相:
但上述计算模型法线的方法已被法线映射打败。。。
法线映射:法线方向可以通过一个额外的纹理来提供。
补充:bump映射(即凹凸映射)包含法线映射和高度映射,但常把bump映射和法线映射当成相同技术。
Tags是用来添加物体渲染信息的。接下来讲讲其中的Queue:Unity提供了默认渲染序列,见下方表格,每个渲染序列都有一个渲染序列值来告诉Unity其出现的顺序。
看看我搞的玻璃:
全息特效只显示物体的轮廓。
图在这:
需要这里提供三张待混合的图:
还需要一张彩色混合(Blend)纹理图:
待混合的图分别分配到R通道、G通道、B通道,再根据彩色混合纹理的RGB分布,将对应的RGB通道的图混合起来(用的几个lerp(a,b,f)函数进行混合,a和b这两种纹理按照f指定的比例进行混合,即为(1-f)*a+f*b)。
核心代码:
最终效果:
不过就是直接更换纹理图表示圈的那一部分~
见图:
引言
表面着色器是Unity中主要使用的一种着色器,使用表面着色器有两个步骤:给材质的物理属性赋值(比如漫反射颜色、光滑度等)。这些物理属性会在表面函数(surf())中赋值,之后,存储在表面输出(surface output)的结构中;
表面输出(负责属性和光照模型之间的通信)会传递给光照模型。光照模型也是一个函数,该函数还依赖于场景中的光照信息。所以,光照函数决定了光线在材质上的最终表现。
漫反射着色
非反光材料最好的渲染方式是使用漫反射着色器,这是一种大量用到的廉价的着色方式。创建漫反射着色器最快的一种方式:修改标准着色器。
Shader "BookShaders/2-2 Diffuse" { Properties { _Color ("Color", Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 struct Input { float2 uv_MainTex; }; fixed4 _Color; //SurfaceOutputStandard是表面输出结构 void surf (Input IN, inout SurfaceOutputStandard o) { o.Albedo = _Color.rgb; } ENDCG } FallBack "Diffuse" }
漫反射着色:
标准着色:
使用包装数组
常识:GPU需要并行计算的原因:着色器中的代码需要在屏幕的每一个像素点上执行。Cg中有两种类型的变量:单一变量和包装数组。float3就属于包装数组,尽管它不是数组,而类似于结构体。
包装数组元素的访问:用x、y、z、w或r、g、b、a(这两种是完全等价的)。其实着色器是处理一些位置和颜色的计算,选择合适的名字访问元素会让代码更加表义。
包装数组可以处理类型转换:比如:Albedo是fixed3类型,而_Color是fixed4类型。
o.Albedo = _Color.rgb;
包装数组可以对元素重新排序,比如:
o.Albedo = _Color.gbr;
补充:
float:32位高精度浮点数
half:16位中精度浮点数
fixed:11位低精度浮点数
给着色器添加纹理
模型是由三角形组成,三角形的每个顶点可存储着色器可访问的数据,UV数据是其中一个。UV数据只是给顶点用的,三角形其他位置的值则由差值运算按照一定的间隔比例去纹理上取值。模型要有UV组件,才能支持纹理映射。操作就是在Unity中赋一个纹理图。着色器知道如何通过UV数据将二维图像映射到三维模型上。
部分代码说明:
//Input结构包含三维模型需要渲染的每个点的_MainTex的UV值,着色器会识别出uv_MainTex引用的是_MainTex的值。 struct Input { float2 uv_MainTex; }; //UV数据被用来对纹理进行采样: fixed4 c = tex2D(_MainTex,IN.uv_MainTex)*_Color;
通过修改UV值来滑动纹理
实际上是通过修改UV值来移动纹理,能实现瀑布、河流等流动效果:Shader "BookShaders/2-5 ScrollingUVs" { Properties { _MainTint("Diffuse Tint", Color) = (1,1,1,1) _MainTex("Base (RGB)", 2D) = "white" {} //两个新属性用于控制纹理的滑动速度。 _ScrollXSpeed("X Scroll Speed", Range(0, 10)) = 2 _ScrollYSpeed("Y Scroll Speed", Range(0, 10)) = 2 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert fixed4 _MainTint; fixed _ScrollXSpeed; fixed _ScrollYSpeed; sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { fixed2 scrolledUV = IN.uv_MainTex; fixed xScrollValue = _ScrollXSpeed * _Time;//_Time是内建的 fixed yScrollValue = _ScrollYSpeed * _Time; scrolledUV += fixed2(xScrollValue, yScrollValue); //将添加了偏移量的UV值传递给tex2D函数作为纹理的新UV值。 half4 c = tex2D(_MainTex, scrolledUV); o.Albedo = c.rgb * _MainTint; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
有图有真相:
法线映射
模型中每个三角形都有一个面朝的方向,其对于光线在物体表面反射的时候起到了至关重要的作用。但弧形物体表面没法用平的三角形拼出来,这时就要用到法线方向。而法线方向是仅次于UV值的一个非常重要的参数,法线方向是单位长度的向量。与面朝方向不同的是,每个三角形的每个顶点都有一个法线方向,这就意味着一个连接着多个三角形的顶点会有多个法线。而这些顶点的法线方向通过线性插值得到。但上述计算模型法线的方法已被法线映射打败。。。
法线映射:法线方向可以通过一个额外的纹理来提供。
补充:bump映射(即凹凸映射)包含法线映射和高度映射,但常把bump映射和法线映射当成相同技术。
创建透明材质
能实现玻璃等效果:Shader "BookShaders/2-7 Transparent" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} } SubShader{ Tags { //表明着色器是一个透明着色器,即在color中调alpha值是有效的。 "Queue" = "Transparent" //确保物体不受Unity的投影的影响(不明觉厉)。 "IgnoreProjector" = "True" //置换着色器(不明觉厉)。 "RenderType"="Transparent" } Cull Back//确保目标模型背后的几何体是没有画过的(不明觉厉)。 LOD 200 CGPROGRAM #pragma surface surf Standard alpha:fade sampler2D _MainTex; struct Input { float2 uv_MainTex; }; fixed4 _Color; void surf (Input IN, inout SurfaceOutputStandard o) { fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Alpha = c.a;//此时修改有效 } ENDCG } FallBack "Diffuse" }
Tags是用来添加物体渲染信息的。接下来讲讲其中的Queue:Unity提供了默认渲染序列,见下方表格,每个渲染序列都有一个渲染序列值来告诉Unity其出现的顺序。
渲染序列 | 渲染序列值 |
---|---|
几何结构(Geometry) | 2000 |
alpha检查(AlphaTest) | 2450 |
透明(Transparent) | 3000 |
创建全息着色器
可以通过噪声、动画扫描线以及振动来创建非常炫酷的全息特效,它能实现显示物体轮廓、幽灵、冲击波、泡泡护盾等效果:全息特效只显示物体的轮廓。
Shader "BookShaders/2-8 Silhouette" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} //模型边缘由那些法线垂直与视线方向的三角形构成, //用_DotProduct来判断点积多么接近于0时才将三角形视为轮廓。 _DotProduct("RimEffect",range(-1,1)) = 0.25 } SubShader{ Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType"="Transparent" } LOD 200 CGPROGRAM //不是模拟真实材质,就没必要用PBR光照模型(Standard), //alpha:fade表明这是一个透明着色器,nolighting禁用所有光照。 #pragma surface surf Lambert alpha:fade nolighting sampler2D _MainTex; struct Input { float2 uv_MainTex; float3 worldNormal; float3 viewDir; }; fixed4 _Color; float _DotProduct; void surf (Input IN, inout SurfaceOutput o) { fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; //点积 float border = 1-abs(dot(IN.viewDir, IN.worldNormal)); //完全可见部分(即模型的边缘)和完全不可见部分之间的渐变褪色,通 //过下面的线性插值来完成,但有了_DotProduct后,就不存在完全不可 //见部分了,即使border为0(原本的完全不可见处),也有一定可见度了。全息效果更真实。 float alpha = border*(1 - _DotProduct) + _DotProduct; o.Alpha = c.a*alpha; } ENDCG } FallBack "Diffuse" }
图在这:
混合纹理
将纹理混合后涂在表面上,这种需求通常出现在地形类的着色器上。需要这里提供三张待混合的图:
还需要一张彩色混合(Blend)纹理图:
待混合的图分别分配到R通道、G通道、B通道,再根据彩色混合纹理的RGB分布,将对应的RGB通道的图混合起来(用的几个lerp(a,b,f)函数进行混合,a和b这两种纹理按照f指定的比例进行混合,即为(1-f)*a+f*b)。
核心代码:
finalColor = lerp(lerp(rTexData, gTexData, blendData.g), bTexData, blendData.b);
最终效果:
在地形周围创建圆环
能实现显示复杂地形上的攻击范围、视野范围等效果:不过就是直接更换纹理图表示圈的那一部分~
见图:
相关文章推荐
- 《着色器和屏幕特效》读书笔记第八章-用Unity的渲染纹理实现屏幕特效
- 《着色器和屏幕特效》读书笔记第五章-顶点函数
- 《着色器和屏幕特效》读书笔记第三章-光照模型
- 《着色器和屏幕特效》读书笔记第四章-PBR
- 《着色器和屏幕特效》读书笔记第六章-碎片着色器和抓取
- 《着色器和屏幕特效》读书笔记第七章-移动端着色器优化
- 《着色器和屏幕特效》读书笔记第九章-游戏可玩性和屏幕特效
- 《着色器和屏幕特效》读书笔记第十章-高级着色技术
- 《着色器和屏幕特效》读书笔记第一章-创建一个着色器
- 读书笔记_GDI+程序设计_第二章(绘图表面)
- 《深入探索C++对象模型》读书笔记——第二章 构造函数语意学
- 菜鸟DirectX之纹理映射
- 《推荐系统实践》读书笔记----第二章
- 【读书笔记】.NET本质论第二章-Components(Part One)
- OpenGL ES 2.0 纹理映射
- 快学scala 第二章 读书笔记及习题答案代码
- 《第一行代码》读书笔记(第一章,第二章)
- 读书笔记----《windows核心编程》第二章 Unicode与字符串处理
- opengl对着色器纹理坐标等的综合
- 西蒙iphone-OpenGL ES 教程-05 :纹理映射我们的矩形