# 前言 本编程指南仅尽可能的列出编写一个shader的参考 # # shader编写结构 ## 1.定义Properties(方便在创建材质的时候可以传入贴图等数据) ## 2.编写SubShader主题 ## 2.1【Tags】 ## 2.2【RenderSetUp】 ### 2.2.1【LOD】渲染深度(详情参考Unity LOD 远景渲染部分) ## 2.3【GrabPass】【UsePass】【Pass】【Pass】(第二个或者其他) ----------------------案例Pass-------------------- 【RenderSetUp】 CGPROGRAM //编译顶点着色器 #pragma vertex vert //编译片元着色器 #pragma fragment frag ### 2.3.1 其他引用以及其它编译指令 ### 2.3.2 声明参数 ### 2.3.3 设置应用数据->顶点着色器结构体a2v,appdata(a2v为app to vert简写) ### 2.3.4 设置顶点->片源着色器结构体v2f(v2f为vert to fragment简写) ### 2.3.5 编写顶点着色器渲染方法 v2f vert (a2v v){ v2f o; //着色器内容 return o; } ### 2.3.5 编写片源着色器渲染方法 fixed4 frag (v2f i) : SV_Target{ fixed4 tex = ...; //着色器内容 return tex; } ENDCG --------------------------------------------------- ## 3.设置Fallback,如果显卡无法运行上面的SubShader,则执行FallBack预设进行渲染 # 1.Properties(参考书籍P30) -------------------------------------------------------------------------- ### 传入数据常用类型 ## Int _Int("Int",Int)=2 ## Float _Float("Float",Float)=1.0 ## Range _Range("Range",Range(0.0,5.0))=1.0 ## Color _Color("Color",Color)=(1,1,1,1) ## Vector _Vector("Vector",Vector)=(1,1,1,1) ## 2D _MainTex ("Texture", 2D) = "white" {} ps:内置纹理名称包含white、black、gray、bump等等 ## Cube _Cubemap ("Environment Cubemap", Cube) = "_Skybox" {} ## 3D _3D ("3D", 3D) = "black" {} -------------------------------------------------------------------------- # 2.Tags(参考网站:https://gameinstitute.qq.com/community/detail/121997) -------------------------------------------------------------------------- ### 渲染类型声明(包含渲染顺序) Tags的书写方法为键值对,可多可少,不需要全部声明,未声明时按默认值 Tags { "RenderType"="Opaque" "Queue"="Transparent" } # 2.1(SubShader)Tags ## key:Queue 渲染顺序,括号内为优先度,值越小越先被渲染 ## value Background(1000) Geometry(2000)【默认】 AlphaTest(2450) Transparent(3000) Overlay(4000) 可以自定义值例如"Queue"="3100" ## key:RenderType 渲染类型 ## value Opaque-----------------不透明(法线、自发光、反射、地形Shader) Transparent------------半透明(透明、粒子、字体、地形添加通道Shader) TransparentCutout------遮罩透明(透明裁切、双通道植物Shader) Background-------------天空盒Shader Overlay----------------GUI纹理、光晕、闪光Shader TreeOpaque-------------地形引擎——树皮 TreeTransparentCutout--地形引擎——树叶 TreeBillboard----------地形引擎——公告牌(始终面向摄像机)式树木 Grass------------------地形引擎——草 GrassBillboard---------地形引擎——公告牌(始终面向摄像机)式草 ## key:DisableBatching 是否禁用Batch(打包、合并) ## value True-------------------禁用 False------------------不禁用(默认) LODFading--------------当LOD fade开启的时候禁用,一般用在树木上面 ## key:ForceNoShadowCasting 是否强制不投射阴影,当这个值为True的时候,使用这个Shader的对象便不会投射阴影。 ## key:IgnoreProjector 无视投影器,当这个值为True的时候,对象便不受投射器影响。 ## key:CanUseSpriteAtlas 可使用精灵集,当这个值为False的时候,不能使用精灵集。 ## key:PreviewType 材质的预览形式,默认显示为球体,可以使用Plane(2D平面)或Skybox(天空盒) # 2.2(Pass)Tags ## key:LightMode 光照模式 ## value Always------------------总是渲染,不使用光照 ForwardBase-------------用于前向渲染,使用环境光、主平行光、顶点/SH(球谐函数)光照以及光照贴图 ForwardAdd--------------用于前向渲染,额外使用每像素光,每个光照一个通道 Deferred----------------用于延迟着色,渲染G-Buffer ShadowCaster------------渲染对象的深度到阴影贴图或者深度纹理 PrepassBase-------------用于(旧版)延迟光照,渲染法线和高光指数 PrepassFinal------------用于(旧版)延迟光照,合并贴图、光照和自发光来渲染最终色彩 Vertex------------------当对象不受光照贴图影响的时候,用来渲染(旧版)顶点发光。使用所有的顶点光照 VertexLMRGBM------------当对象接受光照贴图影响的时候,用来渲染(旧版)顶点发光。适用于使用RGBM编码光照贴图的平台(PC&主机) VertexLM----------------当对象接受光照贴图影响的时候,用来渲染(旧版)顶点发光。适用于使用double-LDR编码光照贴图的平台(移动平台) ## key:PassFlags 标志渲染管线如何传递数据给通道 ## value OnlyDirectional---------只有主平行光、环境光和光照探测器的数据会传递给通道。仅用于LightMode为ForwardBase ## key:RequireOptions 标志通道至于在某些外部条件满足时才会被渲染 SoftVegetation----------当Quality Setting中的Soft Vegetation选项被开启时,才会渲染通道 # 3.RenderSetUp(以下写在CGPROGRAM之前)(参考书籍P31) -------------------------------------------------------------------------- ## 3.1 Cull Cull Back | Front | Off 设置剔除模式:剔除背面/正面/关闭剔除 ## 3.2 ZTest ZTest Less Greater | LEqual | GEqual | Equal | NotEqual | Always 设置深度测试时使用的函数 ## 3.3 ZWrite ZWrite On | Off 开启/关闭深度写入 ## 3.4 Blend BlendOp (Op) 设置混合操作 Blend (SrcFactor) (DstFactor) Blend (SrcFactor) (DstFactor),(SrcFactorA) (DstFactorA) 开启并设置混合模式(透明材质用) 例如:Blend SrcAlpha OneMinusSrcAlpha 其中SrcFactor为源颜色乘以的混合因子 DstFactor为目标颜色乘以的混合因子 两者相加存入颜色缓冲区 Blend混合操作表(参考书籍P174) ----------------------------------------- Add | 源颜色和目标颜色相加 Sub | 源颜色减去目标颜色 RevSub | 目标颜色减去源颜色 Min | 使用目标颜色跟源颜色中较小的值 Max | 使用源颜色跟目标颜色中较大的值 Blend混合因子表(参考书籍P174) ----------------------------------------- One | 1 Zero | 0 SrcColor | 源颜色值 SrcAlpha | 源颜色的透明度值 DstColor | 目标颜色值 DstAlpha | 目标颜色的透明度值 OneMinusSrcColor | 1-源颜色值 OneMinusSrcAlpha | 1-源颜色的透明值 OneMinusDstColor | 1-目标颜色值 OneMinusDstAlpha | 1-目标颜色的透明度值 常用混合类型 ----------------------------------------- 正常--------| Blend SrcAlpha OneMinusSrcAlpha 柔向相加----| Blend OneMinusDstColor One 正片叠底----| Blend DstColor Zero 两倍相乘----| Blend DstColor SrcColor 变暗--------| BlendOp Min ------------| Blend One One 变亮--------| BlendOp Max ------------| Blend One One 滤色--------| Blend OneMinusDstColor One 线性减淡----| Blend One One # 4.Pass -------------------------------------------------------------------------- 渲染所使用的通道,可以使用抓取屏幕图像的Pass--GrabPass 以及引用其他shader的Pass--UsePass 以及自己编写的Pass # 5.vert & frag -------------------------------------------------------------------------- 顶点着色器,编写案例如下 需要前置结构体a2v 输出结构体v2f (应用->顶点坐标->顶点着色器->输出顶点) v2f vert (a2v v){ v2f o; //着色器内容 return o; } 需要前置结构体v2f 输出着色器颜色值fixed4 (顶点->片元着色器->输出颜色) fixed4 frag (v2f i) : SV_Target{ fixed4 tex = ...; //着色器内容 return tex; } ## 5.0 结构体语义(参考书籍P110) ### a2v------从应用阶段传递模型数据给顶点着色器 | 语义 | 描述 | 类型 | | ----------- | ------------------------------------------ | ------------- | | POSITION | 模型空间的顶点位置 | float4 | | NORMAL | 顶点法线 | float3 | | TANGENT | 顶点切线 | float3 | | TEXCOORD0-7 | 该顶点的纹理坐标,可以定义TEXCOORD0,TEXCOORD1表示第一组或者第二组 | float2&float4 | | COLOR | 顶点颜色 | fixed4&float4 | ### v2f------从顶点着色器传递数据给片元着色器 | 语义 | 描述 | 类型 | | ----------- | ----------------- | ------ | | SV_POSITION | 裁剪空间中的顶点坐标 | float4 | | COLOR0 | 通常用于输出第一组顶点颜色,非必需 | fixed4 | | COLOR1 | 通常用于输出第二组顶点颜色,非必需 | fixed4 | | TEXCOORD0-7 | 用于输出纹理坐标0-7 | 任意 | ### SV_Target------片元着色器输出时用的语义 输出值将会存储到渲染目标(Render Target)中。 ### VPOS/WPOS------片元着色器传递屏幕坐标的语义 类型为float4,xy为屏幕空间中的坐标,z为近裁剪平面处于远裁剪平面处的分量,范围0-1。对于w,如果摄像机投影类型为正交投影,w恒为1,如果使用透视投影,w的取值范围为[1/Near,1/Far],Near为近裁剪平面处于摄像机的距离,Far为远裁剪平面处于摄像机的距离。 ## 5.1 变换矩阵(参考书籍P87) ----------------------------------------- ### UNITY_MATRIX_MVP(取模现在被UnityObjectToClipPos(v.vertex)所替代) 当前模型的观察投影矩阵,顶点/方向矢量 模型空间->裁剪空间 ### 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的逆转置矩阵,用于将发现从模型空间变换到观察空间,也可用于得到 UNITY_MATRIX_MV的逆矩阵 ### unity_ObjectToWorld(原为_Object2World) 当前的模型矩阵,用于将顶点/方向矢量从模型空间变换到世界空间 ### unity_WorldToObject(原为_World2Object) unity_ObjectToWorld的逆矩阵,用于将顶点/方向矢量从世界空间变换到模型空间 ## 5.2 Unity内置的摄像机和屏幕参数(参考书籍P88) ------------------------------------------------- ### 【float3】 _WorldSpaceCameraPos 该摄像机在世界空间中的位置 ### 【float4】 _ProjectionParams x = 1.0 & -1.0 | y = Near | z = Far | w = 1.0 + 1.0 / Far Near = 近裁剪平面到摄像机的距离 Far = 远裁剪平面到摄像机的距离 ### 【float4】 _ScreenParams x = width | y = height | z = 1.0 + 1.0 / width | w = 1.0 + 1.0 / height width = 该摄像机的渲染目标的像素宽度 height = 该摄像机的渲染目标的像素高度 ### 【float4】 _ZBufferParams x = 1 - Far / Near | y = Far / Near | z = x / Far | w = y / Far 该变量用于线性化Z缓存中的深度值 ### 【float4】unity_OrthoParams x = width | y = height | z = 无定义 | w = 1.0(该摄像机为正交摄像机) & 0.0(该摄像机为透视摄像机) width = 正交投影摄像机的宽度 height = 正交投影摄像机的高度 ### 【float4x4】unity_CameraProjection 该摄像机的投影矩阵 ### 【float4x4】unity_CameraInvProjection 该摄像机的投影矩阵的逆矩阵 ### 【float4[6]】unity_CameraWorldClipPlanes[6] 该摄像机的6个裁剪平面在世界空间下的等式 按如下顺序:左、右、上、下、近、远裁剪平面 ## 5.3 UnityCG.cginc常用的帮助函数(参考书籍P137) ------------------------------------------------- ### 【float3】 WorldSpaceViewDir(float4 v) 输入:模型空间中的顶点位置 返回:世界空间红从该点到摄像机的观察方向。 ps:内部实现使用了UnityWorldSpaceViewDir函数 ### 【float3】 UnityWorldSpaceViewDir(float4 v) 输入:世界空间中的顶点位置 返回:世界空间中从该点到摄像机的观察方向。 ### 【float3】 ObjectSpaceViewDir(float4 v) 输入:一个模型空间中的顶点位置 返回:模型空间中该点到摄像机的观察方向。 ### 【float3】 WorldSpaceLightDir(float4 v)【仅用于前向渲染】【未被归一化】 输入:一个模型空间中的顶点位置 返回:世界空间中从该点到光源的光照方向。 ps:内部实现使用了UnityWorldSpaceLightDir函数 ### 【float3】 UnityWorldSpaceLightDir(float4 v)【仅用于前向渲染】【未被归一化】 输入:世界空间中的顶点位置 返回:世界空间中该点到光源的光照方向 ### 【float3】 ObjSpaceLightDir(float4 v)【仅用于前向渲染】【未被归一化】 输入:一个模型空间中的顶点位置 返回:模型空间中从该点到光源的光照方向 ### 【float3】 UnityObjectToWorldNormal(float3 normal) 把法线方向从模型空间转换到世界空间中 ### 【float3】 UnityObjectToWorldDir(float3 dir) 把方向矢量从模型空间变换到世界空间中 ### 【float3】 UnityWorldToObjectDir(float3 dir) 把方向矢量从世界空间变换到模型空间中 # 6.关于光照 ## 6.1 Unity渲染路径 ------------------------------------------------------------ 在tag-LightMode里设置,详情见本文2.2 ## 6.2 Unity内置光照变量和函数 ------------------------------------------------------------ ### 【float4】 _LightColor0 该Pass处理的逐像素光源的颜色 ### 【float4】 _WorldSpaceLightPos0 该Pass处理的逐像素光源的位置。 如果该光源是平行光,_WorldSpaceLightPos0.w=0 如果是其他类型光,_WorldSpaceLightPos0.w=1 ### 【float4x4】 _LightMatrix0 从世界空间到光源空间的变换矩阵。可以用于采样cookie和光照衰减纹理 ### 【float4】 unity_4LightPosX0 unity_4LightPosY0 unity_4LightPosZ0 仅用于BasePass 前四个非重要的点光源在世界空间中的位置 ### 【float4】 unity_4LightPosX0 unity_4LightPosY0 unity_4LightPosZ0 仅用于BasePass 前四个非重要的点光源在世界空间中的位置 ### 【float4】 unity_4LightAtten0 仅用于BasePass 前四个非重要的点光源的衰减因子 ### 【half4[4]】 unity_LightColor 仅用于BasePass 前四个非重要的点光源的颜色 ## 6.3 Unity前向渲染可以使用的内置光照参数 ------------------------------------------------------------ 以下函数仅用于前向渲染才可使用。 ### 【float3】 WorldSpaceLightDir(float4 v)【未被归一化】 输入:一个模型空间中的顶点位置 返回:世界空间中从该点到光源的光照方向。 ps:内部实现使用了UnityWorldSpaceLightDir函数 ### 【float3】 UnityWorldSpaceLightDir(float4 v)【未被归一化】 输入:一个世界空间中的顶点位置 返回:世界空间中从该点到光源的光照方向。 ### 【float3】 ObjSpaceLightDir(float4 v)【未被归一化】 输入:一个模型空间中的顶点位置 返回:模型空间中从该点到光源的光照方向。 ### 【float3】 Shade4PointLights(...) 输入:已经打包进矢量的光照数据,参考6.2 返回:计算逐顶点光照。