【UnityShader】高光反射光照模型

先给出基本光照模型中高光反射部分的计算公式:

 

 其中要知道高光反射系数m,视角方向v和反射方向。

反射方向可以由表面法线和光线方向计算 r = l-2(n·l)n ,CG中也提供了reflect函数来操作。

这里给出逐顶点计算的代码:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Custom/Chapter6-SpecularVertexLevel"
{
    Properties{
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color)=(1,1,1,1) //高光颜色
        _Gloss("Gloss",Range(8.0,256)) = 20//高光区域大小
    }
    SubShader{
        Pass{
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v{
                float4 vertex:POSITION;//顶点信息
                float3 normal:NORMAL;
            };
            struct v2f{
                float4 pos:SV_POSITION;//裁剪空间信息
                fixed3 color:COLOR;
            };

            v2f vert(a2v v){
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);//将模型空间坐标转化为裁剪空间

                //获得环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                //将法线由模型空间转化到世界坐标
                fixed3 worldNormal =normalize( mul(v.normal,(float3x3)unity_WorldToObject));
                //得到光源方向
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                //计算漫反射
                fixed3 diffuse = _Diffuse.rgb*_LightColor0*saturate(dot(worldNormal,worldLightDir));  //_LightColor0为内置变量 :表示光色及强度
                //计算反射方向
                fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
                //计算视角方向
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-mul(unity_ObjectToWorld,v.vertex).xyz);
                //计算高光反射
                fixed3 specular = _LightColor0*_Specular.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss);

                o.color = ambient+diffuse+specular;

                return o;
            }

            fixed4 frag(v2f i):SV_Target{
                return fixed4(i.color,1.0);
            }
            ENDCG
        }
    }
    
    FallBack "Specular"
}

此外,还有一种Blinn-Phong光照模型:

Blinn模型引入了一个新的矢量h来替换phomh中的r。

其中h的计算公式如下:

 

给出程序如下:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Custom/Chapter6-SpecularVertexLevel"
{
    Properties{
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color)=(1,1,1,1) //高光颜色
        _Gloss("Gloss",Range(8.0,256)) = 20//高光区域大小
    }
    SubShader{
        Pass{
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v{
                float4 vertex:POSITION;//顶点信息
                float3 normal:NORMAL;
            };
            struct v2f{
                float4 pos:SV_POSITION;//裁剪空间信息
                fixed3 worldNormal:TEXCOORD0;
                fixed3 worldPos:TEXCOORD1;
            };

            v2f vert(a2v v){
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);//将模型空间坐标转化为裁剪空间
                o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
                //o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                return o;
            }

            fixed4 frag(v2f i):SV_Target{
                 //获得环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0).xyz;
                //fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed3 diffuse = _Diffuse.rgb*_LightColor0*saturate(dot(worldNormal,worldLightDir));  //_LightColor0为内置变量 :表示光色及强度
                //计算反射方向
                fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
                //计算视角方向
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);
                //fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                //计算B-P模型新矢量
                fixed3 halfDir = normalize(worldLightDir+viewDir);
                //计算高光反射
                fixed3 specular = _LightColor0*_Specular.rgb*pow(max(0,dot(reflectDir,halfDir)),_Gloss);
              
                return fixed4(ambient+diffuse+specular,1.0);
            }
            ENDCG
        }
    }
    
    FallBack "Specular"
}

一般来说B-P模型高光反射部分更大更亮,而在实际渲染中我们也常选择这个模型。但是注意的是,此为经验模型。

 

从左到右依次是B-P模型,逐像素,逐顶点的渲染情况。

 

 

 = (·) 

posted @ 2021-11-27 21:32  MATSUろ  阅读(175)  评论(0)    收藏  举报