【《Unity 2018 Shaders and Effects Cookbook》翻译提炼】(七)卡通效果和 Phong模型

1.卡通效果shader

        游戏中最常用的效果之一是toonshader,也被称为celluloid(CEL)shading。这是一种非真实感渲染技术,可以让3D模型显得平坦。许多游戏使用它来表示图形是手绘而不是3D建模的错觉。我们可以在下图种看到使用toon Shader(左)和Standard Shader(右)。

       

         要想达到这种效果单纯的使用surface 函数不是不可能实现的,但它将非常昂贵且耗时。事实上,surface 函数仅适用于材质的属性,而不适用于实际的照明条件。由于toon shading需要我们改变光线反射的方式,我们需要创建自定义光照模型。

         a.创建一个shader命名为ToonShader。

         b. 创建一个material命名为ToonShaderMat。

         c.此外我们需要一个称为ramp map 的附加纹理。该纹理将用于指示何时根据收到的阴影使用某些颜色。选中我们的纹理后在Inspector 面板,改变纹理的WrapMode 为Clamp。如果你想要两种颜色之间的边缘变得清晰,Filter Mode也应该设为Point。

     

  

       e.在属性块添加 _RampTex属性并移走_Glossiness,_Metallic,_Color属性,并在CGPROGRAM部分添加移除相关变量

     _RampTex("Ramp",2D) = "white" {}

     sampler2D _RampTex;

       h.更改#pragma指令,使其指向名为LightingToon()的函数:

     #pragma surface surf Toon

       i.添加一个函数并命名为LightingToon:

      fixed4 LightingToon(SurfaceOutput s, fixed3 lightDir, fixed atten)
        {
            //First calculate the dot product of the light direction and the surface's normal
            half NdotL = dot(s.Normal, lightDir);
            //Remap NdotL to the value on the ramp map
            NdotL = tex2D(_RampTex, fixed2(NdotL, 0.5));

            //Next,set what color should be returned
            half4 color;
            color.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
            color.a = s.Alpha;

            //Return the calculated color
            return color;
        }

      j.在surf函数种添加如下部分

      void surf(Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
        }

     k.保存脚本回到场景效果图如下:

    源码如下:

Shader "Custom/ToonShader" {
	Properties {
		_RampTex("Ramp",2D) = "white" {}
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
	
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

		CGPROGRAM
       #pragma surface surf Toon

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0

		sampler2D _MainTex;
		sampler2D _RampTex;
		
		struct Input {
			float2 uv_MainTex;
		};

		fixed4 LightingToon(SurfaceOutput s, fixed3 lightDir, fixed atten)
		{
			//First calculate the dot product of the light direction and the surface's normal
			half NdotL = dot(s.Normal, lightDir);
			//Remap NdotL to the value on the ramp map
			NdotL = tex2D(_RampTex, fixed2(NdotL, 0.5));

			//Next,set what color should be returned
			half4 color;
			color.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
			color.a = s.Alpha;

			//Return the calculated color
			return color;
		}
	   
		void surf(Input IN, inout SurfaceOutput o) {
			o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
		}

		ENDCG
	}
	FallBack "Diffuse"
}

    提示:

            可以通过Window|Lighting|Settings来改变Environment|Environmental Lighting|Intensity Multiplier值为0 来调试该效果。

它是如何运行的

        Toon shading的主要特征是光线的渲染方式;表面没有均匀的阴影。为了达到这个效果,我们需要一个渐变纹理图。其目的是将Lambertian光照强度重新映射到另一个值。使用没有渐变的渐变映射,我们可以强制照明步骤逐步渲染。下图显示了如何使用渐变纹理图来校正光强度:

相关

        有许多不同的方法可以实现Toon shading效果。使用不同的渐变会对模型的外观产生巨大的变化,因此我们应该试验以找到最佳的。渐变纹理的另一种替代方法是捕捉光强度NdotL,以便它只能假设从0到1等距采样一定数量的值。

       

	half4 LightingCustomLambert(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
	{
		half NdotL = dot(s.Normal, lightDir);
		//Snap instead
		half cel = floor(NdotL * _CelShadingLevels) / (_CelShadingLevels - 0.5);
		//Next,set what color should be returned
		half4 color;
		color.rgb = s.Albedo * _LightColor0.rgb * (cel * atten);
		color.a = s.Alpha;
		//Return the calculated color

		return color;
	}

          要捕捉一个数字,我们首先将NdotL乘以_CelShadingLevels变量,通过floor函数将结果四舍五入为整数,然后将其除以。这种舍入由floor函数完成,它将有效地从一个数字中删除小数点。通过这样做,cel 数量被迫承担从0到1的_CelShadingLevels等距值之一。这消除了对渐变纹理的需要并使所有颜色步骤具有相同的大小。如果我们要用此方法,我们要添加_CelShadingLevels属性。

  2.Phong 模型

        物体表面的镜面反射仅仅描述了它的闪亮程度。这些类型的效果通常在shader世界被称为视图相关效果,这是因为,为了在shader中实现逼真的高光效果,我们需要包括相机的方向或永和面向物体的面。最基本且性能最友好的Specular类型使Phong  Specular效果。

         a.创建一个shader命名为Phong。

         b.创建一个material命名为PhongMat。

         c.双击打开shader,删除所有当前属性及其定义,然后将以下属性添加到shader并在SubShader{}模块添加相关变量:

         Properties {
        _MainTint("Diffuse Tint",Color) = (1,1,1,1)
        _MainTex("Base (RGB)",2D) = "white"{}
        _SpecularColor("Specular Color",Color) = (1,1,1,1)
        _SpecPower("Specular Power",Range(0,30)) = 1
         }

         e.现在,我们必须添加我们的自定义光照模型,以便我们可以计算自己的Phong Specular.将以下代码添加到Subshader {}函数  

      fixed4 LightingPhong(surfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
        {
            //Reflection
            float NdotL = dot(s.Normal, lightDir);
            float3 reflectionVector = normalize(2.0 * s.Normal * NdotL - lightDir);

            // Specular
            float spec = pow(max(0, dot(reflectionVector, viewDir)), _SpecPower);

            //Final effect
            fixed4 c;
            c.rgb = (s.Albedo * _LightColor0.rgb * max(0, NdotL) * atten) + (_LightColor0.rgb * finalSpec);
            c.a = s.Alpha;
            return c;

        }

         h.接下来,我们必须告诉CGPROGRAM块它需要使用我们的自定义Lighting函数而不是其中的内置函数。我们通过将#pragma语句更改为以下内容来完成操作

            CGPROGRAM
            #pragma surface surf Phong

        i.最后,我们把surf函数更新为以下代码:

        void surf (Input IN, inout SurfaceOutput o) {
            half4 c = tex2D(_MainTex, IN.uv_MainTex) * _MainTint;
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

        j.保存代码。回到场景,效果图如下

 

       k.尝试更改Specular 属性并观察效果。

       源码如下:
  

Shader "Custom/Phong" {
	Properties {
		_MainTint("Diffuse Tint",Color) = (1,1,1,1)
		_MainTex("Base (RGB)",2D) = "white"{}
		_SpecularColor("Specular Color",Color) = (1,1,1,1)
		_SpecPower("Specular Power",Range(0,30)) = 1
	}
		SubShader{
			Tags { "RenderType" = "Opaque" }
			LOD 200

			CGPROGRAM
			#pragma surface surf Phong

			// Use shader model 3.0 target, to get nicer looking lighting
			#pragma target 3.0
		float4 _SpecularColor;
	 	sampler2D _MainTex;
		float4 _MainTint;
		float _SpecPower;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D(_MainTex, IN.uv_MainTex) * _MainTint;
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}
		fixed4 LightingPhong(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
		{
			//Reflection
			float NdotL = dot(s.Normal, lightDir);
			float3 reflectionVector = normalize(2.0 * s.Normal * NdotL - lightDir);

			// Specular
			float spec = pow(max(0, dot(reflectionVector, viewDir)), _SpecPower);
			float3 finalSpec = _SpecularColor.rgb * spec;

			//Final effect
			fixed4 c;
			c.rgb = (s.Albedo * _LightColor0.rgb * max(0, NdotL) * atten) + (_LightColor0.rgb * finalSpec);
			c.a = s.Alpha;
			return c;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

它是如何运行的:

       

     在我们的例子中,我们使用的是Specular shader,因此我们需要具有依赖于视图的Lighting函数结构,我们必须写下列内容:

CGPROGRAM
#pragma surface surf Phong
fixed4 LightingPhong(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
{
    //...
}
      这告诉shader我们要创建自己的视图相关shader。始终确保Lighting函数声明和#pragma语句中Lighting函数名称相同,否则Unity 将无法找到我们的光照模型。

    在Phong模型中起作用的组件如下入所示。我们有光方向L(加上它的反射R)和法线方向N。它们之前在Lambertian模型中都有遇到过。除了V,它是视图方向:

Phong模型假设反射表面的最终光强度由两个分量给出,即漫反射颜色和镜面反射值。如下所示:

                                                                    I = D + S

漫反射分量D和之前的Lambertian模型保持不变:

                                                                    D = N * L

镜面反射分量S定义如下:

                                                                    S= (R*L)P

这里,P是shader 中定义为_SpecPower的Specular power。唯一未知的参数是R,它是根据N的L的反射。在向量代数中,这可以计算如下。

                                                                   R = 2N * (N * L)- L

这正是以下计算的内容:

       float3 reflectionVector = normalize(2.0 * s.Normal *NdotL - lightDir);

这有使法线向光线弯曲的效果;作为一个顶点,法线指向远离光线,有关更直观的表示,请看下图

     以上均基于Unity2018.1.0f源码可见我的GitHub:

    https://github.com/xiaoshuivv/ShadersUnity2018.1.0f.git

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Book Description: Since their introduction to Unity, Shaders have been notoriously difficult to understand and implement in games: complex mathematics have always stood in the way of creating your own Shaders and attaining that level of realism you crave. With Shaders, you can transform your game into a highly polished, refined product with Unity’s post-processing effects. Unity Shaders and Effects Cookbook is the first of its kind to bring you the secrets of creating Shaders for Unity3D―guiding you through the process of understanding vectors, how lighting is constructed with them, and also how textures are used to create complex effects without the heavy math. We’ll start with essential lighting and finishing up by creating stunning screen Effects just like those in high quality 3D and mobile games. You’ll discover techniques including normal mapping, image-based lighting, and how to animate your models inside a Shader. We’ll explore the secrets behind some of the most powerful techniques, such as physically based rendering! With Unity Shaders and Effects Cookbook, what seems like a dark art today will be second nature by tomorrow. What You Will Learn Understand physically based rendering to fit the aesthetic of your game Enter the world of post-processing effects to make your game look visually stunning Add life to your materials, complementing Shader programming with interactive scripts Design efficient Shaders for mobile platforms without sacrificing their realism Use state-of-the-art techniques such as volumetric explosions and fur shading Build your knowledge by understanding how Shader models have evolved and how you can create your own Discover what goes into the structure of Shaders and why lighting works the way it does Master the math and algorithms behind the most used lighting models
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值