shader入门基础-基础纹理
shader入门基础-基础纹理
本文内容主要参考 《Unity shader 入门精要》一书,旨在总结所学知识与加深个人理解
光照模型实践,使用单张纹理代替漫反射颜色
高光公式
\[\mathtt{c}_{specular}=(\mathtt{c}_{light}\cdot\mathtt{m}_{specular})max(0,\vec n\cdot\vec h)^{m_{gloss}} \qquad \vec h=\frac{\vec v+\vec l}{|\vec v+\vec l|}\]漫反射公式\(\mathtt{c}_{diffuse}=(\mathtt{c}_{light}\cdot \mathtt{m}_{diffuse})max(0,\vec n \cdot \vec l)\)
根据公式 我们需要取到$\vec n$ 表面法线,$\vec l$ 指向光源的单位矢量,$m_{diffuse}$ 材质漫反射颜色,$m_{specular}$ 材质高光颜色,$c_{light}$ 是光源颜色 _MainTex_ST:在 Unity 中,我们需要使用纹理名_ST 的方式来声明某个纹理的属性。其中 ST 是缩放(scale)和平移(translation)的缩写。_MainTex_ST 可以让我们得到该纹理的缩放和平移值,_MainTex_ST.xy 存储的是缩放值,而_MainTex_ST.zw 存储的是偏移值。在顶点着色器中,我们使用纹理的属性值_MainTex_ST 来对 顶点的纹理坐标进行变换,得到最终的纹理。在 UnityCG.cginc 中有预定义 #define TRANSFORM_TEX(tex,name) (tex.xy*name##_ST.xy+name##_ST.zw)。
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
Shader "Practice/SingleTex"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color("Color Tint",Color)= (1,1,1,1) //漫反射颜色
_Gloss("Gloss",Range(8.0,256)) = 20 //光泽度,光泽度越高反光面积越大
_Specular("Specular",Color) = (1,1,1,1) //高光颜色
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 normal : NORMAL;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
};
sampler2D _MainTex;
float4 _MainTex_ST;
half _Gloss;
fixed4 _Specular;
fixed4 _Color;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex); //转换到裁剪空间
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;//转换到世界空间
o.uv = _MainTex_ST.xy*v.texcoord.xy+_MainTex_ST.zw;
// ==> o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); 等价于上面的转换
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col;
//C_diffuse = (C_light·M_diffuse)max(0,N·L)
fixed3 worldNormal = normalize(i.worldNormal); //归一化后的世界坐标
fixed3 wolrdLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); //光线
fixed3 albedo = tex2D(_MainTex,i.uv).rgb*_Color.rgb; //取样当前纹理映射坐标的颜色 * 漫反射颜色 <==> 反射的颜色
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo; //环境光*反射光
//C_diffuse = (C_light·m_diffuse)max(0,N·L) //漫反射计算公式 这里m_diffuse用的是纹理颜色
fixed3 diffuse = _LightColor0.rgb*albedo*saturate(dot(worldNormal,wolrdLightDir));
//WolrdSpaceViewDir 输入的是模型空间中顶点
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));//输入的是世界空间的顶点坐标
//H=(V+L)/|V+L|
fixed3 halfDir = normalize(wolrdLightDir+viewDir);
//C_specular = (C_light*m_specular)pow(max(0,N·H),m_gloss)
fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(worldNormal,halfDir)),_Gloss);
col = fixed4(ambient+diffuse+specular,1.0);
return col;
}
ENDCG
}
}
}
本文由作者按照 CC BY 4.0 进行授权