标准光照模型

标准光照明模型

它的基本方法是,把进入到摄像机的光分为四部分:

  • 自发光(emissive)
  • 高光反射(specular)
  • 漫反射(diffuse)
  • 环境光(ambient)

本文使用Unity Shader实现了兰伯特模型(Lambert)、半-兰伯特模型(Half-Lambert)、Phong模型、Blinn-Phong模型。

效果图

	从左至右依次是:兰伯特模型、半兰伯特模型、Phong模型、Blinn-Phong模型。

效果图

代码分享(附详细注解)

Lambert模型:

v2f vert(a2v v) {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vert);//将顶点方向矢量从模型空间转换到裁剪空间
    o.worldNormal = UnityObjectToWorldNormal(v.normal);//世界空间下的法向量
    o.worldPos = mul(unity_WorldToObject, v.vert).xyz;
    return o;
}
fixed4 frag(v2f f) :SV_Target{
    //Lambert 光照模型公式: 
    // 最终颜色 = 直射光颜色 * 漫反射颜色 * max(0, dot(光源方向, 法线方向))
    //归一化:颜色通道范围在0-1之间,归一化之后的坐标计算才不会超出范围
    fixed3 worldNormal = normalize(f.worldNormal);
    //模型空间中的顶点坐标 --> 世界空间中从这个点到光源的方向
    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(f.worldPos));
    //把光照计算放在片元函数中,计算次数更多,图像会更平滑
    //计算环境光
    fixed ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
    //计算漫反射
    fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldLightDir, worldNormal));
    //fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldLightDir, worldNormal) *0.5+0.5);
    return fixed4(diffuse+ambient, 1.0);
}      

Half-Lambert模型(与Lambert模型不同之处):

// 最终颜色 = 直射光颜色 * 漫反射颜色 *  (dot(光源方向, 法线方向)*0.5+0.5)
   fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldLightDir, f.worldnormal) * 0.5 + 0.5);

Phong模型:

fixed4 frag(v2f f) :SV_Target{
    //ambient
    fixed ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
    //light direction
    fixed3 WorlLightDir= normalize(UnityWorldSpaceLightDir(f.worldpos));
    fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(WorlLightDir, f.WorldNormal)*0.5+0.5);
    //Eye direction
    fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(f.worldpos));     // 计算视角方向
    fixed3 reflectDir = normalize(reflect(-WorlLightDir, f.WorldNormal));     // 计算反射方向
    fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, worldViewDir)), _Glossiness);
    return fixed4(diffuse + specular+ambient, 1.0);
}

Blinn-Phong模型:

float4 frag(v2f f) :SV_TARGET{
    //diffuse:Half-Lambert
    float3 WorlLightDir = normalize(UnityWorldSpaceLightDir(f.worldpos));
    float3 diffuse = _LightColor0.rgb * _diffuse * (dot(WorlLightDir,f.worldnormal) * 0.5 + 0.5);
    //specular:Blinn
    float3 worldViewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldpos.xyz);        // 计算视角方向
    float3 halfDir = normalize(worldViewDir + WorlLightDir);                   // 计算Blinn模型中引入的新矢量
    float3 specular = _LightColor0.rgb*_Specular* pow(saturate(dot(f.worldnormal, halfDir)), _Gloss);
    return float4(diffuse + specular, 1.0);
}

一些问题

关于光照明模型

可以从上面的效果图中看出,光照明模型并不符合真实世界的光照现象。但是由于其易用性、计算速度、较可以的效果,现在仍在广泛使用。

逐像素还是逐顶点

  • 计算速度:逐顶点光照的计算量远小于逐像素光照的计算量。
  • 效果:逐像素光照能得到更高质量的光照效果,无论是漫反射还是高光反射都更加平滑。当光照明模型中有非线性的计算时,逐顶点光照就会出问题。逐顶点得到的高光效果有比较大的问题,从高光中心点向外扩散显得很不平滑。另外,逐顶点光照需要模型有较多较密的顶点才行。如果模型的顶点很少,光照结果可能就完全不对了。

希望这篇文章对大家有所帮助。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值