- A+
所属分类:UnityShader 原创文章
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 |
Shader "chicai/diffuse" { Properties{ _Diffuse("Diffuse",Color) = (1,1,1,1) } SubShader{//子着色器 Pass{//通道 Tags{ "LightMode"="ForwardBase" } CGPROGRAM #include "Lighting.cginc" //包含了一些光照的宏 fixed4 _Diffuse;//假装是物体的自身颜色 struct a2v{ float4 v:POSITION; float3 nor:NORMAL; }; struct v2f{ float4 position:SV_POSITION; float3 col:COLOR0; }; #pragma vertex vert #pragma fragment frag v2f vert(a2v v){ v2f f; f.position = UnityObjectToClipPos(v.v); //计算光颜色 fixed3 norDir = normalize((fixed3) mul(unity_ObjectToWorld,float4(v.nor,0))); fixed3 lightDir = normalize( _WorldSpaceLightPos0.xyz ); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//环境光 float rate = dot(norDir,lightDir) * 0.5 + 0.5; //半兰伯特计算公式 f.col = _LightColor0.rgb * rate * _Diffuse + ambient; return f; } fixed4 frag(v2f f):SV_Target{ return fixed4(f.col,1); } ENDCG } } } |
一、来解析一下这一堆代码吧!首先,看前面一段,属性的声明,_Diffuse-属性("显示的名称",Color(类型)) = (1,1,1,1)
1 2 3 |
Properties{ _Diffuse("Diffuse",Color) = (1,1,1,1) } |
二、两个结构体
1 2 3 4 5 6 7 8 9 |
struct a2v{ float4 v:POSITION; float3 nor:NORMAL; }; struct v2f{ float4 position:SV_POSITION; float3 col:COLOR0; }; |
a2v表示 application to vertex,表示是应用传进来给顶点函数的,v2f表示vertex to fragment,表示的是顶点函数传递给片元函数,里面属性加:后面的是语义,POSITION表示顶点,NORMAL表示法线,都是模型空间的,SV_POSITION表示传入给片元函数的顶点数据,COLOR0就是颜色的意思
三、声明顶点处理函数和片元处理函数
1 2 |
#pragma vertex vert #pragma fragment frag |
四、顶点函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
v2f vert(a2v v){ v2f f; f.position = UnityObjectToClipPos(v.v); //计算光颜色 fixed3 norDir = normalize((fixed3) mul(unity_ObjectToWorld,float4(v.nor,0))); fixed3 lightDir = normalize( _WorldSpaceLightPos0.xyz ); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//环境光 float rate = dot(norDir,lightDir) * 0.5 + 0.5; //半兰伯特计算公式 f.col = _LightColor0.rgb * rate * _Diffuse + ambient; return f; } |
传入a2v结构数据,在里面构造出v2f数据,UnityObjectToClipPos(模型顶点) 转化模型空间的点到剪裁空间,unity_ObjectToWorld 模型空间到世界空间的转换矩阵,_WorldSpaceLightPos0 世界空间下的光线方向,半兰伯特计算公式,dot() 点乘范围=cos()[-1,1],*0.5后[-0.5,0.5],再+0.5=[0,1],刚好是0-1之间,受光照的强度,颜色相乘表示融合,颜色相加表示加强
五、片元函数
1 2 3 |
fixed4 frag(v2f f):SV_Target{ return fixed4(f.col,1); } |
SV_Target语义表示 返回的颜色
六、兰伯特的计算公式
1 2 |
float rate = max(dot(norDir,lightDir),0); f.col = _LightColor0.rgb * rate * _Diffuse + ambient; |
缺点就是,小于0的,就是[-1-0]区间的都是0,这样就会黑乎乎一片
兰伯特和半兰伯特效果对比
左边是兰伯特(黑乎乎的),右边半兰伯特