#ifndef UNITY_STANDARD_CORE_INCLUDED #define UNITY_STANDARD_CORE_INCLUDED #include "UnityCG.cginc" #include "UnityShaderVariables.cginc" #include "UnityInstancing.cginc" #include "UnityStandardConfig.cginc" #include "UnityStandardInput.cginc" #include "UnityPBSLighting.cginc" #include "UnityStandardUtils.cginc" #include "UnityStandardBRDF.cginc" #include "AutoLight.cginc" //------------------------------------------------------------------------------------- // counterpart for NormalizePerPixelNormal // skips normalization per-vertex and expects normalization to happen per-pixel half3 NormalizePerVertexNormal (float3 n) // takes float to avoid overflow { #if (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE return normalize(n); #else return n; // will normalize per-pixel instead #endif } half3 NormalizePerPixelNormal (half3 n) { #if (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE return n; #else return normalize(n); #endif } //------------------------------------------------------------------------------------- UnityLight MainLight (half3 normalWorld) { UnityLight l; #ifdef LIGHTMAP_OFF l.color = _LightColor0.rgb; l.dir = _WorldSpaceLightPos0.xyz; l.ndotl = LambertTerm (normalWorld, l.dir); #else // no light specified by the engine // analytical light might be extracted from Lightmap data later on in the shader depending on the Lightmap type l.color = half3(0.f, 0.f, 0.f); l.ndotl = 0.f; l.dir = half3(0.f, 0.f, 0.f); #endif return l; } UnityLight AdditiveLight (half3 normalWorld, half3 lightDir, half atten) { UnityLight l; l.color = _LightColor0.rgb; l.dir = lightDir; #ifndef USING_DIRECTIONAL_LIGHT l.dir = NormalizePerPixelNormal(l.dir); #endif l.ndotl = LambertTerm (normalWorld, l.dir); // shadow the light l.color *= atten; return l; } UnityLight DummyLight (half3 normalWorld) { UnityLight l; l.color = 0; l.dir = half3 (0,1,0); l.ndotl = LambertTerm (normalWorld, l.dir); return l; } UnityIndirect ZeroIndirect () { UnityIndirect ind; ind.diffuse = 0; ind.specular = 0; return ind; } //------------------------------------------------------------------------------------- // Common fragment setup // deprecated half3 WorldNormal(half4 tan2world[3]) { return normalize(tan2world[2].xyz); } // deprecated #ifdef _TANGENT_TO_WORLD half3x3 ExtractTangentToWorldPerPixel(half4 tan2world[3]) { half3 t = tan2world[0].xyz; half3 b = tan2world[1].xyz; half3 n = tan2world[2].xyz; #if UNITY_TANGENT_ORTHONORMALIZE n = NormalizePerPixelNormal(n); // ortho-normalize Tangent t = normalize (t - n * dot(t, n)); // recalculate Binormal half3 newB = cross(n, t); b = newB * sign (dot (newB, b)); #endif return half3x3(t, b, n); } #else half3x3 ExtractTangentToWorldPerPixel(half4 tan2world[3]) { return half3x3(0,0,0,0,0,0,0,0,0); } #endif half3 PerPixelWorldNormal(float4 i_tex, half4 tangentToWorld[3]) { #ifdef _NORMALMAP half3 tangent = tangentToWorld[0].xyz; half3 binormal = tangentToWorld[1].xyz; half3 normal = tangentToWorld[2].xyz; #if UNITY_TANGENT_ORTHONORMALIZE normal = NormalizePerPixelNormal(normal); // ortho-normalize Tangent tangent = normalize (tangent - normal * dot(tangent, normal)); // recalculate Binormal half3 newB = cross(normal, tangent); binormal = newB * sign (dot (newB, binormal)); #endif half3 normalTangent = NormalInTangentSpace(i_tex); half3 normalWorld = NormalizePerPixelNormal(tangent * normalTangent.x + binormal * normalTangent.y + normal * normalTangent.z); // @TODO: see if we can squeeze this normalize on SM2.0 as well #else half3 normalWorld = normalize(tangentToWorld[2].xyz); #endif return normalWorld; } #ifdef _PARALLAXMAP #define IN_VIEWDIR4PARALLAX(i) NormalizePerPixelNormal(half3(i.tangentToWorldAndParallax[0].w,i.tangentToWorldAndParallax[1].w,i.tangentToWorldAndParallax[2].w)) #define IN_VIEWDIR4PARALLAX_FWDADD(i) NormalizePerPixelNormal(i.viewDirForParallax.xyz) #else #define IN_VIEWDIR4PARALLAX(i) half3(0,0,0) #define IN_VIEWDIR4PARALLAX_FWDADD(i) half3(0,0,0) #endif //adam-begin: #if 1 //UNITY_SPECCUBE_BOX_PROJECTION || UNITY_LIGHT_PROBE_PROXY_VOLUME || defined(_SKINNED_MESH) //adam-end: #define IN_WORLDPOS(i) i.posWorld #else #define IN_WORLDPOS(i) half3(0,0,0) #endif #define IN_LIGHTDIR_FWDADD(i) half3(i.tangentToWorldAndLightDir[0].w, i.tangentToWorldAndLightDir[1].w, i.tangentToWorldAndLightDir[2].w) #define FRAGMENT_SETUP(x) FragmentCommonData x = \ FragmentSetup(i.tex, i.eyeVec, IN_VIEWDIR4PARALLAX(i), i.tangentToWorldAndParallax, IN_WORLDPOS(i)); #define FRAGMENT_SETUP_FWDADD(x) FragmentCommonData x = \ FragmentSetup(i.tex, i.eyeVec, IN_VIEWDIR4PARALLAX_FWDADD(i), i.tangentToWorldAndLightDir, half3(0,0,0)); struct FragmentCommonData { half3 diffColor, specColor; // Note: oneMinusRoughness & oneMinusReflectivity for optimization purposes, mostly for DX9 SM2.0 level. // Most of the math is being done on these (1-x) values, and that saves a few precious ALU slots. half oneMinusReflectivity, oneMinusRoughness; half3 normalWorld, eyeVec, posWorld; half alpha; #if UNITY_OPTIMIZE_TEXCUBELOD || UNITY_STANDARD_SIMPLE half3 reflUVW; #endif #if UNITY_STANDARD_SIMPLE half3 tangentSpaceNormal; #endif }; #ifndef UNITY_SETUP_BRDF_INPUT #define UNITY_SETUP_BRDF_INPUT SpecularSetup #endif inline FragmentCommonData SpecularSetup (float4 i_tex) { half4 specGloss = SpecularGloss(i_tex.xy); half3 specColor = specGloss.rgb; half oneMinusRoughness = specGloss.a; half oneMinusReflectivity; half3 diffColor = EnergyConservationBetweenDiffuseAndSpecular (Albedo(i_tex), specColor, /*out*/ oneMinusReflectivity); FragmentCommonData o = (FragmentCommonData)0; o.diffColor = diffColor; o.specColor = specColor; o.oneMinusReflectivity = oneMinusReflectivity; o.oneMinusRoughness = oneMinusRoughness; return o; } //inline FragmentCommonData MetallicSetup (float4 i_tex) //{ // half2 metallicGloss = MetallicGloss(i_tex.xy); // half metallic = metallicGloss.x; // half oneMinusRoughness = metallicGloss.y; // this is 1 minus the square root of real roughness m. // // half oneMinusReflectivity; // half3 specColor; // half3 diffColor = DiffuseAndSpecularFromMetallic (Albedo(i_tex), metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity); // // FragmentCommonData o = (FragmentCommonData)0; // o.diffColor = diffColor; // o.specColor = specColor; // o.oneMinusReflectivity = oneMinusReflectivity; // o.oneMinusRoughness = oneMinusRoughness; // return o; //} inline FragmentCommonData FragmentSetup (float4 i_tex, half3 i_eyeVec, half3 i_viewDirForParallax, half4 tangentToWorld[3], half3 i_posWorld) { i_tex = Parallax(i_tex, i_viewDirForParallax); half alpha = Alpha(i_tex.xy); #if defined(_ALPHATEST_ON) clip (alpha - _Cutoff); #endif FragmentCommonData o = UNITY_SETUP_BRDF_INPUT (i_tex); o.normalWorld = PerPixelWorldNormal(i_tex, tangentToWorld); o.eyeVec = NormalizePerPixelNormal(i_eyeVec); o.posWorld = i_posWorld; // NOTE: shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha) o.diffColor = PreMultiplyAlpha (o.diffColor, alpha, o.oneMinusReflectivity, /*out*/ o.alpha); return o; } inline UnityGI FragmentGI (FragmentCommonData s, half occlusion, half4 i_ambientOrLightmapUV, half atten, UnityLight light, bool reflections) { UnityGIInput d; d.light = light; d.worldPos = s.posWorld; d.worldViewDir = -s.eyeVec; d.atten = atten; #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON) d.ambient = 0; d.lightmapUV = i_ambientOrLightmapUV; #else d.ambient = i_ambientOrLightmapUV.rgb; d.lightmapUV = 0; #endif d.boxMax[0] = unity_SpecCube0_BoxMax; d.boxMin[0] = unity_SpecCube0_BoxMin; d.probePosition[0] = unity_SpecCube0_ProbePosition; d.probeHDR[0] = unity_SpecCube0_HDR; d.boxMax[1] = unity_SpecCube1_BoxMax; d.boxMin[1] = unity_SpecCube1_BoxMin; d.probePosition[1] = unity_SpecCube1_ProbePosition; d.probeHDR[1] = unity_SpecCube1_HDR; if(reflections) { Unity_GlossyEnvironmentData g; g.roughness = 1 - s.oneMinusRoughness; #if UNITY_OPTIMIZE_TEXCUBELOD || UNITY_STANDARD_SIMPLE g.reflUVW = s.reflUVW; #else g.reflUVW = reflect(s.eyeVec, s.normalWorld); #endif return UnityGlobalIllumination (d, occlusion, s.normalWorld, g); } else { return UnityGlobalIllumination (d, occlusion, s.normalWorld); } } inline UnityGI FragmentGI (FragmentCommonData s, half occlusion, half4 i_ambientOrLightmapUV, half atten, UnityLight light) { return FragmentGI(s, occlusion, i_ambientOrLightmapUV, atten, light, true); } //------------------------------------------------------------------------------------- half4 OutputForward (half4 output, half alphaFromSurface) { #if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON) output.a = alphaFromSurface; #else UNITY_OPAQUE_ALPHA(output.a); #endif return output; } inline half4 VertexGIForward(VertexInput v, float3 posWorld, half3 normalWorld) { half4 ambientOrLightmapUV = 0; // Static lightmaps #ifndef LIGHTMAP_OFF ambientOrLightmapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; ambientOrLightmapUV.zw = 0; // Sample light probe for Dynamic objects only (no static or dynamic lightmaps) #elif UNITY_SHOULD_SAMPLE_SH #ifdef VERTEXLIGHT_ON // Approximated illumination from non-important point lights ambientOrLightmapUV.rgb = 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, posWorld, normalWorld); #endif ambientOrLightmapUV.rgb = ShadeSHPerVertex (normalWorld, ambientOrLightmapUV.rgb); #endif #ifdef DYNAMICLIGHTMAP_ON ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; #endif return ambientOrLightmapUV; } // ------------------------------------------------------------------ // Base forward pass (directional light, emission, lightmaps, ...) struct VertexOutputForwardBase { float4 pos : SV_POSITION; float4 tex : TEXCOORD0; half3 eyeVec : TEXCOORD1; half4 tangentToWorldAndParallax[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] half4 ambientOrLightmapUV : TEXCOORD5; // SH or Lightmap UV SHADOW_COORDS(6) UNITY_FOG_COORDS(7) // next ones would not fit into SM2.0 limits, but they are always for SM3.0+ //adam-begin: #if 1 //UNITY_SPECCUBE_BOX_PROJECTION || UNITY_LIGHT_PROBE_PROXY_VOLUME //adam-end: float3 posWorld : TEXCOORD8; #endif #if UNITY_OPTIMIZE_TEXCUBELOD #if UNITY_SPECCUBE_BOX_PROJECTION half3 reflUVW : TEXCOORD9; #else half3 reflUVW : TEXCOORD8; #endif #endif //adam-begin: shader additions half vertexOcclusion : TEXCOORD10; #if PLANE_REFLECTION_USER_CLIPPLANE float clipDistance : SV_ClipDistance; #endif //adam-end: }; VertexOutputForwardBase vertForwardBase (VertexInput v) { UNITY_SETUP_INSTANCE_ID(v); VertexOutputForwardBase o; UNITY_INITIALIZE_OUTPUT(VertexOutputForwardBase, o); float4 posWorld = mul(unity_ObjectToWorld, v.vertex); //adam-begin: #if 1 //UNITY_SPECCUBE_BOX_PROJECTION || UNITY_LIGHT_PROBE_PROXY_VOLUME o.posWorld = posWorld.xyz; #endif //adam-end: o.pos = UnityObjectToClipPos(v.vertex); o.tex = TexCoords(v); o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos); float3 normalWorld = UnityObjectToWorldNormal(v.normal); #ifdef _TANGENT_TO_WORLD float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w); o.tangentToWorldAndParallax[0].xyz = tangentToWorld[0]; o.tangentToWorldAndParallax[1].xyz = tangentToWorld[1]; o.tangentToWorldAndParallax[2].xyz = tangentToWorld[2]; #else o.tangentToWorldAndParallax[0].xyz = 0; o.tangentToWorldAndParallax[1].xyz = 0; o.tangentToWorldAndParallax[2].xyz = normalWorld; #endif //We need this for shadow receving TRANSFER_SHADOW(o); o.ambientOrLightmapUV = VertexGIForward(v, posWorld, normalWorld); #ifdef _PARALLAXMAP TANGENT_SPACE_ROTATION; half3 viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex)); o.tangentToWorldAndParallax[0].w = viewDirForParallax.x; o.tangentToWorldAndParallax[1].w = viewDirForParallax.y; o.tangentToWorldAndParallax[2].w = viewDirForParallax.z; #endif #if UNITY_OPTIMIZE_TEXCUBELOD o.reflUVW = reflect(o.eyeVec, normalWorld); #endif //adam-begin: shader additions o.vertexOcclusion = v.color.a; #if PLANE_REFLECTION_USER_CLIPPLANE o.clipDistance = dot(posWorld, _PlaneReflectionClipPlane); #endif //adam-end: UNITY_TRANSFER_FOG(o,o.pos); return o; } half4 fragForwardBaseInternal (VertexOutputForwardBase i) { FRAGMENT_SETUP(s) #if UNITY_OPTIMIZE_TEXCUBELOD s.reflUVW = i.reflUVW; #endif UnityLight mainLight = MainLight (s.normalWorld); half atten = SHADOW_ATTENUATION(i); //adam-begin: pass vertex occlusion to occlusion input function half occlusion = Occlusion(i.tex.xy, i.vertexOcclusion); //adam-end: UnityGI gi = FragmentGI (s, occlusion, i.ambientOrLightmapUV, atten, mainLight); half4 c = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect); c.rgb += UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, occlusion, gi); c.rgb += Emission(i.tex.xy); UNITY_APPLY_FOG(i.fogCoord, c.rgb); return OutputForward (c, s.alpha); } half4 fragForwardBase (VertexOutputForwardBase i) : SV_Target // backward compatibility (this used to be the fragment entry function) { return fragForwardBaseInternal(i); } // ------------------------------------------------------------------ // Additive forward pass (one light per pass) struct VertexOutputForwardAdd { float4 pos : SV_POSITION; float4 tex : TEXCOORD0; half3 eyeVec : TEXCOORD1; half4 tangentToWorldAndLightDir[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:lightDir] LIGHTING_COORDS(5,6) UNITY_FOG_COORDS(7) // next ones would not fit into SM2.0 limits, but they are always for SM3.0+ #if defined(_PARALLAXMAP) half3 viewDirForParallax : TEXCOORD8; #endif //adam-begin: #if PLANE_REFLECTION_USER_CLIPPLANE float clipDistance : SV_ClipDistance; #endif //adam-end: }; VertexOutputForwardAdd vertForwardAdd (VertexInput v) { VertexOutputForwardAdd o; UNITY_INITIALIZE_OUTPUT(VertexOutputForwardAdd, o); float4 posWorld = mul(unity_ObjectToWorld, v.vertex); o.pos = UnityObjectToClipPos(v.vertex); o.tex = TexCoords(v); o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos); float3 normalWorld = UnityObjectToWorldNormal(v.normal); #ifdef _TANGENT_TO_WORLD float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w); o.tangentToWorldAndLightDir[0].xyz = tangentToWorld[0]; o.tangentToWorldAndLightDir[1].xyz = tangentToWorld[1]; o.tangentToWorldAndLightDir[2].xyz = tangentToWorld[2]; #else o.tangentToWorldAndLightDir[0].xyz = 0; o.tangentToWorldAndLightDir[1].xyz = 0; o.tangentToWorldAndLightDir[2].xyz = normalWorld; #endif //We need this for shadow receiving TRANSFER_VERTEX_TO_FRAGMENT(o); float3 lightDir = _WorldSpaceLightPos0.xyz - posWorld.xyz * _WorldSpaceLightPos0.w; #ifndef USING_DIRECTIONAL_LIGHT lightDir = NormalizePerVertexNormal(lightDir); #endif o.tangentToWorldAndLightDir[0].w = lightDir.x; o.tangentToWorldAndLightDir[1].w = lightDir.y; o.tangentToWorldAndLightDir[2].w = lightDir.z; #ifdef _PARALLAXMAP TANGENT_SPACE_ROTATION; o.viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex)); #endif //adam-begin: #if PLANE_REFLECTION_USER_CLIPPLANE o.clipDistance = dot(posWorld, _PlaneReflectionClipPlane); #endif //adam-end: UNITY_TRANSFER_FOG(o,o.pos); return o; } half4 fragForwardAddInternal (VertexOutputForwardAdd i) { FRAGMENT_SETUP_FWDADD(s) UnityLight light = AdditiveLight (s.normalWorld, IN_LIGHTDIR_FWDADD(i), LIGHT_ATTENUATION(i)); UnityIndirect noIndirect = ZeroIndirect (); half4 c = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, light, noIndirect); UNITY_APPLY_FOG_COLOR(i.fogCoord, c.rgb, half4(0,0,0,0)); // fog towards black in additive pass return OutputForward (c, s.alpha); } half4 fragForwardAdd (VertexOutputForwardAdd i) : SV_Target // backward compatibility (this used to be the fragment entry function) { return fragForwardAddInternal(i); } // ------------------------------------------------------------------ // Deferred pass struct VertexOutputDeferred { float4 pos : SV_POSITION; float4 tex : TEXCOORD0; half3 eyeVec : TEXCOORD1; half4 tangentToWorldAndParallax[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] half4 ambientOrLightmapUV : TEXCOORD5; // SH or Lightmap UVs //adam-begin: #if 1 //UNITY_SPECCUBE_BOX_PROJECTION || UNITY_LIGHT_PROBE_PROXY_VOLUME //adam-end: float3 posWorld : TEXCOORD6; #endif #if UNITY_OPTIMIZE_TEXCUBELOD #if UNITY_SPECCUBE_BOX_PROJECTION half3 reflUVW : TEXCOORD7; #else half3 reflUVW : TEXCOORD6; #endif #endif //adam-begin: half vertexOcclusion : TEXCOORD10; #if PLANE_REFLECTION_USER_CLIPPLANE float clipDistance : SV_ClipDistance; #endif //adam-end: }; VertexOutputDeferred vertDeferred(VertexInput v) { VertexOutputDeferred o; UNITY_INITIALIZE_OUTPUT(VertexOutputDeferred, o); //adam-begin: UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); float4 posWorld = mul(unity_ObjectToWorld, v.vertex); //adam-begin: #if 1 //UNITY_SPECCUBE_BOX_PROJECTION || UNITY_LIGHT_PROBE_PROXY_VOLUME || defined(_SKINNED_MESH) //adam-end: o.posWorld = posWorld; #endif //adam-begin: o.pos = mul(UNITY_MATRIX_VP, posWorld); //adam-end: o.tex = TexCoords(v); o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos); float3 normalWorld = UnityObjectToWorldNormal(v.normal); #ifdef _TANGENT_TO_WORLD float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w); o.tangentToWorldAndParallax[0].xyz = tangentToWorld[0]; o.tangentToWorldAndParallax[1].xyz = tangentToWorld[1]; o.tangentToWorldAndParallax[2].xyz = tangentToWorld[2]; #else o.tangentToWorldAndParallax[0].xyz = 0; o.tangentToWorldAndParallax[1].xyz = 0; o.tangentToWorldAndParallax[2].xyz = normalWorld; #endif o.ambientOrLightmapUV = 0; #ifndef LIGHTMAP_OFF o.ambientOrLightmapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; #elif UNITY_SHOULD_SAMPLE_SH o.ambientOrLightmapUV.rgb = ShadeSHPerVertex (normalWorld, o.ambientOrLightmapUV.rgb); #endif #ifdef DYNAMICLIGHTMAP_ON o.ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; #endif #ifdef _PARALLAXMAP TANGENT_SPACE_ROTATION; half3 viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex)); o.tangentToWorldAndParallax[0].w = viewDirForParallax.x; o.tangentToWorldAndParallax[1].w = viewDirForParallax.y; o.tangentToWorldAndParallax[2].w = viewDirForParallax.z; #endif #if UNITY_OPTIMIZE_TEXCUBELOD o.reflUVW = reflect(o.eyeVec, normalWorld); #endif //adam-begin: o.vertexOcclusion = v.color.a; #if PLANE_REFLECTION_USER_CLIPPLANE o.clipDistance = dot(posWorld, _PlaneReflectionClipPlane); #endif //adam-end: return o; } void fragDeferred ( VertexOutputDeferred i, out half4 outDiffuse : SV_Target0, // RT0: diffuse color (rgb), occlusion (a) out half4 outSpecSmoothness : SV_Target1, // RT1: spec color (rgb), smoothness (a) out half4 outNormal : SV_Target2, // RT2: normal (rgb), --unused, very low precision-- (a) out half4 outEmission : SV_Target3 // RT3: emission (rgb), --unused-- (a) ) { #if (SHADER_TARGET < 30) outDiffuse = 1; outSpecSmoothness = 1; outNormal = 0; outEmission = 0; return; #endif FRAGMENT_SETUP(s) #if UNITY_OPTIMIZE_TEXCUBELOD s.reflUVW = i.reflUVW; #endif // no analytic lights in this pass UnityLight dummyLight = DummyLight (s.normalWorld); half atten = 1; // only GI //adam-begin: pass vertex occlusion to occlusion input function half occlusion = Occlusion(i.tex.xy, i.vertexOcclusion); //adam-end: #if UNITY_ENABLE_REFLECTION_BUFFERS bool sampleReflectionsInDeferred = false; #else bool sampleReflectionsInDeferred = true; #endif UnityGI gi = FragmentGI (s, occlusion, i.ambientOrLightmapUV, atten, dummyLight, sampleReflectionsInDeferred); half3 color = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect).rgb; color += UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, occlusion, gi); #ifdef _EMISSION color += Emission (i.tex.xy); #endif #ifndef UNITY_HDR_ON color.rgb = exp2(-color.rgb); #endif outDiffuse = half4(s.diffColor, occlusion); outSpecSmoothness = half4(s.specColor, s.oneMinusRoughness); outNormal = half4(s.normalWorld*0.5+0.5,1); outEmission = half4(color, 1); } // // Old FragmentGI signature. Kept only for backward compatibility and will be removed soon // inline UnityGI FragmentGI( float3 posWorld, half occlusion, half4 i_ambientOrLightmapUV, half atten, half oneMinusRoughness, half3 normalWorld, half3 eyeVec, UnityLight light, bool reflections) { // we init only fields actually used FragmentCommonData s = (FragmentCommonData)0; s.oneMinusRoughness = oneMinusRoughness; s.normalWorld = normalWorld; s.eyeVec = eyeVec; s.posWorld = posWorld; #if UNITY_OPTIMIZE_TEXCUBELOD s.reflUVW = reflect(eyeVec, normalWorld); #endif return FragmentGI(s, occlusion, i_ambientOrLightmapUV, atten, light, reflections); } inline UnityGI FragmentGI ( float3 posWorld, half occlusion, half4 i_ambientOrLightmapUV, half atten, half oneMinusRoughness, half3 normalWorld, half3 eyeVec, UnityLight light) { return FragmentGI (posWorld, occlusion, i_ambientOrLightmapUV, atten, oneMinusRoughness, normalWorld, eyeVec, light, true); } #endif // UNITY_STANDARD_CORE_INCLUDED