Unity里基础光照(Lambert、Phong、BlinnPhong模型)的Shader代码

//以下是各种光照模型(Lambert、Phong、BlinnPhong、Gourand)的Shader代码,在Unity里创建一个Material后可以选择使用,各行代码都有注释,不再详细解释了。

Shader "MyShader/BaseShader"
{
//包含Lambert、Phone、Blin-Phong模型
    Properties
    {//定义属性
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(5,255)) = 5
        [Toggle(_Phong)] _Phong("Phong",float) = 1
        [Toggle(BlinnPhong)] _BlinnPhong("BlinnPhong",float) = 1
        _MainTex ("Texture", 2D) = "white" {}
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"} //定义Tag
        //LOD 100

        Pass
        {
            CGPROGRAM
            #include "UnityCG.cginc"    //库函数
            #include "Lighting.cginc"
            //定义触发器,改变光照模型
            #pragma shader_feature _PHONG
            #pragma shader_feature _BLINNPHONG
            #pragma shader_feature _LAMBERT
            #pragma shader_feature _GOURAND
            
            #pragma vertex vert //顶点着色器名称
            #pragma fragment frag   //片元着色器名称
  
            float4 _Diffuse;    //全局参数,漫反射、高光颜色、高光参数
            float4 _Specular;
            float _Gloss;

            struct a2v
            {//应用传入顶点着色器的变量
                float4 vertex : POSITION;
                float3 normal :NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 worldNormal: NORMAL;
                float3 worldPos: TEXCOORD1;
                float3 color: TEXCOORD2;                
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (a2v v)
            {//顶点着色器
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);  //顶点空间到裁剪空间
                //o.worldNormal = normalize(mul(v.normal,(float 3x3) unity_worldTo));
                o.worldNormal = UnityObjectToWorldNormal(v.normal);   //法线转换到世界空间
                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;   //顶点位置转换到世界空间

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                #if defined(_GOURAND)
                    float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse;    //环境光
                    float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);    //归一化光方向
                    float3 worldNormal = normalize(o.worldNormal);              //归一化worldNormal
                    float NdotL = max(0, dot(worldLight, worldNormal));         //法线和光线的点积,即余弦值
                    float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * NdotL;    //计算漫反射Lambert
                    float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - o.worldPos.xyz);  //视角方向
                    float3 reflectDir = normalize(reflect(-worldLight,worldNormal));  //计算反射方向,worldLight表示入射光方向
                    float VdotR = max(0, dot(reflectDir, viewDir));         //反射光方向与观察方向的夹角,点积结果为夹角的余弦值
                    float3 specular = _LightColor0.rgb * _Specular.rgb * pow(VdotR, _Gloss);    //高光值
                    o.color = diffuse + ambient + specular;     //Gourand模型最后输出的颜色值
                #endif
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {//片元着色器
                // sample the texture
                //fixed4 col = tex2D(_MainTex, i.uv);
                float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse;     //环境光
                float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);       //归一化光方向
                float3 worldNormal = normalize(i.worldNormal);                //归一化worldNormal
                float NdotL = max(0, dot(worldNormal,worldLight));             //计算漫反射Lambert公式
                fixed4 renderTex = tex2D(_MainTex, i.uv);  

                float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * NdotL;         //计算Diffuse光
                float3 specular;    //存储高光值
                float3 color;       //存储最终颜色值

                float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);  //归一化视方向
                #if defined(_LAMBERT)
                    color = diffuse;    //Lambert模型
                #endif
                
                //#if defined(_PHONG)
                  //Phong模型计算
                    float3 reflectDir = normalize(reflect(-worldLight,worldNormal));    //计算反射方向,worldLight表示入射光方向
                    float VdotR = max(0, dot(viewDir,reflectDir));   //反射光方向与观察方向的夹角,dot(ViewDir,ReflectDir)
                    specular = _LightColor0.rgb * _Specular.rgb * pow(VdotR, _Gloss); //计算高光反射
                    color = ambient + diffuse + specular;
                //#endif
                
                #if defined(_BLINNPHONG)
                   //BlinnPhong模型计算
                    float3 halfDir = (worldLight +viewDir);  //计算半角向量,光线方向+视方向的结果归一化
                    float NdotH = saturate(dot(halfDir,worldNormal));   //半角向量与法线方向的点积,结果归一化
                    specular = _LightColor0.rgb * _Specular.rgb * pow(NdotH, _Gloss);   //计算BlinnPhong的高光值
                    color = ambient + diffuse + specular;
                #endif
                
                #if defined(_GOURAND)
                    color = i.color;    //直接使用顶点着色器中计算出来的颜色值
                #endif
                color = color * renderTex.rgb;
                return fixed4(color,1.0);
            }
            ENDCG
        }
    }
}

posted @ 2022-01-14 22:15  老岳博客  阅读(459)  评论(0编辑  收藏  举报