TA之路——Shader学习04(光照模型之漫反射(Lambert))

兰伯特光照模型是一种理想的漫反射光照模型,又分为全兰伯特光照模型和半兰伯特光照模型,以下以全兰伯特光照模型举例:

逐顶点光照:

Shader "MyShader/Diffuse_Vertex"{

Properties{

_Diffuse("Diffuse Color",Color)=(1,1,1,1)//定义颜色属性

}

SubShader{
    Pass{
    Tags{"LightMode"="ForwardBase"}  //只有定义了正确的LightMode才能得到一些Unity的内置光照变量
        CGPROGRAM
        #include "Lighting.cginc"//类似C#中的命名空间,引用之后才能使用unity内置的一些变量
        #pragma vertex vert
        #pragma fragment frag

        fixed4 _Diffuse;//小细节:使用属性之前必须在Pass块中再次重复定义

        struct av{
            float4 ps:POSITION;//告诉Unity把模型空间下的顶点坐标填充给ps
            float3 nm:NORMAL;//告诉Unity把模型空间下的法线方向填充给nm

        };

        struct vf{
            float4 position:SV_POSITION;
            fixed3 cl : COLOR;
        };

       
        vf vert(av v){
            vf f;
            f.position=UnityObjectToClipPos(v.ps);

            fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;//获取环境光的颜色并将其填充给ambient

            fixed3 normalDir=normalize(mul(v.nm,(float3x3)unity_WorldToObject));//把法线方向从模型空间转换到世界空间并将其单位化

            fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);//lightDir接收被单位化之后的直射光坐标

            fixed3 diffused=_LightColor0.rgb*max(0,dot(normalDir,lightDir))*_Diffuse.rgb;  //漫反射=直射光颜色*max(0,光和法线的夹角)*需要融合的颜色      注意:融合颜色直接在公式中相乘

            f.cl=diffused+ambient;//注意:叠加颜色直接相加

            return f ;
        }

        fixed4 frag(vf f):SV_Target{
            return fixed4(f.cl,1);
        }

        ENDCG

        }
    }

Fallback "VertexLit"
}

逐像素光照:

Shader "MyShader/Diffuse_Fragment"{

    Properties{

    _Diffuse("Diffuse Color",Color)=(1,0,1,1)

    }

    SubShader{

        Pass{
        Tags{"LightMode"="ForwardBase"}
        CGPROGRAM
        #include "Lighting.cginc"
        #pragma vertex vert
        #pragma fragment frag

         fixed3 _Diffuse;

        struct a2v{
        float4 ps:POSITION;
        float3 nm:NORMAL;

        };

        struct v2f{
        float4 position:SV_POSITION;
        fixed3 cl:COLOR;
        };

        v2f vert(a2v v){

        v2f f;

        f.position=UnityObjectToClipPos(v.ps);

        f.cl=mul(v.nm,(float3x3)unity_WorldToObject);
    
        return f;
        }

        fixed4 frag(v2f f):SV_Target{

        float3 ambient0=UNITY_LIGHTMODEL_AMBIENT.rgb;

        fixed3 normalDir=normalize(f.cl);

        fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);

        fixed3 diffused=_LightColor0.rgb*max(0,dot(lightDir,normalDir))*_Diffuse;

        fixed3 tempColor=diffused+ambient0;

        return fixed4 (tempColor,1);
        }

        ENDCG

        }

    }

    Fallback "Diffuse"

}


逐顶点光照和逐像素光照渲染出来的效果区别如下:

很显然,通过逐像素光照渲染出来的效果明显比前者平滑很多,但是相对应的,耗费的性能也更多。

半兰伯特光照模型:
半兰伯特光照模型基本上与全兰伯特光照模型公式相差不大,代码稍作修改即可:

        fixed3 diffused=_LightColor0.rgb*max(0,dot(lightDir,normalDir))*_Diffuse;

修改为:

		float3 halfLambert=dot(lightDir,normalDir)*0.5+0.5;
		fixed3 diffused=_LightColor0.rgb*halfLambert*_Diffuse;

全兰伯特光照模型与半兰伯特光照模型对比:

在这里插入图片描述
可以看出,半兰伯特光照模型对于阴影部分的处理的更好。全兰伯特光照模型在计算阴影部分时就有点不尽人意。

涉及到的知识点:
1:什么是光照模型?

光照模型就是一个公式,使用这个公式来计算某个点的光照效果。

2:漫反射公式?

漫反射=直射光颜色*max(0,cos夹角(光和法线的夹角)) cosθ=光方向·法线方向

3:#include “Lighting.cginc”:类似C#中引用命名空间,引用之后才能使用Unity内置的一些变量

4:Tags{“LightMode”=“ForwardBase”}:只有定义了正确的LightMode才能得到一些Unity的内置光照变量

5:max(x,n):两个参数之间取最大的一个

6:dot(x,n):取得两个向量点积

7:_WorldSpaceLightPos0 :取得直射光的位置

8:_LightColor0:取得直射光的颜色

9:(float3x3)unity_WorldToObject:模型矩阵的逆(补充:unity_ObjectToWorld是模型矩阵)

10:UNITY_LIGHTMODEL_AMDIENT:获取环境光

11:normalize():把一个向量单位化,方向不变,长度为1

12:颜色融合和颜色叠加:

1)颜色融合:颜色融合直接在公式中相乘,如漫反射融合物体本身材质颜色就相乘。

2)颜色叠加:因为一个物体是受到自发光、高光反射、漫反射及环境光的综合作用,所以相互叠加。颜色叠加一般亮度会增加。

13:通过片元函数实现光照模型比通过顶点函数实现更消耗性能,因为片元函数是逐像素计算,而顶点函数是依赖模型的顶点进行计算。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值