• Lambert (兰伯特)光照模型


    漫反射的定义

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

    Lambert定律

    漫反射光的强度近似地服从于Lambert定律,即漫反射光的光强与表面法线和光源方向之间的夹角的余弦成正比。
    在这里插入图片描述

    原理公式:diffuse = I*cosθ;

    diffuse:反射光线的的光强;

    I:入射光线的光强,方向如上图所示;

    cosθ:光源方向和该顶点法线的余弦,光源方向 · 法线方向,cosθ = dot(L,N);

    Unity中当颜色值小0时会按0处理,所以我们最后的数学表达式为:diffuse = I*max(0,dot(L,N));

    在Unity Shader

    Shader "My/03_1 shader"{
           Properties{
            _Diffuse("Diffuse",Color) = (1,1,1,1)
            
            }
            SubShader{
                Pass{
                    CGPROGRAM
                    #include "Lighting.cginc"//引入灯光库
                    #pragma vertex vert
                    #pragma fragment frag
                             fixed4 _Diffuse;
                    //application to vertex
                    struct a2v
                    {
                        float4 vertex:POSITION;
                        float3 normal:NORMAL;
                    };
    
                    struct v2f
                    {
                        float4 position:SV_POSITION;
                        float3 color:COLOR;
                    };
                    
                    v2f vert(a2v v){
                        v2f f;
                        f.position = UnityObjectToClipPos(v.vertex);//顶点转为裁剪空间
                        fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//环境光
                        fixed3 light_dir = normalize(_WorldSpaceLightPos0.xyz);//归一化光源的方向
                        fixed3 normal_dir = normalize(mul(v.normal,(float3x3)unity_WorldToObject));//先把法线方向转为世界空间,归一化法线方向
                        //兰伯特光照模型,直射光颜色*max(0,cosƟ(光和法线的夹角)),cosƟ = 光源的方向(向量)点乘法线方向
                        fixed3 diffuse = _LightColor0.rgb*max(0,dot(light_dir,normal_dir))*_Diffuse.xyz;//点成求cos,然后灯光颜色矩阵相乘获取漫反射光
                        f.color = diffuse+ambient;
                        return f;
                    }
    
                    fixed4 frag(v2f f):SV_Target{
                        return fixed4(f.color,1);
                    }
                    ENDCG
                    }
            }
        
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    半兰伯特光照模型

    把上面的效果应用到Unity中,可以看出不被光照射的背面是比较暗的,此时我们可以优化兰伯特光照模型,有人提出了半兰伯特光照模型。
    由上面的公式diffuse = I*max(0,dot(N,L)),可知dot(N,L)的范围为-1~1,如果我们可以把范围调整为0 ~1,那么模型看起来会更亮些,我们优化下让 dot(L,N)*0.5+0.5,这样范围就改为了0 ~1。
    最后的公式为:
    diffuse = I*max(0,dot(N,L)*0.5+0.5)

    半兰伯特Shader程序

    Shader "My/05 shader"{
            SubShader{
                Pass{
                    CGPROGRAM
                    #include "Lighting.cginc"//引入灯光库
                    #pragma vertex vert
                    #pragma fragment frag
                    //application to vertex
                    struct a2v
                    {
                        float4 vertex:POSITION;
                        float3 normal:NORMAL;
                    };
    
                    struct v2f
                    {
                        float4 position:SV_POSITION;
                        float3 color:COLOR;
                    };
                    
                    v2f vert(a2v v){
                        v2f f;
                        f.position = UnityObjectToClipPos(v.vertex);//顶点转为裁剪空间
                        fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//环境光
                        fixed3 light_dir = normalize(_WorldSpaceLightPos0.xyz);//归一化灯光方向
                        fixed3 normal_dir = normalize(mul(v.normal,(float3x3)unity_WorldToObject));//先把法线方向转为世界空间,归一化法线方向
                        //半兰伯特光照模型
                        fixed3 diffuse = _LightColor0.rgb*max(0,(dot(light_dir,normal_dir)*0.5+0.5));//点成求cos,然后灯光颜色矩阵相乘获取漫反射光
                        f.color = diffuse+ambient;
                        return f;
                    }
    
                    fixed4 frag(v2f f):SV_Target{
                        return fixed4(f.color,1);
                    }
                    ENDCG
                    }
            }
        
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    从相同的视角来观察两个模型,效果对比如下:
    在这里插入图片描述

  • 相关阅读:
    几种回调的对比
    《Android Studio开发实战 从零基础到App上线(第3版)》出版后记
    查询性能提升3倍!Apache Hudi 查询优化了解下?
    0数据结构-结构体struct与typedef
    【送面试题】构建高可用的秒杀系统:应对Redis集群崩溃的终极指南
    防火墙实验1
    当后端给我返回了302状态码
    Ubuntu22.04安装Mongodb7.0
    leetcode路飞吃桃,递归做法
    react路由传参3种方式
  • 原文地址:https://blog.csdn.net/u014196765/article/details/128100371