着色器的优化

作者:追风剑情 发布于:2016-3-13 14:24 分类:Shader

数据类型优化

float:完整的32位单精度的数据类型,是3个类型中最慢的,同时对应的坐标类型为float2、float3、float4

half:它是低精度16位浮点类型,适合存放UV值、颜色值,比float快得多,相似的坐标类型还有half2、half3、half4

fixed:它是3个类型中最小的,可以用于光照计算、颜色,同样有坐标类型fixed2、fixed3、fixed4


我们对着色器的下一步优化是在#pragma中声明noforwardadd值。它像一个开关会自动告诉Unity,这个着色器在每个像素仅仅接受一个单一的方向光。着色器中任何其他类型的光照计算都会在Unity内部使用球谐光照值进行逐像素处理。我们在场景中再摆放一个方向光对球体进行光照就能明显地看出区别,这是因为着色器使用法线贴图的过程是一个逐像素的操作。


如果场景中有多个方向光,想要其中的一个方向光作为主要的像素光源该如何实现呢?

每个灯光都有一个Render Mode的下拉选项,选择Important认为是像素光源,选择Nor Important则认为是顶点光源。选择Auto,Unity会自动选择光源。


Render Mode.png


放置另一个点光源,移除着色器当前的主贴图。你将发现第二个点光源并没有对法线贴图产生作用,而只有第一个方向光起作用了。这种概念的基本思路就是通过只计算所有额外灯泡的顶点光照来达到节省每个像素操作,以及通过计算主方向光的逐像素光照来达到保持性能的目的。


在#pragma表达式中加入exclude_path:prepass声明。这样着色器就不会接受任何来自延迟渲染的自定义光照了。这也意味着我们可以在主摄像机中将着色器设置成只能在前向着色中有效。


示例:

优化前

Shader "Custom/OptimizedShader001" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {} //漫反射贴图
		_NormalMap ("Normal Map", 2D) = "bump" {} //法线贴图
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf SimpleLambert

		sampler2D _MainTex;
		sampler2D _NormalMap;

		struct Input {
			float2 uv_MainTex;
			float2 uv_NormalMap;
		};
		
		// 自定义光照函数
		inline float4 LightingSimpleLambert (SurfaceOutput s, float3 lightDir, float atten)
		{
			float diff = max (0, dot (s.Normal, lightDir));
			
			float4 c;
			c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
			c.a = s.Alpha;
			return c;
		}

		void surf (Input IN, inout SurfaceOutput o) 
		{
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			
			o.Albedo = c.rgb;
			o.Alpha = c.a;
			o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
		}
		ENDCG
	} 
	FallBack "Diffuse"
}

优化后

//数据优化后的着色器
Shader "Custom/OptimizedShader002" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {} //漫反射贴图
		_NormalMap ("Normal Map", 2D) = "bump" {} //法线贴图
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		//优化: 只开启特定的某些渲染工作 
		//优化: 充分利用内置的光照模型变量来控制光照在着色器中的执行过程
		#pragma surface surf SimpleLambert exclude_path:prepass noforwardadd

		sampler2D _MainTex;
		sampler2D _NormalMap;
		
		//优化: 变量类型
		struct Input {
			half2 uv_MainTex; //float2改为half2
			//half2 uv_NormalMap;
		};
		
		// 自定义光照函数
		inline float4 LightingSimpleLambert (SurfaceOutput s, float3 lightDir, float atten)
		{
			//优化变量类型
			fixed diff = max (0, dot (s.Normal, lightDir));
			//优化变量类型
			fixed4 c;
			c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
			c.a = s.Alpha;
			return c;
		}

		void surf (Input IN, inout SurfaceOutput o) 
		{
			//优化变量类型
			fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
			
			o.Albedo = c.rgb;
			o.Alpha = c.a;
			//将法线贴图和漫反射贴图共享uv
			o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
		}
		ENDCG
	} 
	FallBack "Diffuse"
}

效果

Run.png

标签: Shader

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号