用Unity Shder实现Real-Time Rendering第五章的Gooch Shading

用Unity Shder实现Real-Time Rendering第五章的Gooch Shading

简要介绍

Real-Time Rendering 4th在第五章中介绍了多种着色模型,而在5.1节介绍了一种结合了Gooch着色和高光反射的风格化着色模型作为开篇样例。今天我用Unity的顶点/片元着色器实现了这个着色模型。(对于这种着色器的简单介绍请参考我的另一篇文章:顶点/片元着色器的基本架构)

这个着色模型基本原理如下:
c s h a d e d = s c h i g h l i g h t + ( 1 − s ) ( t c w a r m + ( 1 − t ) c c o o l ) c_{shaded}=sc_{highlight}+(1-s)(tc_{warm}+(1-t)c_{cool}) cshaded=schighlight+(1s)(tcwarm+(1t)ccool)
其中,
c c o o l = ( 0 , 0 , 0.55 ) + 0.25 c s u r f a c e c_{cool}=(0,0,0.55)+0.25c_{surface} ccool=(0,0,0.55)+0.25csurface
c w a r m = ( 0.3.0.3.0 ) + 0.25 c s u r f a c e c_{warm}=(0.3.0.3.0)+0.25c_{surface} cwarm=(0.3.0.3.0)+0.25csurface
c h i g h l i g h t = ( 1 , 1 , 1 ) c_{highlight}=(1,1,1) chighlight=(1,1,1)
t = ( n ⃗ ⋅ l ⃗ ) + 1 2 t=\frac{(\vec n\cdot\vec l)+1}{2} t=2(n l )+1
r ⃗ = 2 ( n ⃗ ⋅ l ⃗ ) n ⃗ − l ⃗ \vec r=2(\vec n\cdot\vec l)\vec n-\vec l r =2(n l )n l
s = s t a t u r e ( 100 ( r ⃗ ⋅ v ⃗ ) − 97 ) s=stature(100(\vec r\cdot\vec v)-97) s=stature(100(r v )97)
这个模型实现起来比较简单,不涉及复杂的纹理运算,只是纯色之间的一个调和。
在书上,作者给出了如下效果图:
用Unity Shder实现Real-Time Rendering第五章的Gooch Shading_第1张图片
而对于三向量关系,有如下图示:
用Unity Shder实现Real-Time Rendering第五章的Gooch Shading_第2张图片

实现

Shader "RTR shaders/Gooch shading"{
    Properties{
        _Surface_Color ("Surface Color",Color)=(1,1,1,1)
        _Warm_Color ("Warm Color",Color)=(0.3,0.3,0.0,1)
        _Cool_Color ("Cool Color",Color)=(0,0,0.55)
        _Specular_Color ("Specular Color",Color)=(1,1,1,1)
    }
    SubShader{
        Tags{"RenderType"="Opaque" "Queue"="Geometry"}

        pass{
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma multi_compile_fwdbase
            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"

            fixed4 _Surface_Color;
            fixed4 _Warm_Color;
            fixed4 _Cool_Color;
            fixed4 _Specular_Color;

            struct a2v{
                float4 vertex:POSITION;
                float3 normal:NORMAL;
            };
            struct v2f{
                float4 pos:SV_POSITION;
                float3 worldPos:TEXCOORD1;
                float3 worldnormal:TEXCOORD2;
            };

            v2f vert(a2v v){
                v2f o;
                o.pos=UnityObjectToClipPos(v.vertex);
                o.worldnormal=UnityObjectToWorldNormal(v.normal);
                o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
                return o;
            }

            fixed4 frag(v2f o):SV_TARGET{
                float3 LightDir=
                normalize(UnityWorldSpaceLightDir(o.worldPos));
                float3 ViewDir=
		        normalize(UnityWorldSpaceViewDir(o.worldPos));
                float t=0.5*(dot(o.worldnormal,LightDir)+1);
                float3 r=
			    2*dot(o.worldnormal,LightDir)*o.worldnormal-LightDir;
                float s=saturate(100*dot(r,ViewDir)-97);

                fixed4 c=s*_Specular_Color+(1-s)*(t*(_Warm_Color+0.25*_Surface_Color)+(1-t)*(_Cool_Color+0.25*_Surface_Color));

                return c;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

测试

最终,我选择用几个简单的模型来测试这个效果,最终效果还是很不错的。
用Unity Shder实现Real-Time Rendering第五章的Gooch Shading_第3张图片用Unity Shder实现Real-Time Rendering第五章的Gooch Shading_第4张图片

你可能感兴趣的:(Unity,Shader,RTR,4th)