Shader基础
shader
Shader的名字会直接决定shader在material里出现的路径
SubShader 顶点函数与片元函数通信
Shader "LiHao/Shader03"{
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v{
float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
float3 normal:NORMAL;//告诉unity把模型空间下的法线方向填充给normal
float4 texcoord:TEXCOORD0;//告诉unity把第一套纹理坐标填充给texcoord
};
struct v2f{
float4 position:SV_POSITION;
float3 temp:COLOR0;
};
v2f vert(a2v v){
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
f.temp = v.normal;
return f;
}
fixed4 frag(v2f f) :SV_Target{
return fixed4(f.temp, 1);
}
ENDCG
}
}
Fallback "VertexLit"
}
Unity Shader语义
1、从应用阶段传递模型数据给顶点着色器时的语义表如下:
语义 | 描述 |
POSITION | 模型空间中的顶点坐标 通常float4 |
NORMAL | 模型空间中的顶点法线 通常float3 |
TANGENT | 模型空间中的顶点切线 通常 float4 |
TEXCOORD(n) | 模型空间中的顶点的纹理坐标 n组 |
COLOR | 模型空间中的顶点颜色 通常fixed4 float4 |
2、从顶点着色器传递到片元着色器时支持的语义表如下:
语义 | 描述 |
SV_POSITION | 剪裁空间中的顶点坐标 |
COLOR0 | 通常用于输出第一组顶点颜色,不是必须 |
COLOR1 | 通常用于输出第二组顶点颜色,不是必须 |
TEXCOORDN(0~7) | 通常用于输出第n组纹理坐标,不是必须 |
3、片元着色器输出时支持的语义:
语义 | 描述 |
SV_Target | 输出值将会存储到渲染目标中 |
什么是光照模型
光照模型就是一个公式,使用这个公式来计算在某个点的光照效果
标准光照模型
在标准光照模型里面,我们把进入摄像机的光分为下面四个部分
自发光(emissive) | |
高光反射(specular) | Specular=直射光颜色*pow(max(cosθ,0),10) 注:θ:是反射光方向和视野方向的夹角 |
漫反射 (diffuse) | Diffuse=直射光颜色*max(0,cos夹角(光和法线的夹角)) |
环境光 (ambient) |
Tags{"LightMode"="ForwardBase"} | 只有定义了正确的LightMode才能得到Unity内置的光照变量 |
#include "Lighting.cginc" | 包含unity的内置的文件,才可以使用unity内置的一些变量 |
normalize() | 用来把一个向量,单位化(原来方向保持不变,长度变为1) |
max() | 用来取得函数中最大的一个 |
dot() | 用来取得两个向量的点积 |
_WorldSpaceLightPos0 | 取得平行光的位置 |
_LightColor0 | 取得平行光的颜色 |
UNITY_MATRIX_MVP | 这个矩阵用来把一个坐标从模型空间 转换到剪裁空间 |
_World2Object | 这个矩阵用来把一个方向从世界空间转换到模型空间 |
逐顶点漫反射实例:
Shader "LiHao/04_Diffuse_Vertex"{
Properties{
_Diffuse("Diffuse Color", Color) = (1,1,1,1)
}
SubShader{
Pass{
Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
struct a2v{
float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
float3 normal:NORMAL;//告诉unity把模型空间下的法线方向填充给normal
};
struct v2f{
float4 position:SV_POSITION;
float3 color:COLOR;
};
v2f vert(a2v v){
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 normalDir = normalize(mul(v.normal, (float3x3)_World2Object));
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb*max(dot(normalDir, lightDir), 0)*_Diffuse.rgb;
f.color = diffuse+ambient;
return f;
}
fixed4 frag(v2f f) :SV_Target{
return fixed4(f.color, 1);
}
ENDCG
}
}
Fallback "VertexLit"
}
逐像素漫反射示例:
Shader "LiHao/05_Diffuse_Fragment"{
Properties{
_Diffuse("Diffuse Color", Color) = (1,1,1,1)
}
SubShader{
Pass{
Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
struct a2v{
float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
float3 normal:NORMAL;//告诉unity把模型空间下的法线方向填充给normal
};
struct v2f{
float4 position:SV_POSITION;
//float3 color:COLOR;
float3 worldNormalDir:COLOR;
};
v2f vert(a2v v){
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
f.worldNormalDir = mul(v.normal, (float3x3)_World2Object);
return f;
}
fixed4 frag(v2f f) :SV_Target{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 normalDir = normalize(f.worldNormalDir);
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb*max(dot(normalDir, lightDir), 0)*_Diffuse.rgb;
float3 diffTemp = diffuse + ambient;
return fixed4(diffTemp, 1);
}
ENDCG
}
}
Fallback "VertexLit"
}
逐顶点与逐像素漫反射对比
高光反射
逐顶点高光反射:
Shader "LiHao/07_Specular_Vertex"{
Properties{
_Diffuse("Diffuse Color", Color) = (1, 1, 1, 1)
_Specular("Specular Color", Color) = (1,1,1,1)
_Gloss("Gloss",Range(8,200))=10
}
SubShader{
Pass{
Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
struct a2v{
float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
float3 normal:NORMAL;//告诉unity把模型空间下的法线方向填充给normal
};
struct v2f{
float4 position:SV_POSITION;
float3 color:COLOR;
};
v2f vert(a2v v){
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 normalDir = normalize(mul(v.normal, (float3x3)_World2Object));
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb*max(dot(normalDir, lightDir), 0)*_Diffuse.rgb;
fixed3 reflectDir = normalize(reflect(-lightDir, normalDir));
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(v.vertex, _World2Object));
fixed3 specular = _LightColor0.rgb*_Specular*pow(max(dot(reflectDir, viewDir), 0), _Gloss);
f.color = diffuse + ambient + specular;
return f;
}
fixed4 frag(v2f f) :SV_Target{
return fixed4(f.color, 1);
}
ENDCG
}
}
Fallback "VertexLit"
}
逐像素高光反射:
Shader "LiHao/08_Specular_Fragment"{
Properties{
_Diffuse("Diffuse Color", Color) = (1, 1, 1, 1)
_Specular("Specular Color", Color) = (1,1,1,1)
_Gloss("Gloss",Range(8,200))=10
}
SubShader{
Pass{
Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
struct a2v{
float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
float3 normal:NORMAL;//告诉unity把模型空间下的法线方向填充给normal
};
struct v2f{
float4 position:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldVertex:TEXCOORD1;
};
v2f vert(a2v v){
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
f.worldNormal = mul(v.normal, (float3x3)_World2Object);
f.worldVertex = mul(v.vertex, _World2Object);
return f;
}
fixed4 frag(v2f f) :SV_Target{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 normalDir = normalize(f.worldNormal);
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb*max(dot(normalDir, lightDir), 0)*_Diffuse.rgb;
fixed3 reflectDir = normalize(reflect(-lightDir, normalDir));
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertex);
fixed3 specular = _LightColor0.rgb*_Specular*pow(max(dot(reflectDir, viewDir), 0), _Gloss);
fixed3 tempColor = diffuse + ambient + specular;
return fixed4(tempColor, 1);
}
ENDCG
}
}
Fallback "VertexLit"
}
逐顶点与逐像素高光反射对比:
Blinn-Phong 高光反射模型
这种光照模型的高光反射看起来更大,更亮一些。在实际渲染中,绝大多数情况会选择 Blinn-Phong 光照模型,此种光照模型更符合实验结果
与普通高光反射对比:
Shader "LiHao/09_Specular_Fragment_Blinn-Phong-unity"{
Properties{
_Diffuse("Diffuse Color", Color) = (1, 1, 1, 1) //漫反射颜色
_Specular("Specular Color", Color) = (1,1,1,1) //高光颜色
_Gloss("Gloss",Range(8,200))=10 //控制高光区域大小
}
SubShader{
Pass{
Tags{ "LightMode" = "ForwardBase" } //定义该Pass在Unity流水线中用于前向渲染
CGPROGRAM //与ENDCG配对用于包裹Cg代码片
#include "Lighting.cginc" //引入内置文件
#pragma vertex vert //利用#pragma告诉Unity顶点着色器的名字叫vert
#pragma fragment frag //利用#pragma告诉Unity片元着色器的名字叫frag
fixed4 _Diffuse; //定义于Properties中相匹配的变量
fixed4 _Specular;
half _Gloss;
struct a2v{ //顶点着色器的输入结构体
float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
float3 normal:NORMAL;//告诉unity把模型空间下的法线方向填充给normal
};
struct v2f{ //顶点着色器的输出结构体和片元着色器的输入结构体
float4 position:SV_POSITION; //模型的顶点信息(基于剪裁空间)
float3 worldNormal:TEXCOORD0; //模型的法线信息(基于世界空间)
float4 worldVertex:TEXCOORD1; //模型的顶点信息(基于世界空间)
};
v2f vert(a2v v){
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex); //顶点位置信息从模型空间转换到剪裁空间
//f.worldNormal = mul(v.normal, (float3x3)_World2Object);
f.worldNormal = UnityObjectToWorldNormal(v.normal); //模型坐标的法线信息从模型空间转换到世界空间
f.worldVertex = mul(v.vertex, _World2Object); //模型坐标的顶点信息从模型空间转换到世界空间
return f;
}
fixed4 frag(v2f f) :SV_Target{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//环境光
fixed3 normalDir = normalize(f.worldNormal); //法线方向
//fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 ligthDir = normalize(WorldSpaceLightDir(f.worldVertex).xyz); //光照方向
fixed3 diffuse = _LightColor0.rgb*max(dot(normalDir, ligthDir), 0)*_Diffuse.rgb; //漫反射
//fixed3 reflectDir = normalize(reflect(-lightDir, normalDir));
//fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertex);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertex).xyz); //视角方向
fixed3 halfDir = normalize(viewDir + ligthDir); // Blinn-Phong 光照模型计算
fixed3 specular = _LightColor0.rgb*_Specular*pow(max(dot(normalDir, halfDir), 0), _Gloss); //高光反射
fixed3 tempColor = diffuse + ambient + specular;
return fixed4(tempColor, 1);
}
ENDCG
}
}
Fallback "VertexLit"
}