Shader学习随笔(二)

目录

1、初尝Shader--重点梳理

1.1 漫反射光照模型

1.2 高光反射光照模型

1.3 单张纹理

1.4 凹凸纹理

1.5 渐变纹理(类似卡通风格)

1.6 遮罩纹理

2、Shader透明--重点梳理

2.1 渲染顺序基本概念

2.2 透明度测试

2.3 透明度混合

2.4 渲染顺序问题处理--Unity中



1、初尝Shader--重点梳理


        在《Shader入门精要》一书中,初级篇包含:标准光照模型,漫反射光照模型,高光反射光照模型,单张纹理,凹凸映射,渐变纹理,遮罩纹理,透明度测试,透明度混合。

        标准光照模型是通过计算自发光,高光反射,漫反射,环境光得出的,这个是光照模型的最初方式。

        具体的shader脚本就不贴出了,这里着重梳理各个shader的重点知识。

1.1 漫反射光照模型


        正常公式: Cdiffuse = (Clight·Mdiffuse)max(0,n·I)

        半兰伯特公式:Cdiffuse = (Clight·Mdiffuse)(0.5(n·I)+0.5)

        基本参数:入射光线的颜色和强度Clight,材质的漫反射系数Mdiffuse,表面法线n,光源方向I。

        重点知识:

        1、max函数是为了防止点积结果为负数,在CG语言中使用的函数叫做 saturate。

        2、环境光可以通过Unity的内置变量 UNITY_LIGHTMODEL_AMBIENT 得到。

        3、计算需要保持各数值都是基于同一坐标空间下,才可以算出正确的效果。

        4、半兰伯特公式是为了解决背光面明暗都一样的问题。

1.2 高光反射光照模型


        公式:Cspecular = (Clight·Mspecular)max(0,v·r)mglass(次幂)

        Blinn-Phone公式:Cspecular = (Clight·Mspecular)max(0,n·h)mglass(次幂)

        矢量h计算公式:视角方向v与光照方向i 相加后归一化所得

        反射方向计算公式:r=2(n·i)n-i 

        基本参数:入射光线的颜色和强度,材质的高光反射系数,视角方向,反射方向

        重点知识:

        1、反射方向可以使用CG函数  reflect(i,n)计算得出。

        2、视角方向使用向量计算(camerapos - pointpos),计算出反射反向,归一化即可(摄像机方向在Unity中可以通过 _WorldSpaceCameraPos 获得)。

        3、高光反射一般在漫反射的基础上叠加使用。

1.3 单张纹理


        公式:uv= texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw

        基本参数:纹理属性,顶点纹理坐标转换(ST)

        重点知识:

        0、_MainTex_ST.xy表示纹理缩放,_MainTex_ST.zw表示纹理位移。Unity内置宏为TRANSFORM_TEX。

        1、纹理需要定义一个类型为2D的属性进行传值。

        2、计算时,纹理需要定义一个sampler2D 的纹理变量,以及一个float4类型的纹理坐标转换变量。

        3、最终光照计算使用 tex2D(_MainTex,v.uv).rgb * _Color.rgb的结果作为漫反射的光照系数,将纹理计算进去。

1.4 凹凸纹理


        公式(切线空间):将模型空间下的切线方向,副切线方向和法线方向按行排列得出模型空间到切线空间的变换矩阵。Unity内置宏为TANGENT_SPACE_ROTATION。mul 变换矩阵rotation把模型空间下的元素转换到切线空间。

        公式(模型空间):按列摆放,使用变量存储矩阵的每一行数据信息(顶点切线,副切线,法线),世界空间下的顶点位置的xyz分量存储在这些变量的w分量中。

        基本参数:纹理属性,顶点纹理坐标转换(ST),凹凸属性,凹凸纹理坐标转换(ST)

        重点知识:

        0、纹理类型为Normal Map时,可以使用UnpackNormal得到正确的法线方向。

1.5 渐变纹理(类似卡通风格)


        公式:漫发射颜色通过-- halfLambert构建一个纹理坐标,对纹理进行采样,然后和颜色值相乘得出最终值。tex2D(_RampTex,fixed2(halfLambert,halfLambert)).rgb * _Color.rgb

        基本参数:纹理属性,顶点纹理坐标转换(ST),凹凸属性,凹凸纹理坐标转换(ST)

        重点知识:

        0、漫发射使用半兰伯特公式。

        1、高光反射使用Blinn-Phone公式。

        2、由于纹理采样时的浮点数精度取值问题,会造成某些顶点位置有黑点存在。纹理的WrapMode设置为Repeat时会舍弃整数部分,只保留小数部分,所以会造成黑点的问题,当设置为Clamp模式,即可解决此类问题。

1.6 遮罩纹理


        原理:保护某些指定区域免于某些修改。如,表现地形草地,石子,地面等混合。

        公式:specularMask= tex2D(_SpecularMask,i.uv).r*_SpecularScale;

                   Specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(tangentNormal,halfDir)),_Glpss)*specularMask;

        基本参数:遮罩纹理属性,遮罩Scale

        重点知识:

        0、首先对遮罩纹理进行采样,然后使用 r 分量计算掩码值,最终和遮罩Scale相乘,控制高光反射的强度。

2、Shader透明--重点梳理

2.1 渲染顺序基本概念

        在shader中需要使用透明时,需要控制渲染模型的透明通道,Unity中会通过两种方式进行实现--透明度测试和透明度混合。不透明物体在不考虑渲染顺序的时候也是可以得出正确的效果,因为有深度缓冲(depth buffer、Z-buff)的存在,正如其名,不透明物体在渲染过程中,会根据各自的深度信息,进行渲染赋值、覆盖和剔除,即便是A渲染在B之前,但是摄像机检测到B比A距离更近,那么B就会渲染在前方,而A则在后面渲染或被剔除。但是对于透明物体来说,渲染顺序就变得尤为重要,因为 为了实现透明,需要使用透明度混合,同时会关闭掉深度写入(ZWrite),这样的话,在渲染透明物体时,深度缓冲就无法写入生效。

2.2 透明度测试

        只要片元的透明度不满足条件(范围区间),则对应片元不进行任何透明处理,按照普通渲染进行处理,同时由于透明度测试的特性,要不该片元完全透明,要不就完全不透明,所以,透明度测试不需要关闭深度写入。

        函数:clip(float1-4 x)

        渲染队列选择:Queue= AlphaTest

        示例:clip(texColor.a - _CutOff);

2.3 透明度混合

        透明度混合是可以得到真正的半透明效果,但是由于需要看到透明物体后面的物体,那么在渲染透明度混合时,需要关闭掉深度写入,防止由于透明物体在前而导致后面的物体没有进行渲染,同时,由于没有关闭深度测试,那么通过深度测试获取物体的深度值,与深度缓冲中的值进行对比,决定是否进行透明度混合操作。

        函数:无

        渲染队列选择:Queue = Transparent

        命令:Blend SrcAlpha OneMinusSrcAlpha(混合) Zwrite Off(关闭深度写入)ColorMask 0(不写入任何颜色/不输出任何颜色)

        Shader学习随笔(二)_第1张图片

 Shader学习随笔(二)_第2张图片

 Shader学习随笔(二)_第3张图片

         由于关闭了深度写入,排序错误会导致错误的透明效果,《UnityShader入门精要》中给到的解决方式是使用两个Pass渲染模型。一个开启深度写入,但是不输出颜色,获取正确的深度信息,另一个做正常混合操作,由于已经获取到了深度信息,后一个pass进行混合时,排序就是正确的了。

2.4 渲染顺序问题处理--Unity中

        因为要实现透明效果,从而关闭了深度写入,导致原有的渲染顺序被破坏,可能会造成渲染重叠或错位等结果,因此,Unity提供了渲染队列来处理这个问题。

        UnityShader中,可以通过指定SubShader中的Queue标签来分配模型的渲染队列归属。索引号越小越早被渲染。

        1)先渲染所有不透明物体。

        2)半透明物体按照队列进行渲染。

Shader学习随笔(二)_第4张图片

你可能感兴趣的:(Shader,unity,游戏引擎,shader)