顶点/片元着色器
在整个渲染流程,顶点与片元阶段是可编程的,也就是在此阶段我们才可以对模型的渲染过程进行修改,达到我们想要的渲染效果。
顶点、片元着色器定义在SubShader中的Pass块中,编写顶点、片元着色器更为复杂,但是灵活性更高,我们可以控制的细节更多。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
Shader "CS02/MiniShader" //Shader的真正名字 可以是路径式的格式 { /*材质球参数及UI面板 https://docs.unity3d.com/cn/current/Manual/SL-Properties.html https://docs.unity3d.com/cn/current/ScriptReference/MaterialPropertyDrawer.html https://zhuanlan.zhihu.com/p/93194054 */ Properties { _MainTex ("Texture", 2D) = "" {} _Float("Float", Float) = 0.0 _Slider("Slider", Range(0.0,1.0)) = 0.07 _Vector("Vector", Vector) = (.34, .85, .92, 1) } /* 这是为了让你可以在一个Shader文件中写多种版本的Shader,但只有一个会被使用。 提供多个版本的SubShader,Unity可以根据对应平台选择最合适的Shader 或者配合LOD机制一起使用。 一般写一个即可 */ SubShader { /* 标签属性,有两种:一种是SubShader层级,一种在Pass层级 https://docs.unity3d.com/cn/current/Manual/SL-SubShaderTags.html https://docs.unity3d.com/cn/current/Manual/SL-PassTags.html */ Tags { "RenderType"="Opaque" } /* Cull 有三种:Off、Back、Front 分别为:正反都不剔除、背面剔除、正面剔除 */ Cull Off /* Pass里面的内容Shader代码真正起作用的地方, 一个Pass对应一个真正意义上运行在GPU上的完整着色器(Vertex-Fragment Shader) 一个SubShader里面可以包含多个Pass,每个Pass会被按顺序执行 */ Pass { CGPROGRAM // Shader代码从这里开始 #pragma vertex vert //指定一个名为"vert"的函数为顶点Shader #pragma fragment frag //指定一个名为"frag"函数为片元Shader #include "UnityCG.cginc" //引用Unity内置的文件,很方便,有很多现成的函数提供使用 //https://docs.unity3d.com/Manual/SL-VertexProgramInputs.html struct a2v //CPU向顶点Shader提供的模型数据 { //冒号后面的是特定语义词,告诉CPU需要哪些类型的数据 float4 vertex : POSITION; //模型空间顶点坐标 half2 texcoord0 : TEXCOORD0; //第一套纹理坐标(UV) half2 texcoord1 : TEXCOORD1; //第二套纹理坐标(UV) half2 texcoord2 : TEXCOORD2; //第三套纹理坐标(UV) half2 texcoord4 : TEXCOORD3; //第四套纹理坐标(UV)模型最多只能有4套UV half4 color : COLOR; //顶点颜色 half3 normal : NORMAL; //顶点法线 half4 tangent : TANGENT; //顶点切线(模型导入Unity后自动计算得到) }; struct v2f //自定义数据结构体,顶点着色器输出的数据,也是片元着色器输入数据 { float4 pos : SV_POSITION; //输出裁剪空间下的顶点坐标数据,给光栅化使用,必须要写的数据 float2 uv : TEXCOORD0; //自定义数据体 //注意跟上方的TEXCOORD的意义是不一样的,上方代表的是UV,这里可以是任意数据。 //插值器:输出后会被光栅化进行插值,而后作为输入数据,进入片元Shader //最多可以写16个:TEXCOORD0 ~ TEXCOORD15。 float3 normal : TEXCOORD1; }; /* Shader内的变量声明,如果跟上面Properties模块内的参数同名,就可以产生链接 */ sampler2D _MainTex; float4 _MainTex_ST; //Unity内置变量:https://docs.unity3d.com/560/Documentation/Manual/SL-UnityShaderVariables.html //Unity内置函数:https://docs.unity3d.com/560/Documentation/Manual/SL-BuiltinFunctions.html //顶点Shader v2f vert (a2v v) { v2f o; float4 pos_world = mul(unity_ObjectToWorld, v.vertex); float4 pos_view = mul(UNITY_MATRIX_V, pos_world); float4 pos_clip = mul(UNITY_MATRIX_P, pos_view); o.pos = pos_clip; //o.pos = mul(UNITY_MATRIX_MVP, v.vertex); //o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord0 * _MainTex_ST.xy + _MainTex_ST.zw; //o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.normal = v.normal; return o; } //片元Shader half4 frag (v2f f) : SV_Target //SV_Target表示为:片元Shader输出的目标地(渲染目标) { //fixed4 col = tex2D(_MainTex, f.uv); half4 col = float4(f.uv,0.0,0.0); return col; } ENDCG // Shader代码从这里结束 } } } |
解释
#pragma vertex vert
定义用来处理顶点着色器的方法。vert为方法名,可修改
#pragma fragment frag
定义用来处理片元着色器的方法。frag为方法名,可修改
a2v
结构体, 用来定义顶点着色器的输入,包含了一些固定语义如下
- POSITION 是顶点位置,通常为 float3 或 float4。
- NORMAL 是顶点法线,通常为 float3。
- TEXCOORD0 是第一个 UV 坐标,通常为 float2、float3 或 float4。
- TEXCOORD1、TEXCOORD2 和 TEXCOORD3 分别是第 2、第 3 和第 4 个 UV 坐标。
- TANGENT 是切线矢量(用于法线贴图),通常为 float4。
- COLOR 是每顶点颜色,通常为 float4。
UnityObjectToClipPos
Unity内置函数,用来将顶点坐标从模型空间转换到裁剪空间
模型空间转为裁剪空间实际需要如下步骤
模型空间->世界空间->相机空间->裁剪空间
Unity提供的空间变换函数
UNITY_MATRIX_MVP | 当前模型 * 视图 * 投影矩阵。 |
UNITY_MATRIX_MV | 当前模型 * 视图矩阵。 |
UNITY_MATRIX_V | 当前视图矩阵。 |
UNITY_MATRIX_P | 当前投影矩阵。 |
UNITY_MATRIX_VP | 当前视图 * 投影矩阵。 |
UNITY_MATRIX_T_MV | 模型转置 * 视图矩阵。 |
UNITY_MATRIX_IT_MV | 模型逆转置 * 视图矩阵。 |
unity_ObjectToWorld | 当前模型矩阵。 |
unity_WorldToObject | 当前世界矩阵的逆矩阵。 |
- 本文固定链接: http://www.u3d8.com/?p=2548
- 转载请注明: 网虫虫 在 u3d8.com 发表过