1. 获取环境光
unity shader中可以通过 UNITY_LIGHTMODEL_AMBIENT获取当前环境光颜色信息。
fixed4 frag(v2f i) : SV_Target
{
return UNITY_LIGHTMODEL_AMBIENT;
}
2. 漫反射
2.1 兰伯特模型
- 创建Chapter_6_Diffuse_Lambert作为测试材质
- 创建Chapter_6_Diffuse_Lambert作为测试shader,并赋给Chapter_6_Diffuse_Lambert材质
- Pass中增加Tags{“LightMode” = “ForwardBase”},并添加引用 #include “Lighting.cginc”
- 场景中创建胶囊体,将Chapter_6_Diffuse_Lambert材质赋给胶囊体
- 场景中添加一盏平行光,并调整平行光角度
shader如下:
Shader "MyShader/Chapter_6/Chapter_6_Diffuse_Lambert"
{
Properties
{
_Diffuse("Diffuse", Color) = (1,1,1,1)
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR0;
};
fixed4 _Diffuse;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 _lightDir = normalize(ObjSpaceLightDir(i.vertex));
float3 _normal = normalize(i.normal);
fixed3 _diffuse = _LightColor0.rgb * _Diffuse.xyz * saturate(dot(_normal, _lightDir));
o.color = fixed4(_diffuse + _ambient, 1);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return i.color;
}
ENDCG
}
}
}
shader效果如下:
2.2 半兰伯特模型
- 将顶点着色器中的 fixed3 _diffuse = _LightColor0.rgb * _Diffuse.xyz * saturate(dot(_normal, _lightDir)); 修改为
fixed3 _diffuse = _LightColor0.rgb * _Diffuse.xyz * (0.5 * dot(_normal, _lightDir) + 0.5);
效果如下:
2.3 逐像素的漫反射
- 以兰伯特模型为基础,将光照计算改为在片元着色器中逐像素处理
- 需要在顶点着色器中先将顶点的法线转换到世界空间
- 然后在片元着色器中用插值得到的当前像素的法线方向与世界空间下的光源方向进行光照计算
- 由于平行光不关心位置信息,因此对于平行光源,_WorldSpaceLightPos0.xyz存储的是光源的方向而不是位置
shader如下:
Shader "MyShader/Chapter_6/Chapter_6_Diffuse_LambertInFragment"
{
Properties
{
_Diffuse("Diffuse", Color) = (1,1,1,1)
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 worldNormal : COLOR0;
};
fixed4 _Diffuse;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 _worldNormal = normalize(i.worldNormal);
float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 _diffuse = _LightColor0.rgb * _Diffuse.xyz * saturate(dot(_worldNormal, _worldLight));
return fixed4(_diffuse + _ambient, 1);
}
ENDCG
}
}
}
效果如下:
可见与逐顶点光照相比,阴影边缘明显更加平滑
3. 高光反射
3.1 逐顶点光照的Phong模型
shader如下:
Shader "MyShader/Chapter_6/Chapter_6_Specular_PhongInVertex"
{
Properties
{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(1.0, 256.0)) = 20
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR0;
};
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 _lightDir = normalize(ObjSpaceLightDir(i.vertex));
float3 _normalDir = normalize(i.normal);
fixed3 _diffuse = _LightColor0.rgb * _Diffuse.xyz * saturate(dot(_lightDir, _normalDir));
float3 _viewDir = normalize(ObjSpaceViewDir(i.vertex));
float3 _reflDir = normalize(2 * dot(_lightDir, _normalDir) * _normalDir - _lightDir);
fixed3 _specular = _LightColor0.rgb * _Specular.xyz * pow(saturate(dot(_viewDir, _reflDir)), _Gloss);
o.color = fixed4(_diffuse + _specular + _ambient, 1);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return i.color;
}
ENDCG
}
}
}
效果如下:
3.2 逐像素光照的Phong模型
- 这里用 reflect(-_worldLight, _worldNormal) 方法代替了原来手动计算反射光线的过程,二者结果是一样的
- reflect方法要求传入的入射光方向是从光源指向照射点,因此需要将原来计算得到的光源方向先取反再传入
shader如下:
Shader "MyShader/Chapter_6/Chapter_6_Specular_PhongInFragment"
{
Properties
{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(1.0, 256.0)) = 20
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 worldNormal : COLOR0;
float3 worldPos : COLOR1;
};
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
o.worldPos = mul(unity_ObjectToWorld, i.vertex).xyz;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 _worldNormal = normalize(i.worldNormal);
float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 _diffuse = _LightColor0.rgb * _Diffuse.xyz * saturate(dot(_worldNormal, _worldLight));
float3 _viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);
// float3 _reflDir = normalize(2 * dot(_worldNormal, _worldLight) * _worldNormal - _worldLight);
float3 _reflDir = normalize(reflect(-_worldLight, _worldNormal));
fixed3 _specular = _LightColor0.rgb * _Specular.xyz * pow(saturate(dot(_viewDir, _reflDir)), _Gloss);
return fixed4(_diffuse + _specular + _ambient, 1);
}
ENDCG
}
}
}
效果如下:
3.3 逐像素光照的Blinn-Phong模型
shader如下:
Shader "MyShader/Chapter_6/Chapter_6_Specular_BlinnPhongInFragment"
{
Properties
{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(1.0, 256.0)) = 20
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 worldNormal : COLOR0;
float3 worldPos : COLOR1;
};
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
o.worldPos = mul(unity_ObjectToWorld, i.vertex).xyz;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 _worldNormal = normalize(i.worldNormal);
float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 _diffuse = _LightColor0.rgb * _Diffuse.xyz * saturate(dot(_worldNormal, _worldLight));
float3 _worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);
float3 _h = normalize(_worldLight + _worldView);
fixed3 _specular = _LightColor0.rgb * _Specular.xyz * pow(saturate(dot(_h, _worldNormal)), _Gloss);
return fixed4(_diffuse + _specular + _ambient, 1);
}
ENDCG
}
}
}
效果如下:
相同Gloss下感觉Blinn-Phong好像要更发散一些,逐顶点的Blinn-Phong就不做了。