与Unity光照相关的Shader知识
渲染路径就是为进行灯光计算的设计的渲染方式。
一、光源的类型
如何创建灯光?
在对象面板右键 Light - XX
二、渲染路径
什么是渲染路径?
渲染路径就是为进行灯光计算的设计的渲染方式
渲染路径有哪些?
1.顶点照明渲染路径 (Vertex Lit Rendering Pass)
2.延迟渲染路径 (Deferred Rendering Pass)
3.前向渲染路径(Forward Rendering Pass)
1. 顶点照明渲染路径
顶点照明渲染路径通常在一个通道中渲染物体,所有光照的计算都是在物体的顶点上进行的,也叫(逐顶点)
优点:性能最优,支持的硬件最广,所有的光照计算都是在顶点上执行
缺点:当顶点数较少时,效果较差
不支持像素级别的效果,例如阴影,高质量的高光效果等
2. 延迟渲染路径
其中 RT 为各种贴图 例如颜色贴图,法线贴图,粗糙度贴图,自发光贴图等等
优点:每一个光源都是逐像素级别的效果,并且可以正确的计算法线贴图以及阴影
影响一个物体的光源数量是没有限制的
缺点: 1.不支持半透明效果
2.不支持抗锯齿
3.内存开销较大
4.不支持正交相机
3. 前向渲染路径
前向渲染路径中会将光源分为以下3种处理方式:
- 逐像素处理
- 逐顶点处理
- 球谐函数(SH)处理
前向渲染路径包括两种 ForwardBase 和 ForwardAdd
ForwardBase渲染路径:仅能用于 一个【逐像素】的【平行灯】和所有的 【逐顶点】 与 【球谐】
ForwardAdd渲染路径: 用于【其他所有】的【逐像素灯】
在【Edit】-【Project Settings】 中可设置Unity程序中默认能承载的逐像素灯的数量
当设置场景中默认能承载的逐像素灯的数量为0时:
- 平行灯的渲染情况:依旧按照逐像素处理的光照渲染方式进行
- 其他种灯的渲染情况:按照ForwardBase中的逐顶点处理的光照渲染方式
当设置场景中默认能承载的逐像素灯的数量>0时:
- 平行灯的渲染情况:第一个平行光按照ForwardBase中的逐像素处理进行光照渲染,其他的 平行灯按照ForwardAdd中的逐像素处理方式进行光照渲染
- 其他类型的灯渲染情况:在满足默认能承载的逐像素灯的数量下,其他类型的灯光按照 ForwardAdd中的逐像素处理进行光照渲染,否则按ForwardBase 中的逐顶点处理进行光照渲染
当将一个光源设置为 Not Important (不重要),则该光源会按照逐顶点处理或者SH的渲染方式进行光照计算
所有逐顶点处理的光照渲染都是在一个Pass中完成
而逐像素处理的光照渲染单独在一个Pass中,且每一个逐像素灯都为单独的一个Pass
三、那么在Unity-Shader中如何选择不同的渲染路径呢?
在 SubShader 中写 Tags{"LightMode"="XXX"} 的语句
四、光照模型
一、Lambert光照模型
Diffuse=Ambient + Kd * LightColor * dot(N,L) //计算光照的公式
1. Diffuse:最终表现在物体上的漫反射光强
2. Ambient:环境光强度
环境光面板的位置:在【Window】-【Rendering】-【Lighting】中打开
环境光有三种类型:
- SkyBox 类型
- Gradient 类型
- Color 类型
unity_AmbientSky 代表环境光(Gradient)中的 Sky Color
unity_AmbientEquator 代表环境光(Gradient)中的 Equator Color
unity_AmbientGround 代表环境光(Gradient)中的 Ground Color
UNITY_LIGHTMODEL_AMBIENT 代表环境光(Color)中的 Sky color
3. Kd:物体材质对光照的反射系数
在Shader中的属性面板定义一个可调节大小的参数属性来赋值Kd
因为之后Kd要进行相乘操作,可将其赋初值为1
4. LightColor:灯光的颜色与光强
_LightColor0 可对应程序灯光的【颜色】和【光强】属性
_LightColor0变量存储在#include “Lighting.cginc”的内置文件包中,所以要使用_LightColor0必须先声明#include “Lighting.cginc”
5. dot(N,L):【法向量】和【顶点到光源向量】之间的点乘操作
有关的数学运算:
向量的点乘:a*b=|a|*|b|*cos∠ (结果为一个数值)
向量的叉乘:|a×b|=|a|*|b|*sin∠ (叉乘的结果为向量)
在shader中需将法线传入到结构体中 并在顶点着色器中将本地坐标系下的法线向量转化为世界坐标系下的法线向量
struct appdata
{
float4 vertex : POSITION;
half3 normal:NORMAL; //将法线向量传入Shader中
};
struct v2f
{
float4 vertex : SV_POSITION;
half3 worldNormal:NORMAL; //世界空间下的法线向量
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
//将本地空间下的法线向量转化为世界空间下的法线向量
o.worldNormal=UnityObjectToWorldNormal(v.normal);
return o;
}
顶点到灯光位置的向量表示 :
fixed3 L=_WorldSpaceLightPos0; //顶点到灯光的向量
_WorldSpaceLightPos0为灯光的位置信息
最终的Shader:
Shader "unity/Light Model"
{
Properties
{
_AmbientIntensity("Ambient Intensity",float)=1 //漫反射系数属性 可赋值给Kd
}
SubShader
{
Tags{"LightMode"="ForWardBase"} //定义前向渲染的基础Pass
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc" //获取灯光包
half _AmbientIntensity;
struct appdata
{
float4 vertex : POSITION;
half3 normal:NORMAL; //将法线向量传入Shader中
};
struct v2f
{
float4 vertex : SV_POSITION;
half3 worldNormal:NORMAL; //世界空间下的法线向量
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.worldNormal=UnityObjectToWorldNormal(v.normal); //将本地空间下的法线向量转化为世界空间下的法线向量
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// _LightColor0 变量存储在 "Lighting.cginc" 中,所以在使用_LightColor0前需先引用 #include "Lighting.cginc"
//变量_LightColor0 中不仅存储有灯光的颜色RGB 还存放着灯光的强度 所以场景中的灯光强度也对Shader对象起作用
// _LighgtColor=_LightColor.rgb*_LigthColor.a (a中存储着Intensity 灯光强度)
// return _LightColor0; //平行光的颜色与光强
// return unity_AmbientSky; //返回值为环境光Gradient中的 Sky Color以及Color中的 Ambient Color
//Diffuse = Ambient + Kd * LightColor * dot(N,L) // Lambert光照模型
fixed4 Ambient=unity_AmbientSky;
half Kd= _AmbientIntensity;
fixed4 LightColor=_LightColor0;
fixed3 N=normalize(i.worldNormal); //将法线向量归一化为单位向量
fixed3 L=_WorldSpaceLightPos0; //顶点到灯光的向量 _WorldSpaceLightPos0为灯光的位置信息
fixed4 Diffuse=Ambient + Kd * LightColor * dot(N,L); //dot(N,L)为点乘运算
return Diffuse;
}
ENDCG
}
}
}
更多推荐
所有评论(0)