一、光照模型
定义:光线与空间中物体表面之间的交互模型
分类:1.基于物理理论的光照模型(PBR)2.经验光照模型
意义:现实光照对于电脑来说过于复杂,影响因素也过多。光照模型通过对现实中的光照情况进行总结和简化,得出一套用于计算机计算光照的方案
历史:
二、局部光照模型
定义:只考虑直接光照的光线
1.漫反射
光线均匀反射,通过吸收和散射改变颜色和方向
符合Lambert理论:
DiffCol = LightCol * BaseCol * nDotl
2.高光反射
理论:
反光只会在圆锥的范围内被观察到,圆锥体顶角的大小表示着反射的集中程度
SpecCol = LightCol * mSpec * (dot(v , r) ^ mGloss)
r= 1 - 2 * ndotl * n
mSpec即反射光强度,mGloss即SpecPow
mGloss(SpecPow)越大,镜面反射越集中
3.环境光
AmbientCol = AO * BaseCol
4.自发光
三、经典光照模型
1.Lambert
DiffCol
2.Phong
DiffCol + SpecCol + AOCol + EmitCol
3.Blinn-Phong
将镜面反射中的vdotr改为hdotn,h为半角向量(光照方向和视线方向的角平分线)
开销相对Phong小
反光度低时,大部分区域都能发射反射光并被人眼接收到,而当lDir和vDir在nDir的同一侧时,Phong判定为暗,产生断层
4.Gourand
以顶点为单位来计算光照然后插值得到像素亮度
优点:很好表现物体光滑性 缺点:镜面高光不集中
好丑。。。
5.Flat
一个面片只有一个颜色,不平滑
多用于low poly风格
DLC:先行版
UnpackNormal:
(0,1)变换到(-1,1)
Cubemap:
给反射光安排个贴图
lod越大,看起来越粗糙(经常用roughness控制lod)
IBL:基于图像的光照,以贴图为光源加入到光照计算中
TRICKS:
ndotl决定是用AO来乘还是LightCol来乘
金属只有镜面反射
一个lerp来决定法线强度(是用模型本身的法线还是法线贴图)
作业:
1.能量守恒理念在基础光照中的作用
能量守恒:E(入射光)>E(出射光)(除非材质自带自发光)
光照照射到表面上,分为折射和反射,折射部分进入物体内部后会被吸收或者散射(产生漫反射)。反射光和折射光互斥,故入射光减去反射光等于进入材质内部的折射光
PBR简化折射光,将折射光是做完全吸收而不散开。金属材质吸收所有折射光,因此只有镜面反射而无折射光的漫反射
随着粗糙度的上升,光照逐渐变散,反射到的区域面积增加,但镜面反射的亮度会减小。(如果亮度恒定,那么反射面积增加的时候,反射出的能量会增加,最终超过入射能量)
2.光照模型coding
先上效果
Blinn-Phong
Phong
CubeMap
然后上代码,从庄老师的11课的OldschoolPro起手改的
Shader "L10/OldschoolPro" { //路径
Properties {
[Header(Texture)]
_MainTex ("基础颜色+透明遮罩", 2D) ="gray"{}
_NormTex ("法线贴图", 2D) ="white"{}
_AOTex ("AO", 2D) ="white"{}
_CubeMap ("CubeMap", CUBE) ="_Skybox"{}
_LightCol ("LightColor", COLOR) =(1.0, 1.0, 1.0, 1.0)
_NormInt ("Normal Int", range(0,1)) =1
_SpecInt ("SpecInt", range(0,10)) =1
_Gloss ("Gloss", range(1,60)) =30 //一定程度上反应金属度
_EnvInt ("EnvInt", range(0, 1)) =1
[Toggle] _specswitch ("Use Blinn-Phong", float) =0
} //面板参数
SubShader {
Tags { //格式{
"RenderType"="Opaque"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0 //}格式
uniform sampler2D _MainTex;
uniform sampler2D _NormTex;
uniform sampler2D _AOTex;
uniform samplerCUBE _CubeMap;
uniform float4 _LightCol;
uniform float _NormInt;
uniform float _SpecInt;
uniform float _Gloss;
uniform float _EnvInt;
uniform float _specswitch;
struct VertexInput {
float4 vertex : POSITION;
float2 uv0 : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent: TANGENT;
}; //输入结构
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0;
float3 posWS : TEXCOORD1;
float3 nDirWS : TEXCOORD2;
float3 tDirWS : TEXCOORD3;
float3 bDirWS : TEXCOORD4;
LIGHTING_COORDS(5,6)
}; //输出结构
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos( v.vertex );
o.uv0 = v.uv0;
o.posWS = mul(unity_ObjectToWorld, v.vertex);
o.nDirWS= UnityObjectToWorldNormal(v.normal);
o.tDirWS= normalize( mul( unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 ) ).xyz );
o.bDirWS= normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w);
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
} //vertex shader
float4 frag(VertexOutput i) : COLOR {
//向量准备
float3 nDirTS = UnpackNormal(tex2D(_NormTex, i.uv0));
float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);
float3 nDirWS = normalize(mul(nDirTS, TBN));
float3 nDirMWS = i.nDirWS;
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
float3 finalNorm= lerp(nDirMWS, nDirWS, _NormInt);
float3 vrDirWS = reflect(-vDirWS, finalNorm);
float3 lDirWS = _WorldSpaceLightPos0.xyz;
float3 lrDirWS = reflect(-lDirWS, finalNorm);
float3 hDir = normalize(vDirWS+lDirWS);
float3 ndoth = saturate(dot(finalNorm, hDir));
//中间量准备
float ndotl = max(0, dot(finalNorm,lDirWS));
float vdotr = max(0, dot(vDirWS,lrDirWS));
float vdotn = max(0, dot(vDirWS,finalNorm));
//纹理采样
float3 var_MainTex = tex2D(_MainTex,i.uv0);
float3 var_NormTex = tex2D(_NormTex,i.uv0);
float var_AO = tex2D(_AOTex,i.uv0).r;
//光照模型
//LAMBERT
float3 dirDiff = lerp(var_MainTex*var_AO, var_MainTex*_LightCol, ndotl);
//PHONG
float3 PCol = lerp(dirDiff*pow(vdotr, _Gloss), pow(vdotr, _Gloss), _Gloss/60)*_Gloss/60*_SpecInt*_LightCol;
//Blinn-Phong
float3 BPCol = lerp(dirDiff*pow(ndoth, _Gloss), pow(ndoth, _Gloss), _Gloss/60)*_Gloss/60*_SpecInt*_LightCol;
//Env
float3 EnvRef = texCUBElod(_CubeMap,float4(vrDirWS,(60-_Gloss)/60*8))*_EnvInt;
//MIX
float3 specCol = lerp(PCol,BPCol,_specswitch);
half3 finalCol = dirDiff+specCol+EnvRef;
//返回值
return float4(EnvRef,0.0);
} //fragment shader
ENDCG
}
}
FallBack "Diffuse"
}