Cook-Torrance光照模型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cook-Torrance光照模型相关的知识,希望对你有一定的参考价值。

技术分享

Cook-Torrance光照模型

  该光照模型是基于物理材质的光照模型。光照射到物体表面发生漫反射、镜面反射、折射、透射等现象,在这里我们只考虑漫反射和镜面反射,Cook-Torrance是用来模拟不同材质的镜面反射效果。

  技术分享

    其中:

      ambient :环境光;

      K:决定高光部分和漫射的比例,一般而已,光复合能量守恒定律,即入射光的总能量和出射光的总能量相等;

      rs :镜面发射;

  技术分享

F项:菲涅尔反射

  即Fresnel,菲涅尔反射。我们在观察水面的时候,垂直看下去,清澈见底,看远处的水面,向镜子一样,这个就是菲涅尔效应。菲涅尔效应可以说是无处不在,不同的材质效果不同而已。

  技术分享

    v:视点的方向;

    h:半角向量,即视点和光线的中间向量;

D项:微平面法线分布函数

  该项模拟物体表面是由无数微小的像镜子一样的平面组成,每一个微平面对于光线会根据自身的方向反射光线,只有那些面向视点的平面贡献大。具体参见微平面法线分布的理论。

  技术分享

G项:几何项

   该项用于计算微平面中反射光重合部分的修正。

  技术分享

  技术分享

  技术分享

=============================================================================

Shader "JQM/Cook-Torrance"
{
    Properties
    {
        _Color("Base Color",Color) = (1,1,1,1)
        _MainTex ("Texture", 2D) = "white" {}

        _Roughness("Roughness",Range(0,1)) = 1
        _Fresnel("Fresnel",Range(0,1)) = 1
        _K("K",Range(0,1)) = 1
    }

    
    SubShader
    {

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

            float4 _Color;
            //使用Unity定义的变量:灯光
            uniform float4 _LightColor0;


            float _Roughness;
            float _Fresnel;
            float _K;

            struct VertexOutput
            {
                float4 pos : SV_POSITION;
                float4 posWorld : TEXCOORD1;
                float2 uv : TEXCOORD2;
                float3 normal:Normal;
                
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            VertexOutput vert (appdata_full v)
            {
                VertexOutput o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.posWorld = mul(_Object2World, v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.normal = v.normal;

                return o;
            }

            fixed4 frag (VertexOutput i) : COLOR
            {
                //将法线转到世界空间:乘以变换矩阵的逆的转置
                //float3 normalWorld  = mul(_Object2World,i.normal);
                float3 normalWorld  = mul(i.normal,_World2Object);

                //观察者
                float3 eyeDir = normalize(_WorldSpaceCameraPos -i.posWorld).xyz;

                //光源
                float3 lightDir = normalize(_WorldSpaceLightPos0).xyz;

                fixed4 col = tex2D(_MainTex, i.uv);

                ///计算漫反射
                float3 diffuse = _Color*saturate(dot(lightDir,normalWorld))*_LightColor0/3.14 ;

                //计算高光
                //float3 h = (eyeDir+lightDir)/2;
                //float3 r = normalize(reflect(-lightDir,normalWorld));
                //float3 specular = saturate(dot(lightDir,normalWorld))* _SpecularColor * pow(saturate(dot(r,eyeDir)),_SpecularPower);

                //计算Cook-Torrance高光
                float s;
                float ln = saturate(dot(lightDir,normalWorld));

                if(ln > 0.0)//在光照范围内
                {
                    float3 h = normalize(eyeDir+lightDir);
                    float nh = saturate(dot(normalWorld, h));
                    float nv = saturate(dot(normalWorld, eyeDir));                
                    float vh = saturate(dot(eyeDir, h));
                    
                    //G项
                    float nh2 = 2.0*nh;
                    float g1 = (nh2*nv)/vh;
                    float g2 = (nh2*ln)/nh;
                    float g = min(1.0,min(g1,g2));

                    //D项:beckmann distribution function
                    float m2 = _Roughness*_Roughness;
                    float r1 = 1.0/(4.0 * m2 *pow(nh,4.0));
                    float r2 = (nh*nh -1.0)/(m2 * nh*nh);
                    float roughness = r1*exp(r2);

                    //F项
                    float fresnel = pow(1.0 - vh,5.0);
                    fresnel *= (1.0-_Fresnel);
                    fresnel += _Fresnel;
                    s = saturate((fresnel*g*roughness)/(nv*ln*3.1415926));
                }
                
                float3 specular =_LightColor0*ln*(_K + s*(1-_K));
                float3 final = _K*diffuse + specular + UNITY_LIGHTMODEL_AMBIENT.xyz;
                return float4(final,1);
            }
            ENDCG
        }
    }
}

 

  

以上是关于Cook-Torrance光照模型的主要内容,如果未能解决你的问题,请参考以下文章

一步步学Metal图形引擎10-《BRDF:Cook-Torrance光照模型》

一步步学Metal图形引擎10-《BRDF:Cook-Torrance光照模型》

光照贴图

GLSL PBS 实现,奇怪的着色器行为

Cg入门16:Fragment shader - 片段级光照

Unity Shader 光照模型(基础公式和代码实现)