UnityShader学习记录_兰伯特光照模型

1.漫反射

        漫反射光照是用于对于哪些物体表面散射光照进行建模的。

        兰伯特定律(Lambert law) 半兰伯特定律(Half Lambert)都是描述漫反射光照的经验模型。

兰伯特定律:

        cDiffuse = cLight  * mDiffuse * Max(0,n • l)

        cLight  是光源颜色 

        mDiffuse 是材质球是设置的漫反射颜射

        n 为 顶点或者片元法向量 ,l 为指向光源的单位矢量

在书写shader代码时,顶点着色器和片元着色器都可以实现兰伯特定律,顶点着色器写的代码执行效率高,片元着色器片效果会更光滑。

 在shader渲染时 片元的个数往往是顶点的几倍所以 顶点效率高,但却没有片元细致

逐顶点、逐片元效果图:

逐顶点代码如下:     

///
//简单漫反射
//
Shader "Unlit/BRM01"
{
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            struct v2f
            {
                fixed3 color : Color;
                float4 vertex : SV_POSITION;
            };

            fixed4 _Diffuse;
            sampler2D _MainTex;
            float4 _MainTex_ST;

            //顶点着色器
            v2f vert (appdata_base v)
            {
                v2f o;
                //物体坐标转裁剪空间坐标
                o.vertex = UnityObjectToClipPos(v.vertex);
               //物体法线转世界坐标法线
                float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                //世界左边光源方向
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                //环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                //漫反射公式
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal , worldLight));
                //最终颜色
                o.color = diffuse + ambient;
                return o;
            }
            
            //片元着色器
            fixed3 frag (v2f i) : SV_Target
            {
                return i.color;
            }
            ENDCG
        }
    }
}

逐片元代码如下:     

//
//简单片元漫反射模型
//
Shader "Unlit/BRM02"
{
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            
            struct v2f
            {
                float3 worldNormal : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            fixed4 _Diffuse;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            
            //顶点着色器
            v2f vert (appdata_base v)
            {
                v2f o;
                //物体坐标转裁剪空间坐标
                o.vertex = UnityObjectToClipPos(v.vertex);
               //物体法线转世界坐标法线
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            //片元着色器
            fixed3 frag (v2f i) : SV_Target
            {
                //环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                //世界左边光源方向
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                //漫反射
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0,dot(worldLight,i.worldNormal));
                //最终颜色
                fixed3 color = ambient + diffuse;
                return color;
            }
            ENDCG
        }
    }
}

半兰伯特定律:

        实现完兰伯特定律时我们会发现光照无法直接照射到的位置通常是全黑的,没有任何明暗变化,这会使模型的背光区看起来像一个平面,失去了模型细节的表现。为此半兰伯特光照模型就出现了。

 公式:     

cDiffuse = cLight  * mDiffuse * 0.5 *(n • l) + 0.5

        cLight  是光源颜色 

        mDiffuse 是材质球是设置的漫反射颜射

        n 为 顶点或者片元法向量 ,l 为指向光源的单位矢量

        因为颜色的范围在[0,1] 、n • l 的范围在[-1,1] 。n • l 小于0的部分会被舍弃 ,所以我们将法向量和光源方向矢量的点积 映射到 [0,1]的范围内。这样背面也可以有明暗变化了。

效果图:

 逐片元半兰伯特模型代码:

//
//简单片元漫反射模型
//半兰伯特模型
//
Shader "Unlit/BRM03"
{
     Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            
            struct v2f
            {
                float3 worldNormal : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            fixed4 _Diffuse;
            sampler2D _MainTex;
            float4 _MainTex_ST;

            //顶点着色器
            v2f vert (appdata_base v)
            {
                v2f o;
                //物体坐标转裁剪空间坐标
                o.vertex = UnityObjectToClipPos(v.vertex);
               //物体法线转世界坐标法线
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            //片元着色器
            fixed3 frag (v2f i) : SV_Target
            {
                //环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                //世界左边光源方向
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                //漫反射 点积为负为背光面
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldLight,i.worldNormal) * 0.5 + 0.5);
                //最终颜色
                fixed3 color = ambient + diffuse;
                return color;
            }
            ENDCG
        }
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值