unity 版本5.4.1,场景中只有一个方向光,没有天空盒子,光照模式为forward。
光照模式设置为Forward(菜单Edit->Project Settings->Player->OtherSettings->Rending Path->Forward)
顶点漫反射光照模型
虽然优化方面来说比较好,但是效果不好。基于顶点的光照计算导致,光照效果不平滑。
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
//unity shader5.0更新。。详见: https://docs.unity3d.com/Manual/UpgradeGuide5-Shaders.html
Shader "LT/VertexDiffuse"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color("Overall Diffuse Color Filter",Color) = (1,1,1,1)
}
SubShader
{
Pass
{
Tags { "LightMode"="ForwardBase" } //光照模式注意要设置为Forward
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _LightColor0; // color of light source (from "Lighting.cginc")
sampler2D _MainTex;
float4 _Color;
float4 _specColor;
float _Shininess;
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 col : COLOR;
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert (appdata v)
{
v2f o;
//ModelMatrix和ModelMatrixInverse,UNITY内置uniform参数
float4x4 ModelMatrix = unity_ObjectToWorld; //模型矩阵 法向量N变化至对象坐标系
float4x4 ModelMatrixInverse = unity_WorldToObject;
//计算对象坐标系中的顶点法向量的单位向量
//将mesh传递过来的顶点法向量 乘以 模型-->世界坐标系矩阵 得到世界坐标系中的法向量 , 然后单位化。
float3 normalDirection = normalize(mul(ModelMatrix,float4(v.normal,0.0)).xyz);
//float4(v.normal,0.0),ModelMatrixInverse 上面那句乘法部分换成这个结果是一样的,意思也是一样的
//计算入射线量的单位向量
float3 LightDirection= normalize(_WorldSpaceLightPos0.xyz);//==normalize(float3 (_WorldSpaceLightPos0));
//计算入射后的颜色
//先将光源颜色与材料颜色相乘, 载乘以上max(0,cos(N,L)),入射向量与法线夹角超过90度为模型的另一面,避免出现>90度,cos为负数的情况
float3 diffuseReflection = _LightColor0.xyz * _Color.xyz * max(0.0,dot(normalDirection,LightDirection));
o.col = float4(diffuseReflection,1.0) + UNITY_LIGHTMODEL_AMBIENT; //float4(diffuseReflection,1.0)
o.vertex =mul(UNITY_MATRIX_MVP,v.vertex) ;
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv) * i.col;
return col;
}
ENDCG
}
}
Fallback "Diffuse"
}
半兰伯特光照模型
半兰伯特光照模型,解了决光照无法到达的区域, 背光面更亮一些
shader"LT/HalfLambert"
{
Properties
{
_Diffuse("Diffuse Color",Color) = (1,1,1,1)
_MainTex("Texture",2D) = "white" {}
}
SubShader
{
Pass
{
Tags{"LightMode"="ForwardBase"}
//Tags{"LightMod"="ForwardBass"} 这句之前单词拼错了,结果导致移动视角的时候模型乎暗乎亮的。unity没报错找半天原因才发现额
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc" //==与下面那句uniform float4 _LightColor0; 2选一写出即可
fixed4 _Diffuse;
sampler2D _MainTex;
// uniform float4 _LightColor0;
struct a2v
{
float4 pos :POSITION;
float2 uv:TEXCOORD0;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos: SV_POSITION;
float3 worldNormal : TEXCOORD1;
float2 uv:TEXCOORD0;
};
v2f vert(a2v v)
{
v2f o;
// float4x4 modelMetrix = unity_ObjectToWorld; //可声明也可不声明直接写在下句
o.worldNormal = normalize( mul((float3x3)unity_ObjectToWorld,v.normal)); //法线模型坐标转化为世界坐标
o.uv = v.uv;
o.pos = mul(UNITY_MATRIX_MVP,v.pos);
return o;
}
fixed4 frag(v2f i): SV_Target
{
fixed4 ambient = UNITY_LIGHTMODEL_AMBIENT; //环境光
fixed4 worldLight = normalize(_WorldSpaceLightPos0);
fixed halfLambert = dot(i.worldNormal,worldLight) * 0.5+0.5; //半兰伯特公式算法
fixed4 diffuse = _LightColor0 * _Diffuse * halfLambert; //半兰伯特漫反射
fixed4 col = tex2D(_MainTex , i.uv) * (diffuse + ambient);
return col;
}
ENDCG
}
}
Fallback "Diffuse"
}
高光反射光照
逐像素光照,光照效果过度更均匀。
Shader "LT/PixelSpecular"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1) //高光反射颜色
_Gloss("gloss", Range(5,30)) = 10 //高光区域大小
}
SubShader
{
Pass
{
Tags { "LightMode"="ForwardBase" } //光照模式注意要设置为Forward
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
float4 _MainTex_ST;
struct appdata
{
float4 vertex : POSITION;
float3 normal:NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldNormal:TEXCOORD1;
float3 worldPos:TEXCOORD2;
};
v2f vert (appdata v)
{
v2f o;
o.worldNormal = normalize(mul((float3x3)unity_ObjectToWorld,v.normal)); //法向量从对象坐标系转换为世界坐标
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz; //顶点从对象坐标系转换为世界坐标
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//漫反射光照计算
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal,worldLightDir));
//反射方向 = 单位化反射光照计算函数
fixed3 reflectDir = normalize(reflect(-worldLightDir,i.worldNormal));
//视角方向 = 单位化(相机方向- 顶点位置)世界坐标系下
fixed3 ViewDir = normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);
//反射光 = 光照颜色*反射光颜色*视角与反射光方向的点积的光滑洗漱次方
fixed3 specular = _LightColor0.rgb* _Specular.rgb * pow(saturate(dot(ViewDir,reflectDir)),_Gloss);
fixed4 col = tex2D(_MainTex, i.uv) * fixed4(diffuse + specular + ambient,1.0);
return col;
}
ENDCG
}
}
Fallback "Specular"
}
Blinn-Phong光照模型
大部分内容与前面逐像素高光反射模型差不多,效果会更亮一些
Shader "LT/Blinn-Phong"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1) //高光反射颜色
_Gloss("gloss", Range(5,30)) = 10 //高光区域大小
}
SubShader
{
Pass
{
Tags { "LightMode"="ForwardBase" } //光照模式注意要设置为Forward
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
float4 _MainTex_ST;
struct appdata
{
float4 vertex : POSITION;
float3 normal:NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldNormal:TEXCOORD1;
float3 worldPos:TEXCOORD2;
};
v2f vert (appdata v)
{
v2f o;
o.worldNormal = normalize(mul((float3x3)unity_ObjectToWorld,v.normal)); //法向量从对象坐标系转换为世界坐标
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz; //顶点从对象坐标系转换为世界坐标
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//漫反射光照计算
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal,worldLightDir));
//反射方向 = 单位化反射光照计算函数
// fixed3 reflectDir = normalize(reflect(-worldLightDir,i.worldNormal));
//视角方向 = 单位化(相机方向- 顶点位置)世界坐标系下
fixed3 ViewDir = normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);
fixed3 halfDir = normalize(worldLightDir+ViewDir);
//反射光 = 光照颜色*反射光颜色*视角与反射光方向的点积的光滑洗漱次方
fixed3 specular = _LightColor0.rgb* _Specular.rgb * pow(saturate(dot(ViewDir,halfDir)),_Gloss);
fixed4 col = tex2D(_MainTex, i.uv) * fixed4(diffuse + specular + ambient,1.0);
return col;
}
ENDCG
}
}
Fallback "Specular"
}
最后上张效果图,用到的C#脚本后面会说到