UnityShader(二)

该博客主要介绍了Unity Shader中的光照模型,包括漫反射模型(Lambert)、Phong高光反射和Blinn - Phong高光反射。详细给出了漫反射模型和Phong高光反射的公式,还提及Blinn - Phong高光反射与Phong参数相同但计算方式不同,并给出了部分代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                                             UnityShader(二)

光照模型:

1.漫反射模型(Lambert)

公式如下:

C反指的是反射光线的强度,C光指的是入射光线的强度,m物指的是物体的材质反射系数,l向量指的是反射光线对应的向量,n向量指的是法线向量。因为,l向量与n向量都是单位向量,所以点乘积得到的结果实际上是cosθ。

放在顶点着色器,代码如下:

Shader "Unlit/005"
{
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags
        { 
            "RenderType" = "Opaque"
            "LightMode"= "Vertex"
        }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            fixed4 _Diffuse;
                
            struct v2f
            {
                float4 vertex:SV_POSITION;
                fixed3 color : Color;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                //环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; 
                //需要在同一个空间 点积 才有效,光源是在世界空间,法线是在模型空间,因此
                //需要将法线从模型空间转换到世界空间,法线的转换并不是简单的用mvp矩阵转换
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                //这个地方不确定_WorldSpaceLightPos0.xyz是否是单位向量,所以需要单位化
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                
                fixed3 diffuse = unity_LightColor0.rgb * _Diffuse.rgb * max(0,dot(worldNormal, worldLight));
                
                o.color = diffuse + ambient;
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                return fixed4(i.color,1);
            }
            ENDCG
        }
    }
}

放在片元着色器,代码如下:

Shader "Unlit/006"
{
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags 
        { 
            "RenderType" = "Opaque" 
            //这个地方可以是Deferred ForwardBase vertex
            //Deferred不写LightMode即是这种模式,在这种模式下unity_LightColor0为(0,0,0)
            //Vertex这种模式用于顶点光照渲染,如果没有光照映射,所有顶点光照被应用
            //ForwardBase用于正向渲染,环境主要方向灯和定点光/SH 等的应用 ,第一个像素光所在的反射通道标记为Forward
            "LightMode" = "Vertex"
        }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            fixed4 _Diffuse;
                
            struct v2f
            {
                float4 vertex:SV_POSITION;
                fixed3 worldNormal : TEXCOORD0;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);    
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldNormal = worldNormal; 
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; 

                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse =unity_LightColor0.rgb* _Diffuse.rgb*max(0,dot(worldLightDir,i.worldNormal));
                fixed3 color = ambient + diffuse;
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}

2.Phong高光反射

公式如下:

其中m只与物体的材质有关,m次是一个常数。

代码如下:

顶点高光反射:

Shader "Unlit/008"
{
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(1, 20)) = 5
    }
    SubShader
    {
        Tags
        { 
            "RenderType" = "Opaque"
            "LightMode"= "Vertex"
        }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            fixed _Gloss;
                
            struct v2f
            {
                float4 vertex:SV_POSITION;
                fixed3 color : Color;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                //环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; 
                //需要在同一个空间 点积 才有效,光源是在世界空间,法线是在模型空间,因此
                //需要将法线从模型空间转换到世界空间,法线的转换并不是简单的用mvp矩阵转换
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                //这个地方不确定_WorldSpaceLightPos0.xyz是否是单位向量,所以需要单位化
                //worldLight代表反射光线 可以自己用_WorldSpaceLightPos0单位化自己写
                //也可以用UnityWorldSpaceLightDir获得,建议使用这个API获得
                //fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 worldLight = UnityWorldSpaceLightDir(UnityObjectToWorldDir(v.vertex));
                
                fixed3 diffuse = unity_LightColor0.rgb * _Diffuse.rgb * max(0,dot(worldNormal, worldLight));
                
                //这个地方算出来的是r向量也就是反射光线的向量
                fixed3 reflectDir = normalize(reflect(-worldLight,worldNormal));
                //fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - UnityObjectToWorldDir(v.vertex));
                //但是这样子求出来的不是世界坐标而是向量,所以要用其他方法
                //fixed3 worldPos = UnityObjectToWorldDir(v.vertex);
                //模型空间坐标变换到世界坐标需要左乘unity_ObjectToWorld矩阵,但这个矩阵应该是4维的,所以下面要去掉3乘3
                //这个地方求位置要用4乘4的,求方向用3乘3的
                //fixed3 worldPos = mul((float3x3)unity_ObjectToWorld,v.vertex);
                fixed3 worldPos = mul(unity_ObjectToWorld,v.vertex);
                //前置带Unity的需要传入世界坐标,而且会单位化
                //fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
                //也可以不把点转到世界坐标,直接由本地坐标得到一个viewDir
                //fixed3 viewDir = normalize(WorldSpaceViewDir(v.vertex));
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
                fixed3 specular = unity_LightColor0.rgb * _Specular.rgb * pow(max(0,dot(viewDir,reflectDir)),_Gloss);
                o.color = diffuse + ambient + specular;
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                return fixed4(i.color,1);
            }
            ENDCG
        }
    }
}

片元高光反射:

Shader "Unlit/009"
{
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(1, 20)) = 5
    }
    SubShader
    {
        Tags 
        { 
            "RenderType" = "Opaque" 
            //这个地方可以是Deferred ForwardBase vertex
            //Deferred不写LightMode即是这种模式,在这种模式下unity_LightColor0为(0,0,0)
            //Vertex这种模式用于顶点光照渲染,如果没有光照映射,所有顶点光照被应用
            //ForwardBase用于正向渲染,环境主要方向灯和定点光/SH 等的应用 ,第一个像素光所在的反射通道标记为Forward
            "LightMode" = "Vertex"
        }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;
                
            struct v2f
            {
                float4 vertex:SV_POSITION;
                fixed3 worldNormal : TEXCOORD0;
                float3 worldPos:TEXCOORD1;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);    
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldNormal = worldNormal; 
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; 
                //漫反射
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = unity_LightColor0.rgb* _Diffuse.rgb*max(0,dot(worldLightDir,i.worldNormal));
                //phong高光反射
                //计算反射向量
                fixed3 reflectDir = normalize(reflect(-worldLightDir,i.worldNormal));
                //fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                //计算高光颜色
                fixed3 specular = unity_LightColor0.rgb * _Specular.rgb * pow(max(0,dot(viewDir,reflectDir)),_Gloss); 


                fixed3 color = ambient + diffuse + specular;
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}

3.Blinn-Phong高光反射

参数同Phong,只是计算的方式不一样。

Shader "Unlit/010"
{
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(1, 20)) = 5
    }
    SubShader
    {
        Tags 
        { 
            "RenderType" = "Opaque" 
            //这个地方可以是Deferred ForwardBase vertex
            //Deferred不写LightMode即是这种模式,在这种模式下unity_LightColor0为(0,0,0)
            //Vertex这种模式用于顶点光照渲染,如果没有光照映射,所有顶点光照被应用
            //ForwardBase用于正向渲染,环境主要方向灯和定点光/SH 等的应用 ,第一个像素光所在的反射通道标记为Forward
            "LightMode" = "Vertex"
        }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;
                
            struct v2f
            {
                float4 vertex:SV_POSITION;
                fixed3 worldNormal : TEXCOORD0;
                float3 worldPos:TEXCOORD1;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);    
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldNormal = worldNormal; 
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; 
                //漫反射
                //获得反射光线 可以自己用对应变量单位化  也可以调用API,建议调用API,这样会有宏判断 跨平台不容易出问题
                //fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 worldLightDir = UnityWorldSpaceLightDir(UnityObjectToWorldDir(i.worldPos));
                
                fixed3 diffuse = unity_LightColor0.rgb* _Diffuse.rgb*max(0,dot(worldLightDir,i.worldNormal));
                //blinnphong高光反射需要求半角向量
                //这个地方计算视角坐标 可以直接相机的位置-点的位置计算
                //fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                //也可以使用unity的内置函数计算,推荐使用内置函数计算,内置函数里会进行一些宏判断
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                //计算半角向量 半角向量等于光源方向加视角方向
                fixed3 halfDir = normalize(worldLightDir + viewDir);
                //计算高光颜色
                fixed3 specular = unity_LightColor0.rgb * _Specular.rgb * pow(max(0,dot(halfDir,i.worldNormal)),_Gloss); 


                fixed3 color = ambient + diffuse + specular;
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值