- 接上篇笔记中的逐顶点光照继续整理
- 逐顶点的计算量发生在光与模型的顶点之间,
- 逐像素(逐片元)最终的颜色其实来自像素周围几个顶点插值结果
-顶点函数:
将上一篇中 vert(a2v f)函数中除 顶点位置 与 法线计算 之外的光方向、归一化的法线方向及漫反射光照以及最后的漫反射与环境光叠加全部移动到逐像素(逐片元)frag(v2f f)里来计算,如下:
//将光照计算过程移出顶点函数,放在片元函数中
v2f vert(a2v v) {
v2f f;
//顶点位置从模型空间转换到裁减空间也叫投影空间
f.position = mul(UNITY_MATRIX_MVP,v.vertex);
//法线计算
f.WorldNormalDir = mul(v.normal, (float3x3)_World2Object);
return f;
}
-片元函数:
//将计算过程放在片元中:逐像素光照
fixed4 frag(v2f f):SV_Target {
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
//光方向(_WorldSpaceLightPos0.xyz 世界空间中灯光位置就等于灯光方向)
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//法线方向(顶点法线与3x3矩阵相乘后归一化)
fixed3 normalDir = normalize(f.WorldNormalDir);
//漫反射光照-颜色的融合 也称:兰伯特光照计算公式
fixed3 diffuse = _LightColor0.rgb * max(dot(lightDir,normalDir),0) * _DiffuseColor.rgb;
//颜色的叠加 相加(亮度变化)
fixed3 tempcolor = diffuse + ambient;
return fixed4(tempcolor,1);
}
-截图说明了逐像素与逐片元在渲染表现上的差异
-关于兰伯特光照缺点:
兰伯特光照-背光面是全黑的光照效果,在卡通或者写实类游戏中,一般拒绝全黑的死角存在的
故在半条命中开发商将兰伯特光照基础改造后,就有了半兰伯特光照(将结果区间从-1到1映射为0-1之间,保证光影结果的可观赏性)
兰伯特光照 = 直射光颜色 * max(0,cos夹角(光与法线的夹角));
半兰伯特光照 = 直射光颜色 * (cos夹角(光与法线的夹角) * 0.5 + 0.5);
将上述理论应用到代码结果为:
//半兰伯特光照
float helflambert = dot(lightDir, normalDir) * 0.5 + 0.5;
//漫反射光照
fixed3 diffuse = _LightColor0.rgb * helflambert * _DiffuseColor.rgb;
背面的光照效果:
完整代码如下:
Shader "Davia/05_Diffuse Fragment"{
Properties{
_DiffuseColor("Diffuse Color",color) = (1,1,1,1)
}
SubShader
{
Pass
{
Tags{"Lightmode" = "ForwardBase"}
CGPROGRAM
#include"Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _DiffuseColor;
//application to vertex
struct a2v{
float4 vertex:POSITION;
fixed3 normal:NORMAL;
};
//vertex to fragment
struct v2f{
float4 position:SV_POSITION;
fixed3 WorldNormalDir:COLOR;
};
//将计算过程放在顶点中:逐顶点光照
v2f vert(a2v v) {
v2f f;
//顶点位置从模型空间转换到裁减空间也叫投影空间
f.position = mul(UNITY_MATRIX_MVP,v.vertex);
//法线计算
f.WorldNormalDir = mul(v.normal, (float3x3)_World2Object);
return f;
}
//将计算过程放在片元中:逐像素光照
fixed4 frag(v2f f):SV_Target
{
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
//光方向(_WorldSpaceLightPos0.xyz 世界空间中灯光位置就等于灯光方向)
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//法线方向(顶点法线与3x3矩阵相乘后归一化)
fixed3 normalDir = normalize(f.WorldNormalDir);
//漫反射光照-颜色的融合 相乘(颜色变化)
fixed3 diffuse = _LightColor0.rgb * max(dot(lightDir,normalDir),0) * _DiffuseColor.rgb;
//颜色的叠加 相加(亮度变化)
fixed3 tempcolor = diffuse + ambient;
return fixed4(tempcolor,1);
}
ENDCG
}
}
Fallback"Unlit/Diffuse"
}
这篇博客主要介绍了如何在Unity的ShaderLab中实现逐像素的漫反射和环境光计算。作者通过调整顶点函数,将光方向、法线、漫反射光照和环境光的叠加计算移到片元函数中进行,详细阐述了这一过程。文中还附带了逐像素光照与逐顶点光照效果的对比截图,揭示了兰伯特光照模型在背面光照处理上的不足。最后,提供了完整的代码示例。
&spm=1001.2101.3001.5002&articleId=76077641&d=1&t=3&u=acb20fc2aae34cf48706e64b7836679a)
674

被折叠的 条评论
为什么被折叠?



