Shader经验分享

流水线 1.应用阶段:(CPU)输出渲染图元,粗粒度剔除等 比如完全不在相机范围内的需要剔除,文件系统的粒子系统实现就用到粗粒度剔除。 2.几何阶段:(GPU)把顶点坐标转换到屏幕空间,包含了模型空间 到世界空间 到观察空间(相机视角view) 到齐次裁剪空间(投影project2维空间,四维矩阵,通过-w<x<w判断是否在裁剪空间) 到归一化设备坐标NDC(四维矩阵通过齐次除法,齐次坐标的w除以xyz实现归一化) 到屏幕空间(通过屏幕宽高和归一化坐标计算)。 a.顶点着色器:坐标变换和逐顶点光照,将顶点空间转换到齐次裁剪空间。 b.曲面细分着色器:可选 c.几何着色器:可选 d.裁剪:通过齐次裁剪坐标的-w<x<w判断不在视野范围内的部分或者全部裁剪,归一化。 e.屏幕映射:把NDC坐标转换为屏幕坐标 3.光栅化阶段:(GPU)把几何阶段传来的数据来产生屏幕上的像素,计算每个图元覆盖了哪些像素,计算他们的颜色、 a.三角形设置:计算网格的三角形表达式 b.三角形遍历:检查每个像素是否被网格覆盖,被覆盖就生成一个片元。 c.片元着色器:对片元进行渲染操作 d.逐片元操作:模板测试,深度测试 混合等 e.屏幕图像 ------------------------------------------------------- 矩阵: M*A=A*M的转置(M是矩阵,A是向量,该公式不适合矩阵与矩阵) 坐标转换: o.pos = mul(UNITY_MATRIX_MVP, v.vertex);顶点位置模型空间到齐次空间 o.worldNormal = mul((float3x3)_Object2World,v.normal);//游戏中正常的法向量转换,转换后法向量可能不与原切线垂直,但是不影响游戏显示,而且大部分显示也是差不多的。一般用这个就行了。 o.worldNormal = mul(v.normal, (float3x3)_World2Object);顶点法向量从模型空间转换到世界空间的精确算法,公式是用_Object2World该矩阵的逆转置矩阵去转换法线。然后通过换算得到该行。 ------------------------------------------------------- API: UNITY_MATRIX_MVP 将顶点方向矢量从模型空间变换到裁剪空间 UNITY_MATRIX_MV 将顶点方向矢量从模型空间变换到观察空间 UNITY_MATRIX_V 将顶点方向矢量从世界空间变换到观察空间 UNITY_MATRIX_P 将顶点方向矢量从观察空间变换到裁剪空间 UNITY_MATRIX_VP 将顶点方向矢量从世界空间变换到裁剪空间 UNITY_MATRIX_T_MV UNITY_MATRIX_MV的转置矩阵 UNITY_MATRIX_IT_MV UNITY_MATRIX_MV的逆转置矩阵,用于将法线从模型空间转换到观察空间 _Object2World将顶点方向矢量从模型空间变换到世界空间,矩阵。 _World2Object将顶点方向矢量从世界空间变换到模型空间,矩阵。 模型空间到世界空间的矩阵简称M矩阵,世界空间到View空间的矩阵简称V矩阵,View到Project空间的矩阵简称P矩阵。 --------------------------------------------- _WorldSpaceCameraPos该摄像机在世界空间中的坐标 _ProjectionParams _ScreenParams _ZBufferParams unity_OrthoParams unity_Cameraprojection unity_CameraInvProjection unity_CameraWorldClipPlanes[6]摄像机在世界坐标下的6个裁剪面,分别是左右上下近远、 ---------------------------- 1.表面着色器 void surf (Input IN, inout SurfaceOutput o) {}表面着色器,unity特殊封装的着色器 Input IN:可以引用外部定义输入参数 inout SurfaceOutput o:输出参数 struct SurfaceOutput//普通光照 { half3 Albedo;//纹理,反射率,是漫反射的颜色值 half3 Normal;//法线坐标 half3 Emission;//自发光颜色 half Specular;//高光,镜面反射系数 half Gloss;//光泽度 half Alpha;//alpha通道 } 基于物理的光照模型:金属工作流SurfaceOutputStandard 高光工作流SurfaceOutputStandardSpecular half3,half4代表rgba或者xyz,可以分开用 Albedo.xy=1.或Albedo.ga=1 --------------------------------- #pragma surface surfname lightModel op - 指出函数surfname 表面着色器。lightModel的光照模型和可选op操作,还可以添加顶点修改函数vertex和颜色修改函数finalcolor。 #pragma surface surf CustomLambert vertex:myvert finalcolor:mycolor addshadow exclude_path:deferred exclude_path:prepass nometa #pragma vertex name - 指出函数name 是顶点着色器。 #pragma fragment name - 指出函数name 是片段着色器。 #pragma fragmentoption option - 添加option 到编辑的OpenGL片段程序。参看ARB fragment program说明书了解被允许的选项列表。这个指示在顶点程序或者编辑到非OpenGL targets的程序没有影响。 #pragma multi_compile_builtin - 为了pixel-lit shaders;;这个将告知Unity去编辑大量的这个着色器程序数列以支持所有的照明种类,和所有的阴影选项。 #pragma multi_compile_builtin_noshadows - 对于pixel-lit 着色器,不接受阴影。这将告知Unity去编辑几个该着色器程序的数列来支持所有的照明种类。这比multi_compile_builtin pragma可以更快的编辑,而且结果着色器也更小。 #pragma target name - 那个着色器target 去编辑。细节参看shader targets。 #pragma only_renderers space separated names - 只为给定的渲染器编辑着色器。默认情况下,着色器为所有的渲染器被编辑。细节参看 renderers。 #pragma exclude_renderers space separated names - 不为给定的渲染器编辑着色器。默认情况下,着色器为所有的渲染器被编辑。细节参看 renderers。 --------------------------------- 2.顶点着色器 struct appdata_full {//vertex输入 float4 vertex : POSITION;//must float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0;//该顶点的纹理坐标,第一组纹理坐标uv 也就是第一张贴图的坐标、为了实现多重纹理贴图,比如子弹打在墙上的弹痕等 float4 texcoord1 : TEXCOORD1;//n的数量和shadermodel版本有关 float4 texcoord2 : TEXCOORD2; float4 texcoord3 : TEXCOORD3; fixed4 color : COLOR;//顶点颜色 }; 3.片段着色器 struct v2f{//vertec的输出和frag的输入 float4 vertex :SV_POSITION;//must float3 color0:COLOR0; float3 color1:COLOR1; float4:texcoord:TEXCOORD0;//TEXCOORD0-TEXCOORD7自定义纹理坐标 } SV_Tatget //frag的输出,输出float4的颜色 ----------------------------------- 光照: 1.逐顶点光照:在顶点着色器阶段计算光照,效率高但是效果不好,在边缘像素映射的时候插值可能会产生锯齿。 2.逐像素光照:在片元着色器阶段计算光照,计算量大,但是边缘表现效果好。 3.半兰伯特模型:处理无光照的地方,也让其有光,不然可能是全黑。经验模型。 #include "Lighting.cginc" Tags { "LightMode"="ForwardBase" } WorldSpaceViewDir(float4 v) 输入模型空间中的顶点坐标,返回世界空间中从该点到摄像机的观察方向 UnityWorldSpaceViewDir(float4 v) 输入世界空间中的顶点坐标,返回世界空间中从该点到摄像机的观察方向 ObjSpaceViewDir(float4 v)输入模型空间中的顶点坐标,返回模型空间中从该点到摄像机的观察方向 WorldSpaceLightDir()仅用于前向渲染,输入模型空间中的顶点坐标,返回世界空间中从该点到光源光照方向,没有归一化。 UnityWorldSpaceLightDir()仅用于前向渲染,输入世界空间中的顶点坐标,返回世界空间中从该点到光源光照方向,没有归一化。 ObjSpaceLightDir()仅用于前向渲染,输入模型空间中的顶点坐标,返回模型空间中从该点到光源光照方向,没有归一化。 UnityObjectToWorldNormal(float3 v)把法线从模型空间转换到世界空间 UnityObjectToWorldDir(float3 v)把方向矢量从模型空间转换到世界空间 UnityWorldToObjectDir(float3 v)把方向矢量从世界空间转换到模型空间 _WorldSpaceLightPos0.xyz获取平行光光源方向,或者点光源的光源位置 _LightColor0.rgb获取当前pass的光源颜色和强度 UNITY_LIGHTMODEL_AMBIENT.xyz; 环境光 normalize(_WorldSpaceCameraPos.xyz - worldPos.xyz); 视觉方向 UnityWorldSpaceViewDir a.漫反射公式:diff=C*max(0,cos<L,N>);//C是颜色和强度_LightColor0.rgb 代码: diff=max(0,dot(i.normal,i.lightDir))//i的单位向量and单位法向量 c=tex2D(tex,i.uv)*_LightColor0*diff//_LightColor0表示的是场景中平行光的颜色和强度 b.高光反射公式:Spec=pow(max(0,cos(R,V),gloss))//R 单位反射向量reflect(ray,normal)函数获取,V视线单位方向向量 ,gloss光色度 代码: Spec=pow(max(0),dot(reflect(-i.lightDir,i.normal),32)) c=c**_LightColor0*(diff+Spec) ----------------------------------------------- 纹理 uv坐标是顶点存储了图片上的坐标 _MainTex ("Main Tex", 2D) = "white" {} sampler2D _MainTex; float4 _MainTex_ST;//Unity中 纹理_ST来默认声明该纹理的属性_MainTex_ST.xy表示Scale, Till缩放,_MainTex_ST.zw表示Transform 偏移 o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);//vs输入纹理坐标和纹理值输出UV,ps对uv进行纹理采样和计算。UV通常在0-1范围,等于o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;//反射率 法线贴图:xyz映射存成rgb值。一般存在切线空间,z轴法线方向,x轴切线方向,y轴副(法)切线方向 TANGENT_SPACE_ROTATION;//Unity来获取rotation矩阵,从模型空间到切线空间变换的矩阵。仅存在旋转和平移时,一个矩阵的转置矩阵等于他的逆矩阵。 自己实现: float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; //切线空间的w分量用来存储负法线向内还是向外 float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);//float3x3是按行存储 float3 tangentNormal = UnpackNormal(packedNormal);Unity将法线贴图纹理坐标0,1映射到正常法线坐标-1,1,返回切线空间下的法线方向。法线贴图要设置成Normal格式。该设置unity有优化 rgb值不再是法线xyz的映射了,如果不设置的话要自己算 该公式不能用。 自己实现: tangentNormal.xy = (packedNormal.xy * 2 - 1) * _BumpScale;//坐标反映射,自己计算的方法 tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));//通过xy计算z 遮罩纹理 ---------------------------------------- 1.透明度测试AlphaTest:只要有一个片元的透明度不满足条件就被裁剪,用来优化显示。 AlphaTest Greater AlphaValue//仅渲染 alpha 值大于 AlphaValue 的像素。AlphaValue :0-1 AlphaTest GEqual AlphaValue//仅渲染 alpha 值大于或等于 AlphaValue 的像素。 AlphaTest LessAlphaValue//仅渲染 alpha 值小于 AlphaValue 的像素。 AlphaTest LEqual AlphaValue//仅渲染 alpha 值小于或等于 AlphaValue 的像素。 AlphaTest Equal AlphaValue//仅渲染 alpha 值等于 AlphaValue 的像素。 AlphaTest NotEqual AlphaValue//仅渲染 alpha 值不等于 AlphaValue 的像素。 AlphaTest Always //渲染所有像素。这在功能上相当于 Alpha 测试关 (AlphaTest Off)。 AlphaTest Never//不渲染任何像素。 2.模板测试:Stencil如果开启了模板测试,GPU会首先会读取模板缓冲区的值,然后把该值和读取的参考值ref进行比较,比较方式由Comp指定,比如大于Greater就表示通过模板测试, 然后由Pass Fail ZFail去指定通过和不通过模板和深度测试后对缓冲区的值进行的Operation处理。 Stencil {Ref 2 //设置模板参考值为2 Comp equal //比较方式,有8种比较方式。 Pass Operation //这个是当stencil测试和深度测试都通过的时候,进行的stencilOperation操作方法 Fail Operation //这个是在stencil测试通过的时候执行的stencilOperation方法 ZFail Operation//这个是在stencil测试通过,但是深度测试没有通过的时候执行的stencilOperation方法。 ReadMask readMask//readMask默认是255,一般不用该功能,设置隐码后 读取ref和buff值都需要与该码进行与操作。(0-255) WriteMask writeMask//写操作进行与操作 } Comp 的参数包括Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never Operation的参数包括: Keep保持 Zero归零 Replace 拿比较的参考值替代原来buffer的值 IncrSat 值增加1,但是不溢出,如果是255,就不再加 DecrSat 值减少1,不溢出,到0就不再减 Invert 翻转所有的位,所以1会变成254 IncrWrap 值增加1,会溢出,所以255会变成0 DecrWrap 值减少1,会溢出,所以0会变成255 clip(x) //x的任何分量小于0 被裁剪掉 discard//舍弃当前片元 ZWrite Off//关闭深入写入 ColorMask RGB|A|0 //设置颜色通道的写掩码,为0表示该pass不进行颜色输出。 3.深度测试ZTEST:一个片元离摄像机的远近,渲染后会进行深度写入,通常会判断缓存深度和当前片元深度 可知前后关系。 ZTest Always //指的是直接将当前像素颜色(不是深度)写进颜色缓冲区中 相当于ZTest Off ZTest Never//而Never指的是不要将当前像素颜色写进颜色缓冲区中,相当于消失。 ZTest Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off,默认值为LEqual 即当物体深度小于或等于缓存深度值时(越远深度越大),该物体渲染,就是默认的先后顺序渲染。 透明度混合AlphaBlending:该片元需要关闭深度写入,不关闭深度测试。会导致片元之间深度穿插。可以采用2个pass,第一个pass只用来做深度写入ZWrite On,第二个pass只用来输出颜色ZWrite Off,这样深度和颜色效果才会正确 Blend Off//关闭混合,只有blend打开后ps输出a通道才有意义 Blend SrcFactor DstFactor//用同样的因子对rgba进行混合(默认都开启混合)第一个参数对源颜色(当前片元颜色,ps输出的颜色)*SrcFactor混合, 第二个参数对目标颜色(当前读到的缓冲区颜色)*DstFactor混合,混合后默认相加后会重新写入缓冲区(相加后超过1的自动截断到1)。混合包括RABG值。结果都是源颜色和目标颜色与各自因子相乘后再加起来作为输出颜色。 shader里边的向量相乘不同于点乘叉乘,相当于各项分别相乘。 Blend SrcFactor DstFactor,SrcFactorA DstFactorA//把rgb和a的混合因子分开。 混合因子 One //因子是1 Zero //因子是0 SrcColor//因子为源颜色值,当前片元颜色,对应rgba分量分别与SrcColor分量相乘 SrcCAlpha//因子为源颜色透明值值,对应rgba分别与SrcCAlpha相乘。 DstColor//因子为目标颜色值,当前读到的缓冲区颜色 DstAlpha//因子为目标颜色透明值值 OneMinusSrcColor//因子为1-源颜色 OneMinusSrcAlpha//因子为1-源alpha OneMinusDstColor//因子为1-目标颜色 OneMinusDstAlpha//因子为1-目标alpha 例子: Blend SrcAlpha OneMinusSrcAlpha// Alpha混合,正常的透明度混合 Blend OneMinusDstColor One //柔和相加Soft Additive Blend One One // Additive相加 线性减淡 Blend One OneMinusDstColor // Soft Additive比较柔和的相加 Blend DstColor Zero // Multiplicative乘法 Blend DstColor SrcColor // 2x Multiplicative2倍乘法 BlendOp OP//对源和目标颜色进行其他操作,而不是默认的相加,op操作包括: Add //相加 Sub//源颜色减目标颜色 RevSub//目标颜色减源颜色 Min //使用2者较小的值 Min //使用2者较大的值 chen BlendOp Min Blend One One //组合变暗 双面渲染:一般采用多个pass分别渲染正面和背面 Cull Back|Front|Off Cull Back默认的背对相机图元不渲染 Cull Front朝向相机图元不渲染,只显示背面 Cull Off关闭剔除功能 全部渲染 性能低,但是可以实现比如看见物体内部结构。 不透明物体有深度测试,先渲前后没有关系,但是先渲染近的效率会更高,因为远的会被深度测试自动剔除不用渲染。 透明物体一般要先渲远的,再渲近的才能保证视觉顺序正确。 ------------------------------------------ SubShader的Tag{}标签类型: Queue:渲染顺序,保证渲染顺序小的先渲 大的后渲 RenderType:Unity可以运行时替换符合特定RenderType的所有Shader,着色器分类 ForceNoShadowCasting:值为”true”时,表示不接受阴影。 IgnoreProjector:值为”true”时,表示不接受Projector组件的投影。常用语半透明物体 DisableBatching:是否对subshader进行批处理,当shader中需要对顶点进行偏移的时候,该项设置为true CanUseSpriteAtlas:当该subshader用于sprite时 该标签设为false PreviewType:指明材质面包怎么预览材质 比如 "PreviewType"="Plane" LightMode : 渲染路径 ,pass的标签类型 ------- 渲染队列:"Queue"="Transparent" Background:1000 //该声明的物体最先被渲染 Geometry:2000//默认的不透明物体使用的渲染队列 AlphaTest:2450//透明度测试,默认不透明物体渲染完后就渲染该物体 Transparent:3000//透明物体,在Geometry和AlphaTest后渲染,保证不透明物体渲染完了再渲染透明的。 Overlay:4000//该队列用来实现叠加效果,该物体会在最后被渲染。 ------ RenderType: Opaque:绝大部分不透明的物体都使用这个; Transparent:绝大部分透明的物体、包括粒子特效都使用这个; Background:天空盒都使用这个; Overlay:GUI、镜头光晕都使用这个 ----------------------------------------------------------------------------------------- 渲染路径 Tag{ "LightMode" = "ForwardBase"}//为每个pass指定渲染路径 LightMode包括: Always:所有渲染路径该pass都会渲染,但不计算光照 ForwardBase:前向渲染,该pass会计算环境光,最重要的平行光,逐顶点光和 Lightmaps ForwardAdd:前向渲染,该pass会计算额外的逐像素光源,每个pass对应一个光源。光源多该pass会被多次调用 效率变低。 Deferred:延时渲染,该Pass会渲染G-buffer ShadowCaster:把物体的深度信息渲染到阴影映射纹理或深度纹理中 PrepassBase:遗留的延迟渲染,该pass会渲染法线和高光反射的指数部分、 PrepassFinal:遗留的延迟渲染,该pass通过合并纹理 光照 自发光来渲染得到最后的颜色 Vertex:遗留的顶点照明渲染 1.前向渲染:包括ForwardBase类型渲染常用光照和ForwardAdd额外光照 #pragma multicompile_fwdbase //ForwardBase中用来保证光照衰减等参数正确赋值。 #pragma multicompile_fwdadd //ForwardAdd中用来保证可以访问到正确的光照变量. #pragma multicompile_fwdadd_fullshadows //ForwardAdd中用来计算阴影效果 USING_DIRECTIONAL_LIGHT//平行光的宏定义 _LightColor0//该pass的桌像素光照颜色 _WorldSpaceLightPos0//获取平行光光源方向,或者点光源的光源位置 _LightMatrix0//世界空间到光源空间(光源位置为坐标原点的坐标系)的变换矩阵 _LightTexture0//光照衰减纹理 ........... tips:光源的RendeMode参数设置为Important unity会自动采用像素光源,如果不重要就是顶点光源。还有qualitysetting里边的PixelLIghtCount,超过这个数也会用顶点光照 光照衰减 float3 lightCoord = mul(_LightMatrix0, float4(i.worldPos, 1)).xyz; fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;//UNITY_ATTEN_CHANNEL获得衰减值所在的分量 float shadow=SHADOW_ATTENUATION(i);//负值使用SHADOW_COORDS对相关纹理进行采样,返回值为阴影。关闭阴影的状态是等于1 return fixed4(ambient + (diffuse + specular) * atten * shadow, 1.0);//atten为衰减,shadow为阴影 ------计算别人投到自己身上的阴影和衰减 SHADOW_COORDS(n)//声明一个_ShadowCoord的阴影纹理坐标 ps输入坐标,n的值是声明TEXCOORD0-7坐标使用的个数 TRANSFER_SHADOW(o);//用于在顶点着色器中计算上一步声明中的阴影纹理坐标 并传向ps阶段。 float shadow=SHADOW_ATTENUATION(i);//负值使用SHADOW_COORDS对相关纹理进行采样,返回值为阴影。关闭阴影的状态是等于1 UNITY_LIGHT_ATTENUATION(atten,v2f i, i.worldPos);//计算别人投影到身上的阴影#include "AutoLight.cginc" Unity会将光照衰减和阴影相乘后存在第一个参数中,并自动声明atten变量。第二个参数结构体包含SHADOW_COORDS,第三个参数世界空间坐标 return fixed4((diffuse + specular) * atten, 1.0);//UNITY_LIGHT_ATTENUATION出的atten为衰减和阴影 -----计算阴影投影到别人身上,自己的阴影 V2F_SHADOW_CASTER//unity里边定义阴影投射需要定义的变量 TRANSFER_SHADOW_CASTER_NORMALOFFSET(0)//unity对顶点进行自动处理 SHADOW_CASTER_FRAGMENT(i)//unity自动完成阴影投射部分,把结果输出到深度图和阴影映射纹理中 --ds2的阴影采用的是屏幕后处理的方式去计算阴影,延迟渲染 2.顶点照明渲染:过时的渲染方式。效果差。 3.延迟渲染:通常2个pass,第一个pass计算哪些片元可见,第二个pass计算真实光照。 --------------------------------------------------------------------------- 1.反射o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);//入射光线,表面法线 2.折射o.worldRefr = refract(-normalize(o.worldViewDir), normalize(o.worldNormal), _RefractRatio);//入射光线,表面法线,介质比 3.镜子效果:使用相机的RenderTexture来设置渲染纹理。o.uv.x = 1 - o.uv.x;坐标需要翻转一下。 4.玻璃效果:反射和折射使用cubemap进行采样 是天空盒的cubemap,然后反射需要采样的是周围环境的光照和纹理。 GrabPass { "_RefractionTex" }//会把屏幕输出到_RefractionTex的texture中, _RefractionTex_TexelSize 可以得到该纹理纹素大小,例如255*255的纹素是(1/255,1/255) GrabPass{} //然后用_GrabTexture直接访问屏幕图像,但是这样效率比较低,推荐要上面需要声明的方法。 o.scrPos = ComputeGrabScreenPos(o.pos);//得到对应被抓取的屏幕图像的采样坐标 反射和折射需要显示环境的效果,所以需要对环境的cubemap进行采样。先用反射和折射的公式计算出光线,然后对环境贴图进行采样texCUBE(_Cubemap, i.worldRefl).rgb就可以得到具体效果了。 反射skybox 3d采样,折射屏幕抓取图像2d采样。 --------------------------------------------------------------------------- 时间变量 _Time:float4 //t是自该场景加载开始所经过的时间,4个分量是(t/20,t,2t,3t) _SinTime:float4//t是时间的正玄弦值,四个分量的值分别是(t/8,t/4,t/2,t) _CosTime:float4//t是时间的余玄弦值,四个分量的值分别是(t/8,t/4,t/2,t) unity_DeltaTime:float4// dt是时间增量,4个分量分别是(dt,1/dt,smoothDt,1/smoothDt) 序列帧动画:时间去控制uv坐标映射转换。uv坐标的xy是顶点坐标,映射到小格子里边,和UItexture的xy和宽高不一样。 背景偏移动画:时间控制uv坐标偏移。 水流动画:通过时间和正弦函数去控制顶点偏移,通过时间控制uv移动。设置DisableBatching=true 广告牌BillBoarding:根据视觉方向来旋转被纹理着色的多边形。顶点动画 ------------------------------------------------------------------------- 屏幕后处理 void OnRenderImage(RenderTexture src, RenderTexture dest){}//全部渲染完后将调用,屏幕纹理存在src上,用来计算后通过dest返回,添加[ImageEffectOpaque]属性,可使不透明物体(AlphaTest)被渲染完后立即调用. Graphics.Blit(src, dest);//直接copy纹理。src是屏幕当前或上一步渲染的纹理,dest是目标纹理 Graphics.Blit(src, dest, material,pass=-1);//将把src传到shader的material的_MainTex纹理。经过material(shader)的处理后输出到dest渲染到屏幕.pass默认是-1会调用所有pass,否则只调用给定顺序的pass。指定pass渲染很重要。 基于颜色变化的边缘检测:Sobel卷积算法,对边缘点进行采样计算 和特定矩阵卷积相乘。 高斯模糊:多次采样纹理混合 消耗较大 Bloom效果:把较亮区域提取出来进行高斯模糊 模拟扩散效果,然后再与原纹理混合。 运动模糊:将上一帧的屏幕图像存到renderTexture中,然后执行Graphics.Blit(src, renderTexture, material),shader将开启混合Blend SrcAlpha OneMinusSrcAlpha把src纹理和目标缓冲纹理renderTexture进行混合,然后再Blit输出到dst进行渲染。就得到了运动模糊效果。

常见的几种混合类型:

//正常(Normal) 即透明度混合

Blend SrcAlpha OneMinusSrcAlpha

//柔和相加 (Soft Additive)

Blend OneMinusDstColor One

//正片叠底(Multiply) 即相乘

Blend DstColor Sero

//两倍相乘(2x Multiply)

Blend DstColor SrcColor

//变暗(Darken)

BlendOp Min

Blend One One

//变亮(Lighten)

BlendOp Max

Blend One One

//滤色(Screen)

Blend OneMinusDstColor One 等同于 Blend One OneMinusSrcColor

//线性减淡(Linear Dodge)

Blend One One

---------------------------------------------------------------------------- 深度和法线纹理 float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth)); _CameraDepthNormalsTexture //unity中调用camera.depthTextureMode=DepthTextureMode.Depth/DepthNormal;这句话后可以通过该变量访问深度纹理或者深度和法线纹理,project空间 float depth=SAMPLE_DEPTH_TEXTURE(tex,uv)//对深度纹理进行采样,返回project空间下非线性深度值。和tex2D类似 只是封装了平台。自动将NDC坐标下的深度映射(0,1)需要转换到(-1,1)veiw空间去计算 LinearEyeDepth(depth)负责把深度纹理的采样结果转换到视角view空间下的线性深度值 Linear01Depth(depth)则会返回一个范围在0,1的线性深度值 half4 sample1 = tex2D(_CameraDepthNormalsTexture, i.uv); half2 centerNormal = DecodeViewNormalStereo(sample1);//center.xy存的法线的映射值 float centerDepth = DecodeFloatRG(center.zw);//zw深度 DecodeDepthNormal(sample1,out centerNormal,out centerDepth)//获取采样的法线和深度 Camera.worldToCameraMatrix //世界转相机矩阵 world2view Camera.cameraToWorldMatrix //相机转世界矩阵 Camera.projectionMatrix //get投影矩阵viewToproject 视角空间到2维投影空间矩阵,set自定义的投影矩阵。如果你改变这个矩阵,相机的渲染不再基于它的fieldOfView更新,直到调用ResetProjectionMatrix 默认把view2project矩阵叫成project矩阵,默认把World2view矩阵叫做view矩阵。比如ViewProject就是world 2 project矩阵 全局雾效 深度雾效:通过每个顶点的深度值计算出该点到摄像机的距离d,然后把距离d进行参与公式计算得到雾效图(远的雾浓 rgb值大,近的雾淡 rgb值小),再把原图和雾效图进行混合。一般用线性,指数,指数平方公式,ds采用指数平方。 地面雾效:通过深度值和摄像机的方向向量计算该点到摄像机的偏移量,再加上摄像机的位置得到该顶点在世界空间中的坐标,然后把该坐标的y值参与雾效计算。如果用坐标z参与计算和深度雾类似。 #pragma multi_compile_fog 基于法线的边缘检测:防止阴影等信息干扰检测,判断临近的4个点的法线和深度值是否是近似,如果差距过大则是边缘roberts算法。(屏幕后处理) --- 渲染轮廓线:第一个pass对顶点进行法线方向扩散渲染,第二个pass用真实渲染实际光照,覆盖第一次,对扩散的顶点未被覆盖的像素就产生了轮廓效果。(模型轮廓) --------------------------------------------------------------------------------- 噪声 消融效果:怪物消失渐散的效果,把某个像素值小于阈值的裁剪掉,阈值附近的值用burncolor进行混合。阴影的pass里边算阴影时也把该项给clip掉,这样阴影就动态变化了//clip(burn.r - _BurnAmount); 水面扰动效果:用时间去控制偏移距离,然后对该顶点的uv偏移两点的法线平均值来代替该点的法线值。水面=反射+折射+绕动 float2 speed = _Time.y * float2(_WaveXSpeed, _WaveYSpeed); / Get the normal in tangent space fixed3 bump1 = UnpackNormal(tex2D(_WaveMap, i.uv.zw + speed)).rgb; fixed3 bump2 = UnpackNormal(tex2D(_WaveMap, i.uv.zw - speed)).rgb; fixed3 bump = normalize(bump1 + bump2); 全局(动态)雾效:通过时间控制噪声纹理的偏移距离,然后根据噪声颜色值来参与计算雾效浓度,然后计算雾效,就有了流动和淡浓的效果。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Shader实例(流光实现)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明...

    bering
  • Unity开发单例模式防止内存泄漏

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明...

    bering
  • Unity使用AssetImporter整理资源对其进行打包

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明...

    bering
  • gitlab两种连接方式:ssh和http配置介绍

    gitlab环境部署好后,创建project工程,在本地或远程下载gitlab代码,有两种方式:ssh和http (1)ssh方式:这是一种相对安全的方式 ...

    洗尽了浮华
  • 浅议“棱镜”计划2013预算任务

    关键字 安恒信息 网络战 信息安全 APT攻击 ...

    安恒信息
  • vsftpd简介和ftpserver在win10上的下载及安装过程

    vsftpd 是“very secure FTP daemon”的缩写,安全性是它的一个最大的特点。vsftpd 是一个 UNIX 类操作系统上运行的服务器的名...

    泰斗贤若如
  • 简单的动态连接库,例子

    的意思是指文中生成的obj文件应该与Test_of_dll.lib一起链接.或者可以在VC的工程中设置加载此lib

    用户1539362
  • C# 获得设备usb信息

    本文告诉大家如何获得设备的usb来进行判断是否有哪些usb和找不到usb可能是什么。

    林德熙
  • 使用贝叶斯做英文拼写检查(c#)

    贝叶斯算法可以用来做拼写检查、文本分类、垃圾邮件过滤等工作,前面我们用贝叶斯做了文本分类,这次用它来做拼写检查,参考:How to Write a Spelli...

    用户1177380
  • 每个公司应为物联网做准备的3种方式

    物联网是指每天围绕着我们的智能、互联设备、物品和家电的不断增长的网络。这些设备不断地通过互联网收集和传输数据,许多都能够自主执行任务。想想健身追踪器是如何与你手...

    用户4122690

扫码关注云+社区

领取腾讯云代金券