// 统一处理UnityGI的算法 #ifndef UNITY_GI_BASE_INCLUDE #define UNITY_GI_BASE_INCLUDE #include "UnityCG.cginc" #include "Lighting.cginc" #include "AutoLight.cginc" #include "SimLightSpecular.cginc" // Forward Base 通用的参数结构 struct v2f_Base { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float4 tSpace0 : TEXCOORD1; float4 tSpace1 : TEXCOORD2; float4 tSpace2 : TEXCOORD3; UNITY_FOG_COORDS(4) SHADOW_COORDS(5) #ifndef LIGHTMAP_OFF float4 lmap : TEXCOORD6; #endif #if UNITY_SHOULD_SAMPLE_SH half3 sh : TEXCOORD7; // SH #endif }; // Forward Add 使用的参数结构 struct v2f_Add { float4 pos : SV_POSITION; float4 uv : TEXCOORD0; float3 lightDir : TEXCOORD1; float3 worldPos : TEXCOORD2; UNITY_FOG_COORDS(3) SHADOW_COORDS(4) }; GLOBAL_LIGHT_INFORMATION #if PLAYER_HALO_ON uniform float _PlayerLightStrength; uniform float4 _PlayerLightPos; fixed LightColorFromWorld(float3 pos) { float lengthSqr = 0; float toLightX = pos.x - _PlayerLightPos.x; float toLightY = pos.y - _PlayerLightPos.y; float toLightZ = pos.z - _PlayerLightPos.z; lengthSqr += toLightX * toLightX; lengthSqr += toLightY * toLightY; lengthSqr += toLightZ * toLightZ; return _PlayerLightStrength * 2.0 / (1.0 + lengthSqr); } #endif // 通用ForwardBase的Vertex代码 v2f_Base vert_Base(appdata_full v) { v2f_Base o; UNITY_INITIALIZE_OUTPUT(v2f_Base, o); o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w; fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign; o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x); o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y); o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z); TRANSFER_SHADOW(o) UNITY_TRANSFER_FOG(o,o.pos); #ifndef LIGHTMAP_OFF o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw; #ifndef DYNAMICLIGHTMAP_OFF o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; #endif #endif #if UNITY_SHOULD_SAMPLE_SH o.sh = 0; // Approximated illumination from non-important point lights #ifdef VERTEXLIGHT_ON o.sh += 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 o.sh = ShadeSHPerVertex (worldNormal, o.sh); #endif return o; } // 通用ForwardAdd的Vertex代码 v2f_Add vert_Add (appdata_full v) { v2f_Add o; UNITY_INITIALIZE_OUTPUT(v2f_Add, o); o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; // 使用真实光源参数,光照贴图将不会走ForwardAdd #ifdef USING_DIRECTIONAL_LIGHT fixed3 lightDir = _WorldSpaceLightPos0.xyz; #else fixed3 lightDir = normalize(UnityWorldSpaceLightDir(o.worldPos)); #endif TANGENT_SPACE_ROTATION; o.lightDir = normalize(MUL_3x3_WITH_VECTOR(rotation, MUL_3x3_WITH_VECTOR(unity_WorldToObject, lightDir))); TRANSFER_SHADOW(o) UNITY_TRANSFER_FOG(o, o.pos); return o; } float3 GetWorldPos(v2f_Base i) { return float3(i.tSpace0.w, i.tSpace1.w, i.tSpace2.w); } float3 GetLightDir(float3 worldPos) { #ifndef LIGHTMAP_OFF fixed3 lightDir = _DirectionalLight.xyz; #else #ifndef USING_DIRECTIONAL_LIGHT fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos)); #else fixed3 lightDir = _WorldSpaceLightPos0.xyz; #endif #endif return lightDir; } // 不使用SurfaceOutput的LambertLight,直接使用ndotl执行计算 inline fixed3 LambertLight (half3 albedo, half ndotl, UnityLight light) { fixed3 c = albedo * light.color * ndotl; return c; } fixed3 GetUnityGiColorFull(half3 color, v2f_Base i, half3 worldNormal, half3 worldPos, half3 lightDir, float ndotl, float atten) { // 构造常规函数UnityGI UnityGI gi; UNITY_INITIALIZE_OUTPUT(UnityGI, gi); gi.indirect.diffuse = 0; gi.indirect.specular = 0; #if !defined(LIGHTMAP_ON) gi.light.color = _LightColor0.rgb; gi.light.dir = lightDir; gi.light.ndotl = ndotl; #endif // 构造常规函数UnityGIInput UnityGIInput giInput; UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput); giInput.light = gi.light; giInput.worldPos = worldPos; giInput.atten = atten; #ifndef LIGHTMAP_OFF giInput.lightmapUV = i.lmap; #else giInput.lightmapUV = 0.0; #endif #if UNITY_SHOULD_SAMPLE_SH giInput.ambient = i.sh; #else giInput.ambient.rgb = 0.0; #endif giInput.probeHDR[0] = unity_SpecCube0_HDR; giInput.probeHDR[1] = unity_SpecCube1_HDR; #if UNITY_SPECCUBE_BLENDING || UNITY_SPECCUBE_BOX_PROJECTION giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending #endif #if UNITY_SPECCUBE_BOX_PROJECTION giInput.boxMax[0] = unity_SpecCube0_BoxMax; giInput.probePosition[0] = unity_SpecCube0_ProbePosition; giInput.boxMax[1] = unity_SpecCube1_BoxMax; giInput.boxMin[1] = unity_SpecCube1_BoxMin; giInput.probePosition[1] = unity_SpecCube1_ProbePosition; #endif // 计算最终UnityGI gi = UnityGlobalIllumination(giInput, 1.0, worldNormal); // 相当于LightingBlinnPhong(o, worldViewDir, gi); fixed3 albedo = color; color = LambertLight(albedo, ndotl, gi.light); // 不会使用分离贴图处理 #if defined(DIRLIGHTMAP_SEPARATE) #ifdef LIGHTMAP_ON color += LambertLight (albedo, ndotl, gi.light2); #endif #ifdef DYNAMICLIGHTMAP_ON color += LambertLight (albedo, ndotl, gi.light3); #endif #endif #ifdef UNITY_LIGHT_FUNCTION_APPLY_INDIRECT color += albedo * gi.indirect.diffuse; #endif return color; } #define GET_UNITY_GI_COLOR \ half3 worldPos = GetWorldPos(i); \ half3 lightDir = GetLightDir(worldPos); \ fixed ndotl = LambertTerm(worldNormal, lightDir); \ half atten = SHADOW_ATTENUATION(i); \ fixed3 giColor = GetUnityGiColorFull(c.rgb, i, worldNormal, worldPos, lightDir, ndotl, atten) #endif