• 漫反射实现 - UnityShader


    漫反射分为两种实现

    • 逐顶点漫反射(主要依靠顶点着色器,计算顶点的光照)
    • 逐片元漫反射(主要依靠片元着色器,计算片元的光照)

    使用的公式是兰伯特定律
    c d i f f u s e = ( c l i g h t ⋅ m d i f f u s e ) cos ⁡ θ (1) c_{diffuse} = (c_{light} \cdot m_{diffuse})\cos{\theta}\tag{1} cdiffuse=(clightmdiffuse)cosθ(1)
    c o s θ = n ^ ⋅ l ^ (2) cos{\theta} = \widehat{n} \cdot \widehat{l}\tag{2} cosθ=n l (2)

    在兰伯特的基础上增加亮光(添加两个偏移)
    c d i f f u s e = ( c l i g h t ⋅ m d i f f u s e ) ( n ^ ⋅ l ^ ∗ 0.5 + 0.5 ) (3) c_{diffuse} = (c_{light} \cdot m_{diffuse})( \widehat{n} \cdot \widehat{l} * 0.5 + 0.5)\tag{3} cdiffuse=(clightmdiffuse)(n l 0.5+0.5)(3)

    c l i g h t c_{light} clight 是光线的颜色, m d i f f u s e m_{diffuse} mdiffuse 是材质的颜色, c o s θ cos{\theta} cosθ是指法线与光线方向的角度

    逐顶点漫反射

    Shader "Lit/DiffuseLitShader1"
    {
        Properties
        {
            _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
        }
        SubShader
        {
            Pass
            {
                Tags { "LightMode" = "ForwardBase" }
                
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
    
                #include 
                #include 
                #include 
    
                struct a2v
                {
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                };
    
                struct v2f
                {
                    float4 pos : SV_POSITION;
                    fixed3 color : COLOR0;
                };
    
                fixed4 _Diffuse;
    
                //逐顶点漫反射
                v2f vert(a2v v)
                {
                    v2f o;
                    //设置裁剪空间
                    o.pos = UnityObjectToClipPos(v.vertex.xyz);
                    
                    //得到环境光
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
    
                    //从物体坐标的法向量变换到全局坐标的法向量
                    float3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                    
                    //光照方向
                    fixed3 litDir = normalize(_WorldSpaceLightPos0.xyz);
                    
                    //兰伯特定律 c = (c * m) max(0, dot(n.normalize, l.normalize)) = (c * m) * cos
                    //fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, litDir));
    
                    //半兰伯特定理 c = (c * m)(0.5 * cos + 0.5), 可实现暗部增强亮光
                    fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldNormal, litDir) * 0.5 + 0.5);
                    
    
                    o.color = ambient + diffuse;
    
                    return o;
                }
    
                fixed4 frag(v2f i) : SV_Target
                {
                    return fixed4(i.color, 1.0);
                }
                ENDCG
            }
        }
        
        FallBack "Diffuse"
    }
    
    
    • 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
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    逐片元漫反射

    Shader "Lit/DiffuseLitShader2"
    {
        Properties
        {
            _Diffuse("Diffuse", Color) = (1, 1, 1, 1)
        }
        SubShader
        {
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
    
                #include 
                #include 
                #include 
    
                struct a2v
                {
                    float4 pos : POSITION;
                    float3 normal : NORMAL;
                };
    
                struct v2f
                {
                    float4 pos : SV_POSITION;
                    float4 worldNormal : TEXCOORD0;
                };
    
                fixed4 _Diffuse;
    
                v2f vert(a2v v)
                {
                    v2f o;
                    
                    //得到裁剪空间
                    o.pos = UnityObjectToClipPos(v.pos.xyz);
    
                    //获得世界空间的法向量,并保存在 uv 中
                    o.worldNormal = float4(UnityObjectToWorldNormal(v.normal.xyz), 1.0);
    
                    return o;
                }
    
                fixed4 frag(v2f i) : SV_Target
                {
                    //得到 ambient
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
    
                    //gl 的 方向
                    float3 litDir = normalize(_WorldSpaceLightPos0.xyz);
    
                    //使用 兰伯特定律
                    //fixed3 diffuse = _LightColor0.rgb * _Diffuse * saturate(dot(i.worldNormal.xyz, litDir));
    
                    //使用 半兰伯特定律
                    fixed3 diffuse = _LightColor0.rgb * _Diffuse * (dot(i.worldNormal.xyz, litDir) * 0.5 + 0.5);
    
                    return fixed4(diffuse + ambient, 1.0);
                }
                ENDCG
            }
        }
        
        FallBack "Diffuse"
    }
    
    
    • 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
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    来源为 Unity Shader 入门精要这本书 - 漫反射光照的实现

  • 相关阅读:
    JavaParser的快速介绍
    【深度学习-第4篇】使用MATLAB快速实现CNN多变量回归预测
    DFT Compiler极简示例1
    记一次 .NET某管理局检测系统 内存暴涨分析
    python之判断是否是目录或文件
    备份系统运行数据采集及分析方法
    Java操作文件Path 和 Paths 及Files类介绍
    canvas 基础 和 动图案例
    ElasticSearch(六)【分词器】
    基于SkyEye运行Qt:著名应用程序开发框架
  • 原文地址:https://blog.csdn.net/m0_52361859/article/details/126921827