項目中美術使用了Unity自帶的Mobile/Diffuse這個shader製做了一部分場景素材,這個shader會依賴場景中的動態實時光源,比較耗費。工具
因而本身手動重寫一份,簡化shader的消耗,但同時保持美術已經制做場景的效果。spa
Shader "Mobile/Diffuse" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 150 CGPROGRAM #pragma surface surf Lambert noforwardadd nolightmap noshadow novertexlights nodynlightmap nodirlightmap sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { fixed4 c = tex2D(_MainTex, IN.uv_MainTex); o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } Fallback "Mobile/VertexLit" }
我在原始shader上添加了一些編譯選項用來關閉一些特性,但編譯出來的shader仍是有不少非必要的運算。code
手動實現一份noforwardadd的(只有一個pass)版本:orm
Shader "James/Scene/Mesh Lighting" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry" } LOD 200 Pass { Tags { "LightMode"="ForwardBase" } // Lighting Off CGPROGRAM #pragma fragmentoption ARB_precision_hint_fastest #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #pragma multi_compile_fog #include "UnityCG.cginc" float4 _LightColor0; uniform sampler2D _MainTex; uniform half4 _MainTex_ST; struct vertexIN_base { float4 vertex : POSITION; float3 normal : NORMAL; float2 texcoord : TEXCOORD0; }; struct v2f_base { float4 pos : SV_POSITION; fixed3 vertexLight : COLOR; half2 uv : TEXCOORD0; float3 normal : TEXCOORD1; float3 lightDir : TEXCOORD2; UNITY_FOG_COORDS(3) }; v2f_base vert(vertexIN_base v) { v2f_base o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.normal = v.normal; o.lightDir = ObjSpaceLightDir(v.vertex); half3 worldNormal = UnityObjectToWorldNormal(v.normal); float3 shlight = ShadeSH9(float4(worldNormal, 1.0)); o.vertexLight = shlight; #ifdef VERTEXLIGHT_ON o.vertexLight += Shade4PointLights ( unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0, unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb, unity_4LightAtten0, worldPos, worldNormal ); #endif UNITY_TRANSFER_FOG(o,o.pos); return o; } fixed4 frag(v2f_base i) : COLOR { i.lightDir = normalize(i.lightDir); i.normal = normalize(i.normal); float diffuse = max(0, dot(i.normal, i.lightDir)); fixed4 mainColor = tex2D(_MainTex, i.uv); fixed4 clr = mainColor * _LightColor0 * diffuse; clr.rgb += mainColor.rgb * i.vertexLight; UNITY_APPLY_FOG(i.fogCoord,clr); return clr; } ENDCG } } FallBack Off }
上述shader和Mobile Diffuse效果基本一致(場景中光照並不複雜),而且默認的效果也是不帶forward add的。htm
但這個shader仍是依賴了場景中的實施光源數據。對象
因而乎,進一步,將場景中的實時光源所有移除,並將光源的顏色和方向信息直接寫在shader的屬性中,獲得了下面的去光源版本:blog
Shader "James/Scene/Mesh Diffuse" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _MainLightColor("主光顏色", Color) = (1,1,1,1) _MainLightDir("主光方向", Vector) = (1,1,0,0) _SecondLightColor("輔光顏色", Color) = (1,1,1,1) _SecondLightDir("輔光方向", Vector) = (1,1,0,0) _SecondLightBrightness ("輔光強度", Range(0, 10)) = 0.9 } SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry" } LOD 200 Pass { Tags { "LightMode"="ForwardBase" } Lighting Off CGPROGRAM #pragma fragmentoption ARB_precision_hint_fastest #pragma vertex vert #pragma fragment frag #pragma multi_compile_fog #include "UnityCG.cginc" float4 _MainLightColor; float4 _MainLightDir; float4 _SecondLightColor; float4 _SecondLightDir; float _SecondLightBrightness; uniform sampler2D _MainTex; uniform half4 _MainTex_ST; struct vertexIN_base { float4 vertex : POSITION; float3 normal : NORMAL; float2 texcoord : TEXCOORD0; }; struct v2f_base { float4 pos : SV_POSITION; half2 uv : TEXCOORD0; float3 normal : TEXCOORD1; float3 lightDir : TEXCOORD2; float3 lightDir2 : TEXCOORD3; UNITY_FOG_COORDS(4) }; v2f_base vert(vertexIN_base v) { v2f_base o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.normal = v.normal; o.lightDir = mul(unity_WorldToObject, _MainLightDir).xyz; o.lightDir2 = mul(unity_WorldToObject, _SecondLightDir).xyz; UNITY_TRANSFER_FOG(o,o.pos); return o; } fixed4 frag(v2f_base i) : COLOR { i.lightDir = normalize(i.lightDir); i.lightDir2 = normalize(i.lightDir2); i.normal = normalize(i.normal); float diffuse = max(0, dot(i.normal, i.lightDir)); float diffuse2 = max(0, dot(i.normal, i.lightDir2)); fixed4 mainColor = tex2D(_MainTex, i.uv); fixed4 clr = mainColor * _MainLightColor * diffuse; clr += _SecondLightBrightness * (mainColor * _SecondLightColor * diffuse2); UNITY_APPLY_FOG(i.fogCoord,clr); return clr; } ENDCG } } FallBack Off }
這個版本支持兩個光源信息,而後按照一樣的Lambert光照方式來計算光照信息,其中輔光給了一個強度的調節因子。ip
注:這裏沒有徹底按照默認的計算方式來計算主光之外的光照信息,是由於half3 ShadeSH9 (half4 normal)因此來的unity_SHAr unity_SHAg unity_SHAb的計算方式不明確。ci
// normal should be normalized, w=1.0 half3 SHEvalLinearL0L1 (half4 normal) { half3 x; // Linear (L1) + constant (L0) polynomial terms x.r = dot(unity_SHAr,normal); x.g = dot(unity_SHAg,normal); x.b = dot(unity_SHAb,normal); return x; } // normal should be normalized, w=1.0 half3 SHEvalLinearL2 (half4 normal) { half3 x1, x2; // 4 of the quadratic (L2) polynomials half4 vB = normal.xyzz * normal.yzzx; x1.r = dot(unity_SHBr,vB); x1.g = dot(unity_SHBg,vB); x1.b = dot(unity_SHBb,vB); // Final (5th) quadratic (L2) polynomial half vC = normal.x*normal.x - normal.y*normal.y; x2 = unity_SHC.rgb * vC; return x1 + x2; } // normal should be normalized, w=1.0 // output in active color space half3 ShadeSH9 (half4 normal) { // Linear + constant polynomial terms half3 res = SHEvalLinearL0L1 (normal); // Quadratic polynomials res += SHEvalLinearL2 (normal); # ifdef UNITY_COLORSPACE_GAMMA res = LinearToGammaSpace (res); # endif return res; }
Unity是怎麼計算出unity_SHAr unity_SHAg unity_SHAb這幾個變量的,又知道的小夥伴能夠告知一下哈。 it
下面是基於以上三個shader的實時渲染效果,其中"James/Scene/Mesh Diffuse"不依賴場景光源。
讓美術直接在材質球上面手動輸入light dir,其實很是的不直觀,因而寫了一個工具,直接把場景中的lighting對應的shader中的方向值給打印出來:
private void WriteLightingDir() { Object obj = Selection.activeGameObject; if (obj is GameObject == false) return; Debug.Log(-(obj as GameObject).transform.forward); }
選中場景中的Lighting對象,而後執行上面的編輯期代碼便可打印出方向值。
添加環境光:
若是隻有場景光照,模型會有一些暗角,所以還須要加上自定義環境光的光照亮度。
首先經過代碼設置全局的環境光,方便shader訪問:
using System.Collections; using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode] public class GlobalShaderSetting : MonoBehaviour { public Color GlobalAmbientColor = new Color(0.5f, 0.5f, 0.5f, 1f); public float GlobalAmbientBrightness = 1; public Vector4 GlobalWindDirection = new Vector4(0.5f, 0.5f, 0.5f, 1f); [ContextMenu("Set")] private void Awake() { Shader.SetGlobalColor("_GlobalAmbientColor", GlobalAmbientColor); Shader.SetGlobalFloat("_GlobalAmbientBrightness", GlobalAmbientBrightness); Shader.SetGlobalVector("_GlobalWindDirection", GlobalWindDirection); } }
而後添加一個cginc的通用文件:
#ifndef JAMES_LIGHTING_H #define JAMES_LIGHTING_H float4 _GlobalAmbientColor; float _GlobalAmbientBrightness; float4 _GlobalWindDirection; #define AMBIENT_COLOR _GlobalAmbientColor * _GlobalAmbientBrightness #endif
在須要添加環境光的shader中添加環境光的影響便可:
clr += mainTex * AMBIENT_COLOR;