#ifndef BAKERY_INCLUDED #define BAKERY_INCLUDED float bakeryLightmapMode; //float2 bakeryLightmapSize; #define BAKERYMODE_DEFAULT 0 #define BAKERYMODE_VERTEXLM 1.0f #define BAKERYMODE_RNM 2.0f #define BAKERYMODE_SH 3.0f //#define BAKERY_SSBUMP //#define BAKERY_COMPRESSED_VOLUME_RGBM // can't fit vertexLM SH to sm3_0 interpolators #if defined(SHADER_API_GLCORE) || defined(SHADER_API_GLES) || defined(SHADER_API_D3D11_9X) #undef BAKERY_VERTEXLMSH #endif // can't do stuff on sm2_0 due to standard shader alrady taking up all instructions #if SHADER_TARGET < 30 #undef BAKERY_BICUBIC #undef BAKERY_LMSPEC #undef BAKERY_RNM #undef BAKERY_SH #undef BAKERY_MONOSH #undef BAKERY_VERTEXLM #endif #ifndef _NORMALMAP #undef BAKERY_RNM //#undef BAKERY_SH #endif #ifndef UNITY_SHOULD_SAMPLE_SH #undef BAKERY_PROBESHNONLINEAR #endif #if defined(BAKERY_RNM) && defined(BAKERY_LMSPEC) #define BAKERY_RNMSPEC #endif #ifndef BAKERY_VERTEXLM #undef BAKERY_VERTEXLMDIR #undef BAKERY_VERTEXLMSH #undef BAKERY_VERTEXLMMASK #endif #define lumaConv float3(0.2125f, 0.7154f, 0.0721f) #if defined(BAKERY_SH) || defined(BAKERY_MONOSH) || defined(BAKERY_VERTEXLMSH) || defined(BAKERY_PROBESHNONLINEAR) || defined(BAKERY_VOLUME) float shEvaluateDiffuseL1Geomerics(float L0, float3 L1, float3 n) { // average energy float R0 = L0; // avg direction of incoming light float3 R1 = 0.5f * L1; // directional brightness float lenR1 = length(R1); // linear angle between normal and direction 0-1 //float q = 0.5f * (1.0f + dot(R1 / lenR1, n)); //float q = dot(R1 / lenR1, n) * 0.5 + 0.5; float q = dot(normalize(R1), n) * 0.5 + 0.5; // power for q // lerps from 1 (linear) to 3 (cubic) based on directionality float p = 1.0f + 2.0f * lenR1 / R0; // dynamic range constant // should vary between 4 (highly directional) and 0 (ambient) float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0); return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p)); } #endif #ifdef BAKERY_VERTEXLM float4 unpack4NFloats(float src) { //return fmod(float4(src / 262144.0, src / 4096.0, src / 64.0, src), 64.0)/64.0; return frac(float4(src / (262144.0*64), src / (4096.0*64), src / (64.0*64), src)); } float3 unpack3NFloats(float src) { float r = frac(src); float g = frac(src * 256.0); float b = frac(src * 65536.0); return float3(r, g, b); } #if defined(BAKERY_VERTEXLMDIR) #ifdef BAKERY_MONOSH void BakeryVertexLMMonoSH(inout float3 diffuseColor, inout float3 specularColor, float3 nL1, float3 normalWorld, float3 viewDir, float smoothness) { nL1 = nL1; float3 L0 = diffuseColor; float3 L1x = nL1.x * L0 * 2; float3 L1y = nL1.y * L0 * 2; float3 L1z = nL1.z * L0 * 2; float3 sh; #if BAKERY_SHNONLINEAR //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); float lumaL0 = dot(L0, 1); float lumaL1x = dot(L1x, 1); float lumaL1y = dot(L1y, 1); float lumaL1z = dot(L1z, 1); float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; float regularLumaSH = dot(sh, 1); //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); #else sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; #endif diffuseColor = max(sh, 0.0); #ifdef BAKERY_LMSPEC float3 dominantDir = nL1; float focus = saturate(length(dominantDir)); half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); half nh = saturate(dot(normalWorld, halfDir)); half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); half spec = GGXTerm(nh, roughness); specularColor = max(spec * sh, 0.0); #endif } #endif void BakeryVertexLMDirection(inout float3 diffuseColor, inout float3 specularColor, float3 lightDirection, float3 vertexNormalWorld, float3 normalWorld, float3 viewDir, float smoothness) { float3 dominantDir = Unity_SafeNormalize(lightDirection); half halfLambert = dot(normalWorld, dominantDir) * 0.5 + 0.5; half flatNormalHalfLambert = dot(vertexNormalWorld, dominantDir) * 0.5 + 0.5; #ifdef BAKERY_LMSPEC half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); half nh = saturate(dot(normalWorld, halfDir)); half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); half spec = GGXTerm(nh, roughness); specularColor = spec * diffuseColor; #endif diffuseColor *= halfLambert / max(1e-4h, flatNormalHalfLambert); } #elif defined(BAKERY_VERTEXLMSH) void BakeryVertexLMSH(inout float3 diffuseColor, inout float3 specularColor, float3 shL1x, float3 shL1y, float3 shL1z, float3 normalWorld, float3 viewDir, float smoothness) { float3 L0 = diffuseColor; float3 nL1x = shL1x; float3 nL1y = shL1y; float3 nL1z = shL1z; float3 L1x = nL1x * L0 * 2; float3 L1y = nL1y * L0 * 2; float3 L1z = nL1z * L0 * 2; float3 sh; #if BAKERY_SHNONLINEAR //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); float lumaL0 = dot(L0, 1); float lumaL1x = dot(L1x, 1); float lumaL1y = dot(L1y, 1); float lumaL1z = dot(L1z, 1); float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; float regularLumaSH = dot(sh, 1); //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); #else sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; #endif diffuseColor = max(sh, 0.0); #ifdef BAKERY_LMSPEC float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); float focus = saturate(length(dominantDir)); half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); half nh = saturate(dot(normalWorld, halfDir)); half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); half spec = GGXTerm(nh, roughness); specularColor = max(spec * sh, 0.0); #endif } #endif #endif #ifdef BAKERY_BICUBIC float BakeryBicubic_w0(float a) { return (1.0f/6.0f)*(a*(a*(-a + 3.0f) - 3.0f) + 1.0f); } float BakeryBicubic_w1(float a) { return (1.0f/6.0f)*(a*a*(3.0f*a - 6.0f) + 4.0f); } float BakeryBicubic_w2(float a) { return (1.0f/6.0f)*(a*(a*(-3.0f*a + 3.0f) + 3.0f) + 1.0f); } float BakeryBicubic_w3(float a) { return (1.0f/6.0f)*(a*a*a); } float BakeryBicubic_g0(float a) { return BakeryBicubic_w0(a) + BakeryBicubic_w1(a); } float BakeryBicubic_g1(float a) { return BakeryBicubic_w2(a) + BakeryBicubic_w3(a); } float BakeryBicubic_h0(float a) { return -1.0f + BakeryBicubic_w1(a) / (BakeryBicubic_w0(a) + BakeryBicubic_w1(a)) + 0.5f; } float BakeryBicubic_h1(float a) { return 1.0f + BakeryBicubic_w3(a) / (BakeryBicubic_w2(a) + BakeryBicubic_w3(a)) + 0.5f; } #endif struct BakeryVertexInput { float4 vertex : POSITION; #ifdef BAKERY_VERTEXLM fixed4 color : COLOR; #ifdef BAKERY_VERTEXLMSH float2 uv3 : TEXCOORD3; #endif #endif half3 normal : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; #if defined(DYNAMICLIGHTMAP_ON) || defined(UNITY_PASS_META) float2 uv2 : TEXCOORD2; #endif #if defined(_TANGENT_TO_WORLD) || defined(BAKERY_RNMSPEC) half4 tangent : TANGENT; #endif UNITY_VERTEX_INPUT_INSTANCE_ID }; float4 BakeryTexCoords(BakeryVertexInput v) { float4 texcoord; texcoord.xy = TRANSFORM_TEX(v.uv0, _MainTex); // Always source from uv0 texcoord.zw = TRANSFORM_TEX(((_UVSec == 0) ? v.uv0 : v.uv1), _DetailAlbedoMap); return texcoord; } inline half4 BakeryVertexGIForward(BakeryVertexInput 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 #ifdef BAKERY_VERTEXLM if (bakeryLightmapMode == BAKERYMODE_VERTEXLM) { #ifdef BAKERY_VERTEXLMMASK ambientOrLightmapUV = unpack4NFloats(v.uv1.x); #endif } #endif return ambientOrLightmapUV; } //Forward Pass struct BakeryVertexOutputForwardBase { float4 pos : SV_POSITION; float4 tex : TEXCOORD0; half3 eyeVec : TEXCOORD1; #if UNITY_VERSION >= 201740 float4 tangentToWorldAndPackedData[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] #else half4 tangentToWorldAndPackedData[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] #endif #if defined(BAKERY_RNMSPEC) half3 viewDirForParallax : TEXCOORD13; #endif half4 ambientOrLightmapUV : TEXCOORD5; // SH or Lightmap UV UNITY_SHADOW_COORDS(6) UNITY_FOG_COORDS(7) #ifdef BAKERY_VERTEXLM float4 color : COLOR_centroid; #if defined(BAKERY_VERTEXLMDIR) float3 lightDirection : TEXCOORD10_centroid; // is this even legal #elif defined(BAKERY_VERTEXLMSH) float3 shL1x : TEXCOORD10_centroid; float3 shL1y : TEXCOORD11_centroid; float3 shL1z : TEXCOORD12_centroid; #endif #endif // next ones would not fit into SM2.0 limits, but they are always for SM3.0+ #if UNITY_SPECCUBE_BOX_PROJECTION || UNITY_LIGHT_PROBE_PROXY_VOLUME || (UNITY_REQUIRE_FRAG_WORLDPOS && !UNITY_PACK_WORLDPOS_WITH_TANGENT) float3 posWorld : TEXCOORD8; #endif #if UNITY_OPTIMIZE_TEXCUBELOD #if UNITY_SPECCUBE_BOX_PROJECTION half3 reflUVW : TEXCOORD9; #else half3 reflUVW : TEXCOORD8; #endif #endif UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; BakeryVertexOutputForwardBase bakeryVertForwardBase(BakeryVertexInput v) { UNITY_SETUP_INSTANCE_ID(v); BakeryVertexOutputForwardBase o; UNITY_INITIALIZE_OUTPUT(BakeryVertexOutputForwardBase, o); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); float4 posWorld = mul(unity_ObjectToWorld, v.vertex); #if UNITY_REQUIRE_FRAG_WORLDPOS #if UNITY_PACK_WORLDPOS_WITH_TANGENT o.tangentToWorldAndPackedData[0].w = posWorld.x; o.tangentToWorldAndPackedData[1].w = posWorld.y; o.tangentToWorldAndPackedData[2].w = posWorld.z; #else o.posWorld = posWorld.xyz; #endif #endif o.pos = UnityObjectToClipPos(v.vertex); float3 normalWorld = UnityObjectToWorldNormal(v.normal); o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos); o.tex = BakeryTexCoords(v); #ifdef _TANGENT_TO_WORLD float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w); o.tangentToWorldAndPackedData[0].xyz = tangentToWorld[0]; o.tangentToWorldAndPackedData[1].xyz = tangentToWorld[1]; o.tangentToWorldAndPackedData[2].xyz = tangentToWorld[2]; #else o.tangentToWorldAndPackedData[0].xyz = 0; o.tangentToWorldAndPackedData[1].xyz = 0; o.tangentToWorldAndPackedData[2].xyz = normalWorld; #endif //We need this for shadow receving UNITY_TRANSFER_SHADOW(o, v.uv1); o.ambientOrLightmapUV = BakeryVertexGIForward(v, posWorld, normalWorld); #if defined(_PARALLAXMAP) || defined(BAKERY_RNMSPEC) TANGENT_SPACE_ROTATION; #endif #if defined(_PARALLAXMAP) half3 viewDirForParallax = mul(rotation, ObjSpaceViewDir(v.vertex)); o.tangentToWorldAndPackedData[0].w = viewDirForParallax.x; o.tangentToWorldAndPackedData[1].w = viewDirForParallax.y; o.tangentToWorldAndPackedData[2].w = viewDirForParallax.z; #endif #if defined(BAKERY_RNMSPEC) o.viewDirForParallax = mul(rotation, ObjSpaceViewDir(v.vertex)); #endif #if UNITY_OPTIMIZE_TEXCUBELOD o.reflUVW = reflect(o.eyeVec, normalWorld); #endif #ifdef BAKERY_VERTEXLM // Unpack from RGBM o.color = v.color; o.color.rgb *= o.color.a * 8.0f; o.color.rgb *= o.color.rgb; #if defined(BAKERY_VERTEXLMDIR) o.lightDirection = unpack3NFloats(v.uv1.y) * 2 - 1; #elif defined(BAKERY_VERTEXLMSH) o.shL1x = unpack3NFloats(v.uv1.y) * 2 - 1; o.shL1y = unpack3NFloats(v.uv3.x) * 2 - 1; o.shL1z = unpack3NFloats(v.uv3.y) * 2 - 1; #endif #endif UNITY_TRANSFER_FOG(o, o.pos); return o; } /* inline UnityGI BakeryFragmentGI (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.probeHDR[0] = unity_SpecCube0_HDR; d.probeHDR[1] = unity_SpecCube1_HDR; #if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION) d.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending #endif #ifdef UNITY_SPECCUBE_BOX_PROJECTION d.boxMax[0] = unity_SpecCube0_BoxMax; d.probePosition[0] = unity_SpecCube0_ProbePosition; d.boxMax[1] = unity_SpecCube1_BoxMax; d.boxMin[1] = unity_SpecCube1_BoxMin; d.probePosition[1] = unity_SpecCube1_ProbePosition; #endif if(reflections) { Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup(s.smoothness, -s.eyeVec, s.normalWorld, s.specColor); // Replace the reflUVW if it has been compute in Vertex shader. Note: the compiler will optimize the calcul in UnityGlossyEnvironmentSetup itself #if UNITY_STANDARD_SIMPLE g.reflUVW = s.reflUVW; #endif return UnityGlobalIllumination (d, occlusion, s.normalWorld, g); } else { return UnityGlobalIllumination (d, occlusion, s.normalWorld); } } */ #if defined(BAKERY_RNM) || defined(BAKERY_SH) sampler2D _RNM0, _RNM1, _RNM2; float4 _RNM0_TexelSize; #endif #if UNITY_VERSION >= 201740 SamplerState bakery_trilinear_clamp_sampler; #endif #ifdef BAKERY_VOLUME Texture3D _Volume0, _Volume1, _Volume2, _VolumeMask; SamplerState sampler_Volume0; float3 _VolumeMin, _VolumeInvSize; float3 _GlobalVolumeMin, _GlobalVolumeInvSize; #ifdef BAKERY_COMPRESSED_VOLUME Texture3D _Volume3; #endif #ifdef BAKERY_VOLROTATION float4x4 _GlobalVolumeMatrix, _VolumeMatrix; #endif #endif #ifdef BAKERY_BICUBIC // Bicubic float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) { float x = uv.x * texelSize.z; float y = uv.y * texelSize.z; x -= 0.5f; y -= 0.5f; float px = floor(x); float py = floor(y); float fx = x - px; float fy = y - py; float g0x = BakeryBicubic_g0(fx); float g1x = BakeryBicubic_g1(fx); float h0x = BakeryBicubic_h0(fx); float h1x = BakeryBicubic_h1(fx); float h0y = BakeryBicubic_h0(fy); float h1y = BakeryBicubic_h1(fy); return BakeryBicubic_g0(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h0y) * texelSize.x)) + g1x * tex2D(tex, (float2(px + h1x, py + h0y) * texelSize.x))) + BakeryBicubic_g1(fy) * ( g0x * tex2D(tex, (float2(px + h0x, py + h1y) * texelSize.x)) + g1x * tex2D(tex, (float2(px + h1x, py + h1y) * texelSize.x))); } float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) { float x = uv.x * texelSize.z; float y = uv.y * texelSize.z; x -= 0.5f; y -= 0.5f; float px = floor(x); float py = floor(y); float fx = x - px; float fy = y - py; float g0x = BakeryBicubic_g0(fx); float g1x = BakeryBicubic_g1(fx); float h0x = BakeryBicubic_h0(fx); float h1x = BakeryBicubic_h1(fx); float h0y = BakeryBicubic_h0(fy); float h1y = BakeryBicubic_h1(fy); return BakeryBicubic_g0(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h0y) * texelSize.x)) + g1x * tex.Sample(s, (float2(px + h1x, py + h0y) * texelSize.x))) + BakeryBicubic_g1(fy) * ( g0x * tex.Sample(s, (float2(px + h0x, py + h1y) * texelSize.x)) + g1x * tex.Sample(s, (float2(px + h1x, py + h1y) * texelSize.x))); } #else // Bilinear float4 BakeryTex2D(sampler2D tex, float2 uv, float4 texelSize) { return tex2D(tex, uv); } float4 BakeryTex2D(Texture2D tex, SamplerState s, float2 uv, float4 texelSize) { return tex.Sample(s, uv); } #endif #ifdef DIRLIGHTMAP_COMBINED #ifdef BAKERY_LMSPEC float BakeryDirectionalLightmapSpecular(float2 lmUV, float3 normalWorld, float3 viewDir, float smoothness) { #if UNITY_VERSION >= 201740 float3 dominantDir = unity_LightmapInd.Sample(bakery_trilinear_clamp_sampler, lmUV).xyz * 2 - 1; #else float3 dominantDir = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lmUV).xyz * 2 - 1; #endif half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); half nh = saturate(dot(normalWorld, halfDir)); half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); half spec = GGXTerm(nh, roughness); return spec; } #endif #endif #ifdef BAKERY_RNM void BakeryRNM(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalMap, float smoothness, float3 viewDirT) { const float3 rnmBasis0 = float3(0.816496580927726f, 0, 0.5773502691896258f); const float3 rnmBasis1 = float3(-0.4082482904638631f, 0.7071067811865475f, 0.5773502691896258f); const float3 rnmBasis2 = float3(-0.4082482904638631f, -0.7071067811865475f, 0.5773502691896258f); float3 rnm0 = DecodeLightmap(BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize)); float3 rnm1 = DecodeLightmap(BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize)); float3 rnm2 = DecodeLightmap(BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize)); #ifdef BAKERY_SSBUMP diffuseColor = normalMap.x * rnm0 + normalMap.z * rnm1 + normalMap.y * rnm2; diffuseColor *= 2; #else diffuseColor = saturate(dot(rnmBasis0, normalMap)) * rnm0 + saturate(dot(rnmBasis1, normalMap)) * rnm1 + saturate(dot(rnmBasis2, normalMap)) * rnm2; #endif #ifdef BAKERY_LMSPEC float3 dominantDirT = rnmBasis0 * dot(rnm0, lumaConv) + rnmBasis1 * dot(rnm1, lumaConv) + rnmBasis2 * dot(rnm2, lumaConv); float3 dominantDirTN = NormalizePerPixelNormal(dominantDirT); float3 specColor = saturate(dot(rnmBasis0, dominantDirTN)) * rnm0 + saturate(dot(rnmBasis1, dominantDirTN)) * rnm1 + saturate(dot(rnmBasis2, dominantDirTN)) * rnm2; half3 halfDir = Unity_SafeNormalize(dominantDirTN - viewDirT); half nh = saturate(dot(normalMap, halfDir)); half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); half spec = GGXTerm(nh, roughness); specularColor = spec * specColor; #endif } #endif #ifdef BAKERY_SH void BakerySH(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalWorld, float3 viewDir, float smoothness) { /* #ifdef SHADER_API_D3D11 #if UNITY_VERSION >= 201740 float3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, bakery_trilinear_clamp_sampler, lmUV, _RNM0_TexelSize)); #else float3 L0 = DecodeLightmap(BakeryTex2D(unity_Lightmap, samplerunity_Lightmap, lmUV, _RNM0_TexelSize)); #endif #else float3 L0 = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, lmUV)); #endif */ // already sampled float3 L0 = diffuseColor; float3 nL1x = BakeryTex2D(_RNM0, lmUV, _RNM0_TexelSize) * 2 - 1; float3 nL1y = BakeryTex2D(_RNM1, lmUV, _RNM0_TexelSize) * 2 - 1; float3 nL1z = BakeryTex2D(_RNM2, lmUV, _RNM0_TexelSize) * 2 - 1; float3 L1x = nL1x * L0 * 2; float3 L1y = nL1y * L0 * 2; float3 L1z = nL1z * L0 * 2; float3 sh; #if BAKERY_SHNONLINEAR float lumaL0 = dot(L0, 1); float lumaL1x = dot(L1x, 1); float lumaL1y = dot(L1y, 1); float lumaL1z = dot(L1z, 1); float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; float regularLumaSH = dot(sh, 1); //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); #else sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; #endif diffuseColor = max(sh, 0.0); specularColor = 0; #ifdef BAKERY_LMSPEC float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); float focus = saturate(length(dominantDir)); half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); half nh = saturate(dot(normalWorld, halfDir)); half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); half spec = GGXTerm(nh, roughness); sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; specularColor = max(spec * sh, 0.0); #endif } #endif #ifdef BAKERY_MONOSH void BakeryMonoSH(inout float3 diffuseColor, inout float3 specularColor, float2 lmUV, float3 normalWorld, float3 viewDir, float smoothness) { #if UNITY_VERSION >= 201740 float3 dominantDir = unity_LightmapInd.Sample(bakery_trilinear_clamp_sampler, lmUV).xyz; float3 L0 = DecodeLightmap(unity_Lightmap.Sample(bakery_trilinear_clamp_sampler, lmUV)); #else float3 dominantDir = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lmUV).xyz; float3 L0 = DecodeLightmap(UNITY_SAMPLE_TEX2D_SAMPLER(unity_Lightmap, unity_Lightmap, lmUV)); #endif float3 nL1 = dominantDir * 2 - 1; float3 L1x = nL1.x * L0 * 2; float3 L1y = nL1.y * L0 * 2; float3 L1z = nL1.z * L0 * 2; float3 sh; #if BAKERY_SHNONLINEAR float lumaL0 = dot(L0, 1); float lumaL1x = dot(L1x, 1); float lumaL1y = dot(L1y, 1); float lumaL1z = dot(L1z, 1); float lumaSH = shEvaluateDiffuseL1Geomerics(lumaL0, float3(lumaL1x, lumaL1y, lumaL1z), normalWorld); sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; float regularLumaSH = dot(sh, 1); //sh *= regularLumaSH < 0.001 ? 1 : (lumaSH / regularLumaSH); sh *= lerp(1, lumaSH / regularLumaSH, saturate(regularLumaSH*16)); //sh.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), normalWorld); //sh.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), normalWorld); //sh.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), normalWorld); #else sh = L0 + normalWorld.x * L1x + normalWorld.y * L1y + normalWorld.z * L1z; #endif diffuseColor = max(sh, 0.0); specularColor = 0; #ifdef BAKERY_LMSPEC dominantDir = nL1; float focus = saturate(length(dominantDir)); half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - viewDir); half nh = saturate(dot(normalWorld, halfDir)); half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness );//* sqrt(focus)); half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); half spec = GGXTerm(nh, roughness); sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; specularColor = max(spec * sh, 0.0); #endif } #endif half4 bakeryFragForwardBase(BakeryVertexOutputForwardBase i) : SV_Target { FRAGMENT_SETUP(s) #if UNITY_OPTIMIZE_TEXCUBELOD s.reflUVW = i.reflUVW; #endif UnityLight mainLight = MainLight (); UNITY_LIGHT_ATTENUATION(atten, i, s.posWorld); #ifdef BAKERY_VOLUME bool isGlobal = _VolumeInvSize.x > 1000000; // ~inf float3 volViewDir = s.eyeVec; #ifdef BAKERY_VOLROTATION float4x4 volMatrix = (isGlobal ? _GlobalVolumeMatrix : _VolumeMatrix); float3 volInvSize = (isGlobal ? _GlobalVolumeInvSize : _VolumeInvSize); float3 lpUV = mul(volMatrix, float4(s.posWorld,1)).xyz * volInvSize + 0.5f; float3 volNormal = mul((float3x3)volMatrix, s.normalWorld); #ifdef BAKERY_LMSPEC volViewDir = mul((float3x3)volMatrix, volViewDir); #endif #else float3 lpUV = (s.posWorld - (isGlobal ? _GlobalVolumeMin : _VolumeMin)) * (isGlobal ? _GlobalVolumeInvSize : _VolumeInvSize); float3 volNormal = s.normalWorld; #endif #endif #ifdef BAKERY_VOLUME mainLight.color *= saturate(dot(_VolumeMask.Sample(sampler_Volume0, lpUV), unity_OcclusionMaskSelector)); #elif BAKERY_VERTEXLMMASK if (bakeryLightmapMode == BAKERYMODE_VERTEXLM) { mainLight.color *= saturate(dot(i.ambientOrLightmapUV, unity_OcclusionMaskSelector)); } #endif half occlusion = Occlusion(i.tex.xy); UnityGI gi = FragmentGI(s, occlusion, i.ambientOrLightmapUV, atten, mainLight); #ifdef BAKERY_VOLUME #ifdef BAKERY_COMPRESSED_VOLUME float4 tex0, tex1, tex2, tex3; float3 L0, L1x, L1y, L1z; tex0 = _Volume0.Sample(sampler_Volume0, lpUV); tex1 = _Volume1.Sample(sampler_Volume0, lpUV) * 2 - 1; tex2 = _Volume2.Sample(sampler_Volume0, lpUV) * 2 - 1; tex3 = _Volume3.Sample(sampler_Volume0, lpUV) * 2 - 1; #ifdef BAKERY_COMPRESSED_VOLUME_RGBM L0 = tex0.xyz * (tex0.w * 8.0f); L0 *= L0; #else L0 = tex0.xyz; #endif L1x = tex1.xyz * L0; L1y = tex2.xyz * L0; L1z = tex3.xyz * L0; #else float4 tex0, tex1, tex2; float3 L0, L1x, L1y, L1z; tex0 = _Volume0.Sample(sampler_Volume0, lpUV); tex1 = _Volume1.Sample(sampler_Volume0, lpUV); tex2 = _Volume2.Sample(sampler_Volume0, lpUV); L0 = tex0.xyz; L1x = tex1.xyz; L1y = tex2.xyz; L1z = float3(tex0.w, tex1.w, tex2.w); #endif gi.indirect.diffuse.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), volNormal); gi.indirect.diffuse.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), volNormal); gi.indirect.diffuse.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), volNormal); #ifdef UNITY_COLORSPACE_GAMMA gi.indirect.diffuse = pow(gi.indirect.diffuse, 1.0f / 2.2f); #endif #ifdef BAKERY_LMSPEC float3 nL1x = L1x / L0; float3 nL1y = L1y / L0; float3 nL1z = L1z / L0; float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - volViewDir); half nh = saturate(dot(volNormal, halfDir)); half perceptualRoughness = SmoothnessToPerceptualRoughness(s.smoothness); half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); half spec = GGXTerm(nh, roughness); float3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; gi.indirect.specular += max(spec * sh, 0.0); #endif #elif BAKERY_PROBESHNONLINEAR float3 L0 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); gi.indirect.diffuse.r = shEvaluateDiffuseL1Geomerics(L0.r, unity_SHAr.xyz, s.normalWorld); gi.indirect.diffuse.g = shEvaluateDiffuseL1Geomerics(L0.g, unity_SHAg.xyz, s.normalWorld); gi.indirect.diffuse.b = shEvaluateDiffuseL1Geomerics(L0.b, unity_SHAb.xyz, s.normalWorld); #endif #ifdef DIRLIGHTMAP_COMBINED #ifdef BAKERY_LMSPEC #ifndef BAKERY_MONOSH if (bakeryLightmapMode == BAKERYMODE_DEFAULT) { gi.indirect.specular += BakeryDirectionalLightmapSpecular(i.ambientOrLightmapUV.xy, s.normalWorld, s.eyeVec, s.smoothness) * gi.indirect.diffuse; } #endif #endif #endif #ifdef BAKERY_VERTEXLM if (bakeryLightmapMode == BAKERYMODE_VERTEXLM) { gi.indirect.diffuse = i.color.rgb; float3 prevSpec = gi.indirect.specular; #if defined(BAKERY_VERTEXLMDIR) #ifdef BAKERY_MONOSH BakeryVertexLMMonoSH(gi.indirect.diffuse, gi.indirect.specular, i.lightDirection, s.normalWorld, s.eyeVec, s.smoothness); #else BakeryVertexLMDirection(gi.indirect.diffuse, gi.indirect.specular, i.lightDirection, i.tangentToWorldAndPackedData[2].xyz, s.normalWorld, s.eyeVec, s.smoothness); #endif gi.indirect.specular += prevSpec; #elif defined (BAKERY_VERTEXLMSH) BakeryVertexLMSH(gi.indirect.diffuse, gi.indirect.specular, i.shL1x, i.shL1y, i.shL1z, s.normalWorld, s.eyeVec, s.smoothness); gi.indirect.specular += prevSpec; #endif } #endif #ifdef BAKERY_RNM if (bakeryLightmapMode == BAKERYMODE_RNM) { #ifdef BAKERY_SSBUMP float3 normalMap = tex2D(_BumpMap, i.tex.xy).xyz; #else float3 normalMap = NormalInTangentSpace(i.tex); #endif float3 eyeVecT = 0; #ifdef BAKERY_LMSPEC eyeVecT = -NormalizePerPixelNormal(i.viewDirForParallax); #endif float3 prevSpec = gi.indirect.specular; BakeryRNM(gi.indirect.diffuse, gi.indirect.specular, i.ambientOrLightmapUV.xy, normalMap, s.smoothness, eyeVecT); gi.indirect.specular += prevSpec; } #endif #ifdef BAKERY_SH #if SHADER_TARGET >= 30 if (bakeryLightmapMode == BAKERYMODE_SH) #endif { float3 prevSpec = gi.indirect.specular; BakerySH(gi.indirect.diffuse, gi.indirect.specular, i.ambientOrLightmapUV.xy, s.normalWorld, s.eyeVec, s.smoothness); gi.indirect.specular += prevSpec; } #endif #ifdef DIRLIGHTMAP_COMBINED #ifdef BAKERY_MONOSH if (bakeryLightmapMode != BAKERYMODE_VERTEXLM) { float3 prevSpec = gi.indirect.specular; BakeryMonoSH(gi.indirect.diffuse, gi.indirect.specular, i.ambientOrLightmapUV.xy, s.normalWorld, s.eyeVec, s.smoothness); gi.indirect.specular += prevSpec; } #endif #endif half4 c = UNITY_BRDF_PBS(s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect); c.rgb += UNITY_BRDF_GI(s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, s.normalWorld, -s.eyeVec, occlusion, gi); c.rgb += Emission(i.tex.xy); UNITY_APPLY_FOG(i.fogCoord, c.rgb); return OutputForward(c, s.alpha); } // Additive forward pass (one light per pass) struct BakeryVertexOutputForwardAdd { float4 pos : SV_POSITION; float4 tex : TEXCOORD0; half3 eyeVec : TEXCOORD1; #if UNITY_VERSION >= 201740 float4 tangentToWorldAndLightDir[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] #else half4 tangentToWorldAndLightDir[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] #endif float3 posWorld : TEXCOORD5; UNITY_SHADOW_COORDS(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 #ifdef BAKERY_VERTEXLMMASK fixed4 shadowMask : COLOR; #endif UNITY_VERTEX_OUTPUT_STEREO }; BakeryVertexOutputForwardAdd bakeryVertForwardAdd(BakeryVertexInput v) { UNITY_SETUP_INSTANCE_ID(v); BakeryVertexOutputForwardAdd o; UNITY_INITIALIZE_OUTPUT(BakeryVertexOutputForwardAdd, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); float4 posWorld = mul(unity_ObjectToWorld, v.vertex); o.pos = UnityObjectToClipPos(v.vertex); o.tex = BakeryTexCoords(v); o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos); o.posWorld = posWorld.xyz; 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 receving UNITY_TRANSFER_SHADOW(o, v.uv1); 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 #ifdef BAKERY_VERTEXLMMASK o.shadowMask = unpack4NFloats(v.uv1.x); #endif UNITY_TRANSFER_FOG(o, o.pos); return o; } half4 bakeryFragForwardAdd(BakeryVertexOutputForwardAdd i) : SV_Target { FRAGMENT_SETUP_FWDADD(s) UNITY_LIGHT_ATTENUATION(atten, i, s.posWorld) UnityLight light = AdditiveLight (IN_LIGHTDIR_FWDADD(i), atten); UnityIndirect noIndirect = ZeroIndirect (); half4 c = UNITY_BRDF_PBS(s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, s.normalWorld, -s.eyeVec, light, noIndirect); #ifdef BAKERY_VOLUME bool isGlobal = _VolumeInvSize.x > 1000000; // ~inf #ifdef BAKERY_VOLROTATION float4x4 volMatrix = (isGlobal ? _GlobalVolumeMatrix : _VolumeMatrix); float3 volInvSize = (isGlobal ? _GlobalVolumeInvSize : _VolumeInvSize); float3 lpUV = mul(volMatrix, float4(s.posWorld,1)).xyz * volInvSize + 0.5f; #else float3 lpUV = (s.posWorld - (isGlobal ? _GlobalVolumeMin : _VolumeMin)) * (isGlobal ? _GlobalVolumeInvSize : _VolumeInvSize); #endif c *= saturate(dot(_VolumeMask.Sample(sampler_Volume0, lpUV), unity_OcclusionMaskSelector)); #elif BAKERY_VERTEXLMMASK if (bakeryLightmapMode == BAKERYMODE_VERTEXLM) { c *= saturate(dot(i.shadowMask, unity_OcclusionMaskSelector)); } #endif UNITY_APPLY_FOG_COLOR(i.fogCoord, c.rgb, half4(0,0,0,0)); // fog towards black in additive pass return OutputForward(c, s.alpha); } //Deferred Pass struct BakeryVertexOutputDeferred { float4 pos : SV_POSITION; float4 tex : TEXCOORD0; half3 eyeVec : TEXCOORD1; #if UNITY_VERSION >= 201740 float4 tangentToWorldAndPackedData[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] #else half4 tangentToWorldAndPackedData[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] #endif #if defined(BAKERY_RNMSPEC) half3 viewDirForParallax : TEXCOORD9; #endif half4 ambientOrLightmapUV : TEXCOORD5; // SH or Lightmap UVs #ifdef BAKERY_VERTEXLM fixed4 color : COLOR; #if defined(BAKERY_VERTEXLMDIR) float3 lightDirection : TEXCOORD8; #elif defined(BAKERY_VERTEXLMSH) float3 shL1x : TEXCOORD8_centroid; float3 shL1y : TEXCOORD10_centroid; float3 shL1z : TEXCOORD11_centroid; #endif #endif #if UNITY_SPECCUBE_BOX_PROJECTION || UNITY_LIGHT_PROBE_PROXY_VOLUME || (UNITY_REQUIRE_FRAG_WORLDPOS && !UNITY_PACK_WORLDPOS_WITH_TANGENT) || BAKERY_VOLUME float3 posWorld : TEXCOORD6; #endif #if UNITY_OPTIMIZE_TEXCUBELOD #if UNITY_SPECCUBE_BOX_PROJECTION half3 reflUVW : TEXCOORD7; #else half3 reflUVW : TEXCOORD6; #endif #endif UNITY_VERTEX_OUTPUT_STEREO }; BakeryVertexOutputDeferred bakeryVertDeferred(BakeryVertexInput v) { UNITY_SETUP_INSTANCE_ID(v); BakeryVertexOutputDeferred o; UNITY_INITIALIZE_OUTPUT(BakeryVertexOutputDeferred, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); float4 posWorld = mul(unity_ObjectToWorld, v.vertex); #if UNITY_SPECCUBE_BOX_PROJECTION || UNITY_LIGHT_PROBE_PROXY_VOLUME || BAKERY_VOLUME o.posWorld = posWorld; #endif o.pos = UnityObjectToClipPos(v.vertex); o.tex = BakeryTexCoords(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.tangentToWorldAndPackedData[0].xyz = tangentToWorld[0]; o.tangentToWorldAndPackedData[1].xyz = tangentToWorld[1]; o.tangentToWorldAndPackedData[2].xyz = tangentToWorld[2]; #else o.tangentToWorldAndPackedData[0].xyz = 0; o.tangentToWorldAndPackedData[1].xyz = 0; o.tangentToWorldAndPackedData[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 BAKERY_VERTEXLMMASK if (bakeryLightmapMode == BAKERYMODE_VERTEXLM) { o.ambientOrLightmapUV = unpack4NFloats(v.uv1); } #endif #if defined(_PARALLAXMAP) || defined(BAKERY_RNMSPEC) TANGENT_SPACE_ROTATION; #endif #if defined(_PARALLAXMAP) half3 viewDirForParallax = mul(rotation, ObjSpaceViewDir(v.vertex)); o.tangentToWorldAndPackedData[0].w = viewDirForParallax.x; o.tangentToWorldAndPackedData[1].w = viewDirForParallax.y; o.tangentToWorldAndPackedData[2].w = viewDirForParallax.z; #endif #if defined(BAKERY_RNMSPEC) o.viewDirForParallax = mul(rotation, ObjSpaceViewDir(v.vertex)); #endif #ifdef BAKERY_VERTEXLM // Unpack from RGBM o.color = v.color; o.color.rgb *= o.color.a * 8.0f; o.color.rgb *= o.color.rgb; #if defined(BAKERY_VERTEXLMDIR) o.lightDirection = unpack3NFloats(v.uv1.y) * 2 - 1; #elif defined(BAKERY_VERTEXLMSH) o.shL1x = unpack3NFloats(v.uv1.y) * 2 - 1; o.shL1y = unpack3NFloats(v.uv3.x) * 2 - 1; o.shL1z = unpack3NFloats(v.uv3.y) * 2 - 1; #endif #endif #if UNITY_OPTIMIZE_TEXCUBELOD o.reflUVW = reflect(o.eyeVec, normalWorld); #endif return o; } void bakeryFragDeferred( BakeryVertexOutputDeferred 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 defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4) ,out half4 outShadowMask : SV_Target4 // RT4: shadowmask (rgba) #endif ) { #if (SHADER_TARGET < 30) outDiffuse = 1; outSpecSmoothness = 1; outNormal = 0; outEmission = 0; #if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4) outShadowMask = 1; #endif return; #endif FRAGMENT_SETUP(s) #if UNITY_OPTIMIZE_TEXCUBELOD s.reflUVW = i.reflUVW; #endif // no analytic lights in this pass UnityLight dummyLight = DummyLight(); half atten = 1; // only GI half occlusion = Occlusion(i.tex.xy); #if UNITY_ENABLE_REFLECTION_BUFFERS bool sampleReflectionsInDeferred = false; #else bool sampleReflectionsInDeferred = true; #endif UnityGI gi = FragmentGI(s, occlusion, i.ambientOrLightmapUV, atten, dummyLight, sampleReflectionsInDeferred); #ifdef BAKERY_VOLUME bool isGlobal = _VolumeInvSize.x > 1000000; // ~inf float3 volViewDir = s.eyeVec; #ifdef BAKERY_VOLROTATION float4x4 volMatrix = (isGlobal ? _GlobalVolumeMatrix : _VolumeMatrix); float3 volInvSize = (isGlobal ? _GlobalVolumeInvSize : _VolumeInvSize); float3 lpUV = mul(volMatrix, float4(i.posWorld,1)).xyz * volInvSize + 0.5f; float3 volNormal = mul((float3x3)volMatrix, s.normalWorld); #ifdef BAKERY_LMSPEC volViewDir = mul((float3x3)volMatrix, volViewDir); #endif #else float3 lpUV = (i.posWorld - (isGlobal ? _GlobalVolumeMin : _VolumeMin)) * (isGlobal ? _GlobalVolumeInvSize : _VolumeInvSize); float3 volNormal = s.normalWorld; #endif #ifdef BAKERY_COMPRESSED_VOLUME float4 tex0, tex1, tex2, tex3; float3 L0, L1x, L1y, L1z; tex0 = _Volume0.Sample(sampler_Volume0, lpUV); tex1 = _Volume1.Sample(sampler_Volume0, lpUV) * 2 - 1; tex2 = _Volume2.Sample(sampler_Volume0, lpUV) * 2 - 1; tex3 = _Volume3.Sample(sampler_Volume0, lpUV) * 2 - 1; #ifdef BAKERY_COMPRESSED_VOLUME_RGBM L0 = tex0.xyz * (tex0.w * 8.0f); L0 *= L0; #else L0 = tex0.xyz; #endif L1x = tex1.xyz * L0; L1y = tex2.xyz * L0; L1z = tex3.xyz * L0; #else float4 tex0, tex1, tex2; float3 L0, L1x, L1y, L1z; tex0 = _Volume0.Sample(sampler_Volume0, lpUV); tex1 = _Volume1.Sample(sampler_Volume0, lpUV); tex2 = _Volume2.Sample(sampler_Volume0, lpUV); L0 = tex0.xyz; L1x = tex1.xyz; L1y = tex2.xyz; L1z = float3(tex0.w, tex1.w, tex2.w); #endif gi.indirect.diffuse.r = shEvaluateDiffuseL1Geomerics(L0.r, float3(L1x.r, L1y.r, L1z.r), volNormal); gi.indirect.diffuse.g = shEvaluateDiffuseL1Geomerics(L0.g, float3(L1x.g, L1y.g, L1z.g), volNormal); gi.indirect.diffuse.b = shEvaluateDiffuseL1Geomerics(L0.b, float3(L1x.b, L1y.b, L1z.b), volNormal); #ifdef UNITY_COLORSPACE_GAMMA gi.indirect.diffuse = pow(gi.indirect.diffuse, 1.0f / 2.2f); #endif #ifdef BAKERY_LMSPEC float3 nL1x = L1x / L0; float3 nL1y = L1y / L0; float3 nL1z = L1z / L0; float3 dominantDir = float3(dot(nL1x, lumaConv), dot(nL1y, lumaConv), dot(nL1z, lumaConv)); half3 halfDir = Unity_SafeNormalize(normalize(dominantDir) - volViewDir); half nh = saturate(dot(volNormal, halfDir)); half perceptualRoughness = SmoothnessToPerceptualRoughness(s.smoothness); half roughness = PerceptualRoughnessToRoughness(perceptualRoughness); half spec = GGXTerm(nh, roughness); float3 sh = L0 + dominantDir.x * L1x + dominantDir.y * L1y + dominantDir.z * L1z; gi.indirect.specular += max(spec * sh, 0.0); #endif #elif BAKERY_PROBESHNONLINEAR float3 L0 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); gi.indirect.diffuse.r = shEvaluateDiffuseL1Geomerics(L0.r, unity_SHAr.xyz, s.normalWorld); gi.indirect.diffuse.g = shEvaluateDiffuseL1Geomerics(L0.g, unity_SHAg.xyz, s.normalWorld); gi.indirect.diffuse.b = shEvaluateDiffuseL1Geomerics(L0.b, unity_SHAb.xyz, s.normalWorld); #endif #ifdef DIRLIGHTMAP_COMBINED #ifdef BAKERY_LMSPEC #ifndef BAKERY_MONOSH if (bakeryLightmapMode == BAKERYMODE_DEFAULT) { gi.indirect.specular += BakeryDirectionalLightmapSpecular(i.ambientOrLightmapUV.xy, s.normalWorld, s.eyeVec, s.smoothness) * gi.indirect.diffuse; } #endif #endif #endif #ifdef BAKERY_VERTEXLM if (bakeryLightmapMode == BAKERYMODE_VERTEXLM) { gi.indirect.diffuse = i.color.rgb; float3 prevSpec = gi.indirect.specular; #if defined(BAKERY_VERTEXLMDIR) #ifdef BAKERY_MONOSH BakeryVertexLMMonoSH(gi.indirect.diffuse, gi.indirect.specular, i.lightDirection, s.normalWorld, s.eyeVec, s.smoothness); #else BakeryVertexLMDirection(gi.indirect.diffuse, gi.indirect.specular, i.lightDirection, i.tangentToWorldAndPackedData[2].xyz, s.normalWorld, s.eyeVec, s.smoothness); #endif gi.indirect.specular += prevSpec; #elif defined (BAKERY_VERTEXLMSH) BakeryVertexLMSH(gi.indirect.diffuse, gi.indirect.specular, i.shL1x, i.shL1y, i.shL1z, s.normalWorld, s.eyeVec, s.smoothness); gi.indirect.specular += prevSpec; #endif } #endif #ifdef BAKERY_RNM if (bakeryLightmapMode == BAKERYMODE_RNM) { #ifdef BAKERY_SSBUMP float3 normalMap = tex2D(_BumpMap, i.tex.xy).xyz; #else float3 normalMap = NormalInTangentSpace(i.tex); #endif float3 eyeVecT = 0; #ifdef BAKERY_LMSPEC eyeVecT = -NormalizePerPixelNormal(i.viewDirForParallax); #endif float3 prevSpec = gi.indirect.specular; BakeryRNM(gi.indirect.diffuse, gi.indirect.specular, i.ambientOrLightmapUV.xy, normalMap, s.smoothness, eyeVecT); gi.indirect.specular += prevSpec; } #endif #ifdef BAKERY_SH #if SHADER_TARGET >= 30 if (bakeryLightmapMode == BAKERYMODE_SH) #endif { float3 prevSpec = gi.indirect.specular; BakerySH(gi.indirect.diffuse, gi.indirect.specular, i.ambientOrLightmapUV.xy, s.normalWorld, s.eyeVec, s.smoothness); gi.indirect.specular += prevSpec; } #endif #ifdef DIRLIGHTMAP_COMBINED #ifdef BAKERY_MONOSH if (bakeryLightmapMode != BAKERYMODE_VERTEXLM) { float3 prevSpec = gi.indirect.specular; BakeryMonoSH(gi.indirect.diffuse, gi.indirect.specular, i.ambientOrLightmapUV.xy, s.normalWorld, s.eyeVec, s.smoothness); gi.indirect.specular += prevSpec; } #endif #endif half3 color = UNITY_BRDF_PBS(s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect).rgb; color += UNITY_BRDF_GI(s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, 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.smoothness); outNormal = half4(s.normalWorld*0.5 + 0.5, 1); outEmission = half4(color, 1); // Baked direct lighting occlusion if any #if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4) #ifdef BAKERY_VOLUME outShadowMask = _VolumeMask.Sample(sampler_Volume0, lpUV); #elif BAKERY_VERTEXLMMASK outShadowMask = i.ambientOrLightmapUV; #else outShadowMask = UnityGetRawBakedOcclusions(i.ambientOrLightmapUV.xy, IN_WORLDPOS(i)); #endif #endif } #endif