《Unity Shader 入门精要》读书笔记 ——记录一下自己看书时遇到的一下困惑的地方和自己的一些想法,愿明天的我更加强大 1.要正确获得阴影和光照衰减效果,需要#pragma multi_compile_fwdbase指令,该指令可以保证我们在Shader中使用光照变量可以被正确赋值。
2.渲染队列 渲染队列数字小于2500的对象认为是完全不透明(从前往后渲染),高于2500的被认为是半透明物体(从后往前渲染)。
标签 | 说明 |
---|
“Queue” = “Background” | 值1000,此队列最先渲染。(一般用来渲染背景) | “Queue” = “Geometry” | 值2000,通常是不透明物体。 | “Queue” = “AlphaTest” | 值2450,透贴,要么完全透明,要么完全不透明。 | “Queue” = “Transparent” | 值3000,常用于半透明对象,要混合的对象。 | “Queue” = “Overlay” | 值4000,最后渲染,用于叠加效果。 |
3.内置RanderType标签 RenderType是可以完全自定义的标签名的,Unity内置的标签名不过是约定俗成的叫法,为了方便用于着色器替换。因此您也完全可以将一个RenderType命名为Transparent,然后让它所在的SubShader渲染不透明的物体。
标签 | 说明 |
---|
Opaque | most of the shaders (Normal, Self Illuminated, Reflective, terrain shaders).用于大多数着色器(法线着色器、自发光着色器、反射着色器以及地形的着色器)。 | Transparent | most semitransparent shaders (Transparent, Particle, Font, terrain additive pass shaders).用于半透明着色器(透明着色器、粒子着色器、字体着色器、地形额外通道的着色器)。 | TransparentCutout | masked transparency shaders (Transparent Cutout, two pass vegetation shaders).蒙皮透明着色器(Transparent Cutout,两个通道的植被着色器)。 | Background | Skybox shaders. 天空盒着色器。 | Overlay | GUITexture, Halo, Flare shaders. 光晕着色器、闪光着色器。 | TreeOpaque | terrain engine tree bark. 地形引擎中的树皮。 | TreeTransparentCutout | terrain engine tree leaves. 地形引擎中的树叶。 | TreeBillboard | terrain engine billboarded trees. 地形引擎中的广告牌树。 | Grass | terrain engine grass. 地形引擎中的草。 | GrassBillboard | terrain engine billboarded grass. 地形引擎何中的广告牌草。 |
4.LightMode标签支持的渲染路径设置选项
标签名 | 描述 |
---|
Always | 不管使用哪种渲染路径,该Pass总是会被渲染,但是不会计算光照 | ForwardBase | 用于前向渲染。该Pass会计算环境光、最重要的平行光、逐顶点/SH(球谐函数)光源和Lightmaps | ForwardAdd | 用于前向渲染。该Pass会计算额外的逐像素光源(Unity最多支持4个额外的逐像素光源),每有一个逐像素光源就会计算一次 | Deferred | 用于延迟渲染。该Pass会渲染G缓冲(G-buffer) | ShadowCaster | 把物体的深度信息渲染到阴影映射纹理(shadowmap)或一张深度纹理中 | PrepassBase | 用于遗留的延迟渲染(现在基本不用了)。该Pass会渲染法线和高光反射的指数部分 | PrepassFinal | 用于遗留的延迟渲染(现在基本不用了)。该Pass通过合并纹理、光照和自发光来渲染得到的最后的颜色 | Vertex、VertexLMRGBM、VertexLM | 均用于遗留的顶点照明渲染(属于前向渲染的子集,现在基本不用了) |
5.光照衰减 光照衰减可以用衰减纹理采样或者数学公式来计算,一般采用衰减纹理采样。 对于衰减纹理,越靠近(0,0)越亮,越靠近(1,1)越暗,纵轴没有变化,可以在横轴和对角线上进行采样,在对角线上采样会让光照衰减更加平滑。
对于光源光照衰减的处理:
fixed atten = tex2D(_LightTexture0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;
1.UNITY_ATTEN_CHANNEL是unity中的一个宏,用来兼容不同平台的光照衰减通道,一般来说是r通道。
2._LightTexture0就是光照衰减纹理,通过采样该纹理的光照衰减通道来获取到衰减值。
3.dot(lightCoord,lightCoord):其实就是计算到光源中心的距离,不过这里是个平方,要获得真正的光源到点的距离,其实还要进行一个开方运算,但是我们知道,开放的运算量是很大的,需要消耗额外的机器性能,并且在这里其实我们并不需要开方,因为我们之所以要得到距离,就是为了要反应光照的强弱,也就是物体相对于光源有多远,只是一个反应强度的参数而已(就好比0-255可以表示颜色,0-1也可以表示颜色,只不过是对这两个区间进行了一定比例的缩放,实现了两个区间的相互转换),对于这个参数,缩放其实没有什么影响,我们知道,纹理的uv坐标通常来说是会归一化到[0,1]的范围内,在用tex2D进行采样时,也可以理解为是将传进来的UV坐标进行了归一化的操作,所以及时我们不开方,最终的强度也会映射到[0,1]的区间内,所以我们即使开方了,也是白白浪费了计算力,因为最终都会映射到[0,1]的区间内。
6.什么时候颜色相乘?什么时候颜色相加? 在学习光照时,总会发现有些颜色之间是相加的、有些颜色之间是相乘的,对于是该相乘还是相加,首先要了解的是眼睛看见物体的过程,首先是光线照在物体上,而每个物体自身具有对光线的不同的反射率,越光滑的物体,它反射的光就会越多,到我们眼睛里时我们能看见的颜色也就越亮,而光照在物体上物体反射光线的这个过程,就是颜色的相乘,也就是光线乘上物体对光线的反射率。而现实中光源并不是只有一个,所以会有很多的光线照在物体上,以至于物体也会反射很多不同的光线进入我们的眼睛中,这些光线就包括环境光、反射高光、物体自发光等等,这些光的颜色的叠加,才形成了我们实际看到的颜色,就像太阳光,其实有很多种颜色,但这些颜色叠加在一起后才形成了我们看到的类似白光的太阳光,所以在shader中我们就用相加来得到叠加光的效果。 7.渐变纹理为什么用半兰伯特作为uv坐标进行采样?
fixed halfLambert = dot(worldNormal, lightDir) * 0.5 + 0.5;
fixed3 color = tex2D(_RampTex, fixed2(halfLambert, halfLambert)).rgb * _Color.rgb;
我们从漫反射的公式中看出,由于法线向量(worldNormal)和光照方向向量(lightDir)都是单位向量,所以他们的点积值就代表了两条向量的夹角的正弦值,也就表示了两个向量的夹角的大小,法线与光照方向的夹角决定了光照系数,夹角越小,光照系数越大,漫反射越强,反之,系数越小,漫反射越弱,那么我们用渐变纹理的x轴表示其系数变化,x轴也就是系数越小,就采样越黑的颜色,表示漫反射越弱,系数越大也就是x越大,就采样越白的颜色,表示漫反射越强,所以我们的渐变纹理是从左到右从黑到白,就是这个原理。(这里其实也是在对角线上进行采样)
8.开启深度写入后无法得到有透视的半透明物体 因为在开启深度写入后,物体的背面不会被深度写入,也就无法进行渲染,即使使用cull fornt剔除正面后也依旧看不到物体的背面,因为物体的背面没有通过深度测试。
9.法线纹理的默认值需要设置为“bump”{},而非"white"{}
10.texCube(立方体纹理,反射方向):这里的反射方向其实是入射光的方向,可以想象成是光线穿过立方体纹理的一个点后将立方体纹理上这个点的颜色照到了物体上,然后反射到摄像机中,所以采样所用的向量是光线所在直线上的向量,方向从物体向外。
11.渲染纹理(玻璃效果) 计算偏移:
float2 offset = bump.xy * _Distortion * -2/_RefractionTex_TexelSize.zw;
offset为需要计算的偏移量 bump.xy表示希望在法线不垂直的地方进行偏移计算,因为在法线垂直的地方时(由于在计算偏移量时法线坐标处于切线空间中)法线坐标的xy值为0,最后得到的offse也就为0 _Distortion用来进一步控制法线纹理的凹凸感,这个值越大,代表法线倾斜的角度越大,视觉效果上也就凹凸感更强 最后一个值 -2/_RefractionTex_TexelSize.zw并不是固定的,目的是为了进一步控制偏移量,由于设置的 _Distortion的取值范围是0-100,而视口空间的坐标范围是[0,0]-[1,1],所以我们可以通过乘上_RefractionTex_TexelSize.zw的倒数来将偏移量的范围缩小到0-1之间(因为_RefractionTex_TexelSize的z分量和w分量中的数据其实就是屏幕的宽高,所以这个数往往要远大于1),也就是说,我们其实可以删掉-2/_RefractionTex_TexelSize.zw,单纯使用_Distortion 来控制偏移程度,不过这个时候就需要改变_Distortion的取值范围在0-1左右,或者我们也可以将-2/_RefractionTex_TexelSize.zw手动改成0.01之类的小数,效果都是差不多的,不过我们通常会直接用_RefractionTex_TexelSize.xy(=1/_RefractionTex_TexelSize.zw,就是屏幕宽高的倒数)。
12.lerp函数 官方解释
float lerp(float a, float b, float w) {
return a + w*(b-a);
}
转换一下
float lerp(float a, float b, float w) {
return a(1-w) + b*w;
}
即当w越接近0的时候,插值出来的值越接近a,w越接近1的时候插值出来的值越接近b。 在12章边缘检测中有一条代码
fixed4 onlyEdgeColor = lerp(_EdgeColor,_BackgroundColor,edge);
其中half edge = 1- abs(edgex) + abs(edgey); 因为edge越接近0是,表示越接近边缘,在上面的代码中也就越接近_EdgeColor ,当距离边缘越远时也就越接近_BackgroundColor ,也就可以达到边缘区域和非边缘区域都是几乎纯色的效果,也就是图中这种效果 13.像素边缘的卷积操作 在学习卷积操作时,由于卷积核是有半径的,所以我很疑惑在对于一个图片的边缘像素,是如何进行卷积操作的,于是在查阅相关资料后了解到了对于边缘像素的处理方法:原理是在卷积操作时,扩大相当于卷积核半径大小的像素边缘,比如使用3x3的卷积核时,可以在图像四周各填充1个像素的边缘(长宽分别扩大一个像素,比如一个55的图像,扩大后就变成了66),这样就确保图像的边缘能被处理,并在卷积处理之后再去掉这些边缘就可以了。
|