Vertex中实现每极点光照的镜面高光效果

Vertex中实现每顶点光照的镜面高光效果

1,基础知识讲解

  一个物体在自然界会收到三种光的影响,周围的环境光、漫反射和镜面反射。那么对于计算机要想模拟现实中的光照,就应该也会实现这三种基本光照->环境光、漫反射、镜面高光。对于这三种光照,都存在着一定的影响因素,这就需要去追究其光照模型的公式了。

  (1),环境光强影响因素

     ,由此可看出环境光照的效果取决于一般环境光的强度  和漫反射的材质颜色 

 

  (2),漫反射光强影响因素

    

    

    由此可看出,漫反射的反射光取决于入射光强度  和材质常数,对于黑色表面,材质常数  的值是 0,对于白色表面,材质常数  的值是 1。当入射光的方向和物体表面法线的夹角有关,夹角越小,越接近法线,那么接受到的光强也就越多,就越亮。此时的dot乘积也就越大。(回想Cos的函数)

  (3),镜面反射光强影响因素

    

     

    镜面反射通过观察者方向 V 来计算镜面反射,如果 V 接近于 R,反射的强度也会变大(同时也受光泽度 影响),根据 R 与 V 角度余弦值的 -th 次方(pow 值)来生成不同光泽的亮点,我们需要限制负余弦的值为 0,此外镜面反射还要求一个材质颜色 (通常是白色)

2,代码演练

  

Shader "JiKi/VertexLighting_Specular" 
{
    Properties
    {
        _Color("Base RGB",Color)=(1,1,1,1)
        _Shininess("Shininess",Range(0.001,10))=10
        _SpecColor("Specular Color",Color)=(1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            Tags
            {
                "LightMode"="ForwardBase"
            }
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            uniform float4 _LightColor0;
            
            uniform float4 _Color;
            uniform float _Shininess;
            uniform float4 _SpecColor;
            
            struct inputVertex
            {
                float4 vertex:POSITION;
                float3 normal:NORMAL;
            };
            struct outPutVertex
            {
                float4 pos:SV_POSITION;
                float4 col:COLOR;    
            };
            
            outPutVertex vert(inputVertex input)
            {
                outPutVertex o;
                //工具函数
                float4x4 modelMatrix=_Object2World;
                float4x4 modelMatrixVerse=_World2Object;
                //世界空间中的法线向量
                float3 normalDir=normalize(mul(float4(input.normal,0.0),modelMatrixVerse).xyz);
                //视线方向
                float3 viewDir=normalize(_WorldSpaceCameraPos-mul(modelMatrix,input.vertex).xyz);
                //灯光
                float3 lightDir;
                float attenuation;//衰减量
                
                if(_WorldSpaceLightPos0.w==0)//证明是无限长度的方向向量
                {
                    attenuation=1.0;
                    lightDir=normalize(_WorldSpaceLightPos0).xyz;
                }
                else
                {
                    float3 vertexToLightSource=(_WorldSpaceLightPos0-mul(modelMatrix,input.vertex)).xyz;
                    float dist=length(vertexToLightSource);
                    lightDir=normalize(vertexToLightSource);
                    attenuation=1/dist;
                }
                //环境光
                float3 ambientColor=UNITY_LIGHTMODEL_AMBIENT.rgb*_Color.rgb;
                //漫反射
                float3 diffuseColor=attenuation*_LightColor0.rgb*_Color.rgb*max(0,dot(normalDir,lightDir));
                //镜面高光
                float3 specularColor;
                if(dot(lightDir,normalDir)<0)//证明是背面
                {
                    specularColor=float3(0,0,0);
                }
                else
                {
                    specularColor=attenuation*_LightColor0.rgb*_SpecColor.rgb*pow((max(0,dot(viewDir,reflect(-lightDir,normalDir)))),_Shininess);
                }
                //混合
                o.col=float4(ambientColor+diffuseColor+specularColor,1.0);
                o.pos=mul(UNITY_MATRIX_MVP,input.vertex);
                return o;
            }
            
            float4 frag(outPutVertex input):COLOR
            {
                return input.col;
            }
            ENDCG
        }
    }
}

  最后上效果图

     

  上面代码写的有些简陋,但个人觉得反映出来光照的原理了,有问题还请大家多多指正。

  由于这个是基于顶点的,因此光照效果显得有些粗糙,不够细腻,后续将在fragment中去实现光照,那样就会得到光滑的镜面高光。敬请期待!!不早了该睡了哈哈

相关内容推荐