Chapter 9 经典光照模型
前言
最近再阅读《GPU 编程与 CG 语言之阳春白雪下里巴人》 就想着用Unity Shader实现其中的代码,文章夹杂了自己的一些理解,难免会有很多错误,希望多多指出,一起交流进步。
阅读本文需要有一定的基础 0基础可以先去阅读 零基础入门Unity Shader 系列文章
漫反射
Lambert 光照模型 :
其中的 表示环境光的强度,
表示材质对环境光的反射系数(通常用Color值来表示)
表示入射光方向与顶点法线的夹角
最后公式为:
是法向量
是光的方向
Unity中的Shader 代码如下:
Shader "Unlit/diffuse"
{
Properties
{
// 控制Kd的强度
_KdIntensity ("Kd Intensity", Range(0, 1)) = 0.5
// 系数
_Kd ("Kd", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
Tags{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
float _KdIntensity;
float4 _Kd;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};
v2f vert (a2v v)
{
v2f o;
// 裁切空间
o.pos = UnityObjectToClipPos(v.vertex);
// 世界坐标法向量
o.normal = UnityObjectToWorldNormal(v.normal);
// 世界坐标
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
float4 frag (v2f i) : SV_Target
{
float3 N = normalize(i.normal);
float3 L = normalize(UnityWorldSpaceLightDir(i.worldPos)).xyz;
// 环境光
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Kd;
//漫反射
float3 diffuse =_Kd * _LightColor0.rgb * _KdIntensity * max(dot(N, L), 0);
return float4(ambient + diffuse, 1.0);
}
ENDCG
}
}
}
效果如下
镜面反射 Phong模型
这个属于高光反射
公式:
其中
为镜面反射系数,
是高光系数,
观察方向,
反射光方向
是法向量
是光的方向
图示如下:
图中我写错了 应该是
的
Unity Shader代码如下
Shader "Unlit/Phong"
{
Properties
{
_Glossness ("Shininess", Range(8, 256)) = 8
_Kd ("Diffuse Color", Color) = (1, 1, 1, 1)
_Ks ("Specular Color", Color) = (1, 1, 1, 1)
// 强度
_KdIntensity ("Kd Intensity", Range(0, 1)) = 0.5
_KsIntensity ("Ks Intensity", Range(0, 1)) = 0.5
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
Tags{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
float _Glossness;
float _KdIntensity;
float _KsIntensity;
float4 _Kd;
float4 _Ks;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};
v2f vert (a2v v)
{
v2f o;
// 裁切空间
o.pos = UnityObjectToClipPos(v.vertex);
// 世界坐标法向量
o.normal = UnityObjectToWorldNormal(v.normal);
// 世界坐标
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
float4 frag (v2f i) : SV_Target
{
float3 N = normalize(i.normal);
float3 L = normalize(UnityWorldSpaceLightDir(i.worldPos)).xyz;
float3 V = normalize(UnityWorldSpaceViewDir(i.worldPos)).xyz;
// 当入射角度和N为负数的时候说明接受不到高光
float3 R = normalize(2 * max(dot(N, L), 0) * N - L);
// 环境光
float3 ambient = _Kd * UNITY_LIGHTMODEL_AMBIENT.xyz;
//漫反射
float3 diffuse = _Kd.rgb * _LightColor0.rgb * _KdIntensity * max(dot(N, L), 0);
// 高光
float3 specular = _Ks.rgb * _LightColor0.rgb * _KsIntensity * pow(max(dot(V, R), 0), _Glossness);
return float4(ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
}
效果如下:
Blinn-Phong模型
在Phong 光照模型中 必须计算的值,在Blinn-Phong中我们用
取代
公式如下:
其中
是法向量
是 入射方向
和视点方向
的中间向量
和
的含义同上
如图所示:
代码如下:
Shader "Unlit/Blinn-Phong"
{
Properties
{
_Glossness ("Shininess", Range(8, 256)) = 8
_Kd ("Diffuse Color", Color) = (1, 1, 1, 1)
_Ks ("Specular Color", Color) = (1, 1, 1, 1)
// 系数
_KdIntensity ("Kd Intensity", Range(0, 1)) = 0.5
_KsIntensity ("Ks Intensity", Range(0, 1)) = 0.5
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
Tags{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
float _Glossness;
float _KdIntensity;
float _KsIntensity;
float4 _Kd;
float4 _Ks;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};
v2f vert (a2v v)
{
v2f o;
// 裁切空间
o.pos = UnityObjectToClipPos(v.vertex);
// 世界坐标法向量
o.normal = UnityObjectToWorldNormal(v.normal);
// 世界坐标
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
float4 frag (v2f i) : SV_Target
{
float3 N = normalize(i.normal);
float3 L = normalize(UnityWorldSpaceLightDir(i.worldPos)).xyz;
float3 V = normalize(UnityWorldSpaceViewDir(i.worldPos)).xyz;
float3 R = normalize(2 * max(dot(N, L), 0) * N - L);
float3 H = normalize(L + V);
// 环境光
float3 ambient = _Kd * UNITY_LIGHTMODEL_AMBIENT.xyz;
//漫反射
float3 diffuse = _Kd * _LightColor0.rgb * _KdIntensity * max(dot(N, L), 0);
// 高光
float3 specular = _Ks * _LightColor0.rgb * _KsIntensity* pow(max(dot(H, N), 0), _Glossness);
return float4(ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
}
效果如下
本章节 完

京公网安备 11010502036488号