兰伯特光照模型是经验模型,主要用来模拟粗糙物体表面的光照现象,即漫反射。
漫反射特点
1:反射强度与观察者的角度没有关系
2:反射强度与光线的入射角度有关系
漫反射光照符合兰伯特定律(Lambert’s law):反射光线的强度与表面法线和光源方向之间夹角的余弦值成正比,夹角越大,受到的光线照射量越少,当夹角大于90度,光线照射物体背面,此时认为光照强度为0。


漫反射公式:漫反射 = 光源颜色 x 模型基础颜色 x(法线 · 光源方向),这里使用max函数防止结果为负值,另外可以乘以一个系数来控制最终结果。这里法线和光源方向点乘表示两者之间的夹角,夹角越大点乘值越小

漫反射,兰伯特逐顶点光照

Shader "MyCustom/Diffuse_Lambert_Vertex"
{Properties{//材质的漫反射颜色_Color("Base Color", color) = (1.0, 1.0, 1.0, 1.0)//漫反射系数_kD("kD", Range(0, 1)) = 1}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag// make fog work#pragma multi_compile_fog//引入Unity内置的一些变量#include "UnityCG.cginc"//UnityCG.cginc中定义了结构体appdata_base,appdata_tan,appdata_full用于顶点着色器输入//这里自定义appdata类型,只包含需要的数据struct appdata{float4 vertex : POSITION; //顶点位置float3 normal : NORMAL;   //法线};//顶点着色器输出struct v2f{//SV_POSITION是裁剪空间中的顶点坐标,它是DirectX 10中引入的系统数值语义,在大多数平台上,它和POSITION语义是等价的,//但在某些平台(例如PS4)上必须使用SV_POSITION来修饰顶点着色器的输出,否则无法让Shader正常工作//SV_POSITION一旦被作为顶点着色器的输出语义,那么顶点位置就被固定了,后续不能再被改变它的空间位置float4 vertex : SV_POSITION;float4 col : COLOR;};//为了使用Properties语义块中声明的属性,需要定义一个和该属性类型相匹配的变量//由于颜色属性的范围在0到1之间,因此我们可以使用fixed精度的变量来存储它float4 _Color;float _kD;//表示这个变量的初始值来自于外部的其他环境uniform float4 _LightColor0;v2f vert (appdata v){v2f o;//Unity内置 模型 * 世界 * 投影矩阵 UNITY_MATRIX_MVP,把顶点位置从模型空间转换到裁剪空间中o.vertex = UnityObjectToClipPos(v.vertex);//在计算法线和光线之间的点积时,只有两者处于同一坐标系下,它们的点积才有意义,//所以需要把顶点的法线从模型空间转到世界空间,unity_WorldToObject是4*4float3 worldNormal = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);//也可以这么写// float3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));//获取光源方向(们假设场景中只有一个光源且该光源的类型是平行光)float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);//当法线和光线之间夹角大于90时,光线是在照射物体的背面,此时光照强度为0float lambert = max(dot(worldNormal, worldLight), 0.0);//也可以使用saturate函数把参数截取到[0, 1]的范围内,防止负值// float lambert = saturate(dot(worldNormal, worldLight));float3 diffuse = _kD * lambert * _Color.rgb * _LightColor0.rgb;//环境光float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;float3 finalColor = diffuse + ambient;o.col = float4(finalColor, 1.0);return o;}fixed4 frag (v2f i) : SV_Target{return i.col;}ENDCG}}
}

漫反射,兰伯特逐像素光照

Shader "MyCustom/Diffuse_Lambert_Pixel"
{Properties{_Color("Base Color", color) = (1.0, 1.0, 1.0, 1.0)_kD("kD", Range(0, 1)) = 1}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag// make fog work#pragma multi_compile_fog#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 vertex : SV_POSITION;//顶点着色器中计算世界空间下法线,传递给片元着色器float3 worldNormal : TEXCOORD0;};float4 _Color;float _kD;uniform float4 _LightColor0;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));return o;}//将光照的计算转移到片元着色器中fixed4 frag (v2f i) : SV_Target{float3 worldNormal = i.worldNormal;float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);float lambert = max(dot(worldNormal, worldLight), 0.0);float3 diffuse = _kD * lambert * _Color.rgb * _LightColor0.rgb;float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;float3 finalColor = diffuse + ambient;return float4(finalColor, 1.0);}ENDCG}}
}

半兰伯特逐像素光照

Shader "MyCustom/HalfLambert"
{Properties{_Color ("Base Color", color) = (1.0, 1.0, 1.0, 1.0)_kD ("kD", Range(0, 1)) = 1}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag// make fog work#pragma multi_compile_fog#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 vertex : SV_POSITION;float3 worldNormal : TEXCOORD0;};float4 _Color;float _kD;uniform float4 _LightColor0;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));return o;}fixed4 frag (v2f i) : SV_Target{float3 worldNormal = i.worldNormal;float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);// 广义上的半兰伯特 half lambert = light * diffuse * (α* (n * l) + β)// half lambert = light * diffuse * (0.5 * (n * l) + 0.5)float halfLambert = 0.5 * dot(worldNormal, worldLight) + 0.5;float3 diffuse = _kD * halfLambert * _Color.rgb * _LightColor0.rgb;float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;float3 finalColor = diffuse + ambient;return float4(finalColor, 1.0);}ENDCG}}
}

实际对比


逐顶点光照:计算量较小,明暗过渡的边缘有锯齿,不够自然。而且,由于逐顶点光照会在渲染图元内部对顶点颜色进行插值,这会导致渲染图元内部的颜色总是暗于顶点处的最高颜色值,这在某些情况下会产生明显的棱角现象。
逐像素光照:计算量较大,光照效果更加平滑,有一个问题仍然存在。在光照无法到达的区域,模型的外观通常是全黑的,没有任何明暗变化,这会使模型的背光区域看起来就像一个平面一样,失去了模型细节表现。为此,有一种改善技术被提出来,这就是半兰伯特光照模型。
半兰伯特光照:为了解决兰伯特光照不够亮的问题。

参考《Unity Shader入门精要》

兰伯特(Lambert)光照模型总结相关推荐

  1. Lambert (兰伯特)光照模型

    Lambert (兰伯特)光照模型 是光源照射到物体表面后,向四面八方反射,产生的漫反射效果.这是一种理想的漫反射光照模型.如下图:这个是顶点函数处理后的该光照模型,因此看起来像素不够平滑. 漫反射 ...

  2. Shader学习第六篇:Lambert (兰伯特)光照模型

    漫反射的定义 漫反射是投射在粗糙表面上的光向各个方向反射的现象.当一束平行的入射光线射到粗糙的表面时,表面会把光线向着四面八方反射,所以入射线虽然互相平行,由于各点的法线方向不一致,造成反射光线向不同 ...

  3. 兰伯特(Lambert)模型

    漫反射,是投射在粗糙表面上的光向各个方向反射的现象.当一束平行的入射光线射到粗糙的表面时,表面会把光线向着四面八方反射,所以入射线虽然互相平行,由于各点的法线方向不一致,造成反射光线向不同的方向无规则 ...

  4. 兰伯特(Lambert)方程的求解算法1

    本文针对兰伯特方程给出具体的算法,并不打算给出详细的过程.各位读者可参照此算法及相应的代码进行编程计算. 介绍 见下图,仅考虑中心天体C的万有引力,飞行器从P1P_1P1​点飞行到P2P_2P2​点, ...

  5. 兰伯特(Lambert)方程的求解算法3

    在前2篇文章中,介绍了兰伯特方程的基本概念,并给出了无量纲飞行时间TTT的具体的算法,且给出了由时间TTT求解自变量xxx的具体算法.本章给出最终的算法:转移轨道两端点p1.p2p_1.p_2p1​. ...

  6. 兰伯特(Lambert)方程的求解算法2

    在前一文章中,介绍了兰伯特方程的基本概念,并给出了无量纲飞行时间TTT的具体的算法,本节给出上述逆过程,即由无量纲飞行时间TTT求解自变量xxx. 已知TTT求解自变量xxx采用函数求根方法,即求解下 ...

  7. 兰伯特光照模型(Lambert Lighting)和半兰伯特光照模型(Half-Lanbert)

    关于漫反射 光打到凹凸不平的平面上,光线会被反射到四面八方,被称为漫反射 关于这种模型,由于光线由于分散,所以进入人眼的光线强度和观察角度没有区别 在A点和B点接收到的光线强度是一样的 在漫反射下,光 ...

  8. Shader学习2——兰伯特

    本以为写个兰伯特很简单,但是仔细考虑了一下,不光要受场景中光源影响,还需要受环境光影响,然后发现单个pass通道只能实现单光源.因此前期我们都只考虑单平行光. 兰伯特:漫反射颜色 = 光源颜色 x 材 ...

  9. Shader学习3——半兰伯特

    半兰伯特其实就是把暗的地方提亮了一些,在数值上就是获取到的光源强度* 0.5 + 0.5,也就是原来是0的会变成0.5,原来是1的还是1. 半兰伯特:漫反射颜色 = 光源颜色 x 材质的漫反射颜色 x ...

最新文章

  1. poj3678详解(2-SAT)
  2. 工作中常用的linux命令梳理
  3. TCP/IP 协议簇 端口 三次握手 四次挥手 11种状态集
  4. 字符串扩展_JAVA
  5. feign如何使用?
  6. 梯度下降法、随机梯度下降法、批量梯度下降法及牛顿法、拟牛顿法、共轭梯度法
  7. 一款好看的html动态跳转页源码
  8. ruby koans:tdd方式学习ruby
  9. 工业基础类IFC—EXPRESS语言
  10. 人工智能算法:遗传算法
  11. IObit Uninstaller(卸载工具) v10.0.2.20
  12. 帮助用户连接网络打印机工具
  13. 经典机器学习模型:朴素贝叶斯分类
  14. 有些人二十几岁就提前退休了,凭什么?
  15. SDM(Supervised Descent Method)代码实现在Windows下的配置与使用
  16. c++ 判断回文,说实话,累赘
  17. Cadence Allegro通孔PAD制作图文教程及视频演示
  18. 【JavaEE】进入Web开发的世界-HTML
  19. 鞋为什么会臭?14个方法巧除鞋臭脚臭
  20. 微信7种支付应用场景

热门文章

  1. 如何使用万用表测量三级管的阻值
  2. 【NETGEAR网件】WNDR3700V4 或 WNDR4300 刷OpenWrt及恢复(刷回)
  3. 使用Phaser和HTML5特性检测移动设备旋转重力方向
  4. GeneXus学习(一)安装与介绍
  5. poj2069求最小外接球半径 模拟退火
  6. 如何拥有一颗平常心?(KK记)
  7. js-键盘事件案例-小人快跑
  8. minio分布式对象存储
  9. linux服务器删除cdn,有惊无险的一次后台删除操作!警告不要乱删除东西
  10. 打不开计算机 在任务栏里显示,电脑下方的任务栏不显示怎么办 电脑任务栏不显示解决方法【图文】...