《Unity Shader入门精要》学习笔记 - Chapter 7
7.1 单张纹理在Blinn-Phong的基础上增加了纹理采样相关代码,实现贴图。
Properties中增加纹理属性:
_MainTex ("Main Tex", 2D) = "white" {}
对应的变量声明有两个:
sampler2D _MainTex; //贴图内容
float4 _MainTex_ST; //贴图缩放和偏移
在之后增加了法线贴图、遮罩贴图等等之后,如果缩放和偏移都是一样的,可以用同一个float4来存储。
结构体a2v中增加:
float4 texcoord : TEXCOORD0;
四维浮点数,xy定义tiling,zw定义offset。接受前面的
结构体v2f中增加:
float2 uv : TEXTCOORD2;
采样的坐标,在顶点着色器里接受从a2v里传过来的texcoord并且加上_MainText_ST的变换:
v2f o;
o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
//o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); //使用Unity内置宏
对纹理进行采样的过程发生在片元着色器中,使用tex2D(被采样纹理(_MainTex), 采样坐标(i.uv))函数,作为diffuse color:
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
之后加上ambient、specular即可。
疑惑的地方:TEXCOORD语义究竟传递了什么信息?a2v和v2f中都用到了TEXCOORD0,可以重复?另外在粘贴上面一行代码的时候发现写成了TEXTCOORD2(应为TEXCOORD2),但是shader没有报错,可以正常运行达到想要的效果?
我的理解是TEXCOORD在硬件上分配了一个寄存数值的地方,其数值并不一定和纹理有关,比如v2f中的worldPos存储在TEXCOORD1中,用法很灵活,比如这里的float4 _MainTex_ST就用前两位和后两位分别存储了缩放和偏移,后面的法线贴图还有用三个float4的TEXCOORD的前三位构建切线空间到世界空间的转化矩阵、最后一位存位置的操作。总之,充分利用存储空间。
另一个疑惑的地方:颜色相乘有什么意义?两个颜色的乘积就代表混合吗?总的方向是对的:白色的环境光(1,1,1)照射到物体上,物体颜色不改变, 没有环境光(0,0,0)的时候物体也显示出黑色;max(0, dot(worldNormal, worldLightDir)),兰伯特(漫反射)定律。
7.1.2讲了一下纹理的属性,在纹理的inspector面板里调整类型(normal map/cubemap……默认类型我现在用的版本是Default,不是书里的Texture)、wrap mode(常用Repeat、Clamp,但是调整了之后没看出来区别?)、滤波模式ffilter mode、advanced中可选是否生成mipmap,
7.2 凹凸映射
bump mapping,包括法线纹理(normal map)、高度纹理(height map,从说明来看就是位移贴图displacement map?)
如何理解模型空间和切线空间下法线纹理的“样子”?
模型空间:各顶点的法线各异,从(-1,-1,-1)到(1,1,1)都有→法线的绝对值→许多不同的值→花花绿绿的法线纹理。
切线空间原点是顶点→法线的相对值→如果相对于原来的法线变化不大,则值基本相同(0,0,1)→大片蓝色的法线纹理。不变→(0,0,1)→映射到→(0.5,0.5,1)→浅蓝色。
使用切线空间的好处:
可移植,不限于某一特定模型;可以实现uv动画;可压缩(z总是正向,只存储xy即可)
使用模型空间的好处:
简单直观;边角处更平滑。书中关于纹理连续性的说明没太看懂……
我们甚至都不需要模型原始的法线和切线等信息,也就是说,计算更少。生成它也非常简单,而如果要生成切线空间下的法线纹理,由于模型的切线一般是和UV方向相同,因此想要得到效果比较好的法线映射就要求纹理映射也是连续的。
-在切线空间中计算
新函数:ObjSpaceLightDir(v.vertex)、ObjSpaceViewDir(v.vertex)。
用于将模型空间转换到切线空间的矩阵:float3x3(v.tangent.xyz, binormal, v.normal)。三个向量分别是顶点上的切线、副切线、法线方向单位矢量,满足相互垂直,是一组标准正交基(见4.4.4)。或使用内置宏TANGENT_SPACE_ROTATION。
也可以使用世界空间,代码如下:
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
float3x3 worldToTangent = float3x3(worldTangent, worldBinormal, worldNormal);
//transform light direction from object space to tangent space
o.lightDir = mul(worldToTangent, WorldSpaceLightDir(v.vertex));
//transform view direction from object space to tangent space
o.viewDir = mul(worldToTangent, WorldSpaceViewDir(v.vertex));
7.3 渐变纹理
其实和凹凸纹理的道理一样,shader里也都是用tex2D函数实现的。但是二维贴图更直观一点,给人一种“把纹理贴到物体上”的感觉,而一维的渐变纹理(应该不是所有渐变纹理都是一维的,我猜。书中没有介绍二维渐变纹理,但提到了“纹理其实可以用于存储任何表面属性”)给人一种“针对模型上的点到色带上采样”的感觉。
渐变纹理经常在卡通渲染中控制漫反射光照。
7.4 遮罩纹理
纹理“存储任何表面属性”的另一个例子,和ps里蒙版的逻辑差不多,控制模型上哪些区域收到修改,例如指定不同的高光强度、混合多张地形材质等。精细化控制光照。
书中示例的效果是高光部分被压暗了一些。
正常的Blinn-Phong高光
添加了遮罩纹理
页:
[1]