@@ -344,16 +344,36 @@ VS_OUT FixedFuncVS( VS_IN In )
344344 return Out;
345345}
346346
347- bool IsExperimentalShader () {
347+ bool ShaderUsesTerrainInfoTexture () {
348348 // The tile value basically says how often the texture gets repeated on the map.
349349 // A value less than one doesn't make sense under normal conditions, so it is
350350 // relatively save to use it as our switch.
351+ // We use the upper layer slot to store the terrain info texture, so we don't need
352+ // the tile value for anything else.
351353
352- // in order to trigger this you can set the albedo scale to be bigger than the map
353- // size. Use the value 10000 to be safe for any map
354+ // In order to trigger this you need to set the albedo scale to be bigger than the
355+ // map size in the editor . Use the value 10000 to be safe for any map
354356 return UpperAlbedoTile.x < 1.0 ;
355357}
356358
359+ bool ShaderUsesPbrRendering () {
360+ // The tile value basically says how often the texture gets repeated on the map.
361+ // A value less than one doesn't make sense under normal conditions, so it is
362+ // relatively save to use it as our switch.
363+ // We use the stratum 7 normal slot to store the roughness texture, so we don't need
364+ // the tile value for anything else.
365+
366+ // In order to trigger this you need to set the normal scale to be bigger than the
367+ // map size in the editor. Use the value 10000 to be safe for any map
368+ return Stratum7NormalTile.x < 1.0 ;
369+ }
370+
371+ bool MapUsesAdvancedWater () {
372+ // LightingMultiplier is one of the few variables that is driven by the map,
373+ // but accessible by the mesh shader.
374+ return LightingMultiplier > 2.1 ;
375+ }
376+
357377// sample a texture that is another buffer the same size as the one
358378// we are rendering into and with the viewport setup the same way.
359379float4 SampleScreen (sampler inSampler, float4 inTex)
@@ -388,35 +408,29 @@ float ComputeShadow( float4 vShadowCoord )
388408 return tex2D ( ShadowSampler, vShadowCoord ).g;
389409}
390410
391- // apply the water color
392- float3 ApplyWaterColor (float terrainHeight, float waterDepth, float3 color)
411+ float3 ApplyWaterColor (float3 viewDirection, float terrainHeight, float waterDepth, float3 color)
393412{
394413 if (waterDepth > 0 ) {
395414 // With this extra check we get rid of unwanted coloration on steep cliffs when zoomed in,
396415 // but we prevent that terrain tesselation swallows too much of the water when zoomed out
397416 float opacity = saturate (smoothstep (10 , 200 , CameraPosition.y - WaterElevation) + step (terrainHeight, WaterElevation));
398- float4 waterColor = tex1D (WaterRampSampler, waterDepth);
399- color = lerp (color.xyz, waterColor.rgb, waterColor.a * opacity);
400- }
401- return color;
402- }
403-
404- float3 ApplyWaterColorExponentially (float3 viewDirection, float terrainHeight, float waterDepth, float3 color)
405- {
406- if (waterDepth > 0 ) {
407- float opacity = saturate (smoothstep (10 , 200 , CameraPosition.y - WaterElevation) + step (terrainHeight, WaterElevation));
408- float3 up = float3 (0 ,1 ,0 );
409- // this is the length that the light travels underwater back to the camera
410- float oneOverCosV = 1 / max (dot (up, normalize (viewDirection)), 0.0001 );
411- // Light gets absorbed exponentially,
412- // to simplify, we assume that the light enters vertically into the water.
413- // We need to multiply by 2 to reach 98% absorption as the waterDepth can't go over 1.
414- float waterAbsorption = 1 - saturate (exp (-waterDepth * 2 * (1 + oneOverCosV)));
415- // darken the color first to simulate the light absorption on the way in and out
416- color *= 1 - waterAbsorption * opacity;
417- // lerp in the watercolor to simulate the scattered light from the dirty water
418- float4 waterColor = tex1D (WaterRampSampler, waterAbsorption);
419- color = lerp (color, waterColor.rgb, waterAbsorption * opacity);
417+ if (MapUsesAdvancedWater ()) {
418+ float3 up = float3 (0 ,1 ,0 );
419+ // this is the length that the light travels underwater back to the camera
420+ float oneOverCosV = 1 / max (dot (up, normalize (viewDirection)), 0.0001 );
421+ // Light gets absorbed exponentially,
422+ // to simplify, we assume that the light enters vertically into the water.
423+ // We need to multiply by 2 to reach 98% absorption as the waterDepth can't go over 1.
424+ float waterAbsorption = 1 - saturate (exp (-waterDepth * 2 * (1 + oneOverCosV)));
425+ // darken the color first to simulate the light absorption on the way in and out
426+ color *= 1 - waterAbsorption * opacity;
427+ // lerp in the watercolor to simulate the scattered light from the dirty water
428+ float4 waterColor = tex1D (WaterRampSampler, waterAbsorption);
429+ color = lerp (color, waterColor.rgb, waterAbsorption * opacity);
430+ } else {
431+ float4 waterColor = tex1D (WaterRampSampler, waterDepth);
432+ color = lerp (color, waterColor.rgb, waterColor.a * opacity);
433+ }
420434 }
421435 return color;
422436}
@@ -427,10 +441,10 @@ float4 CalculateLighting( float3 inNormal, float3 worldTerrain, float3 inAlbedo,
427441 float4 color = float4 ( 0 , 0 , 0 , 0 );
428442
429443 float shadow = ( inShadows && ( 1 == ShadowsEnabled ) ) ? ComputeShadow (shadowCoords) : 1 ;
430- if (IsExperimentalShader ()) {
444+ if (ShaderUsesTerrainInfoTexture ()) {
431445 float3 position = TerrainScale * worldTerrain;
432- float mapShadow = tex2D (UpperAlbedoSampler, position.xy).w;
433- shadow = shadow * mapShadow ;
446+ float terrainShadow = tex2D (UpperAlbedoSampler, position.xy).w;
447+ shadow = shadow * terrainShadow ;
434448 }
435449
436450 // calculate some specular
@@ -444,11 +458,7 @@ float4 CalculateLighting( float3 inNormal, float3 worldTerrain, float3 inAlbedo,
444458 light = LightingMultiplier * light + ShadowFillColor * ( 1 - light );
445459 color.rgb = light * inAlbedo;
446460
447- if (IsExperimentalShader ()) {
448- color.rgb = ApplyWaterColorExponentially (-viewDirection, worldTerrain.z, waterDepth, color);
449- } else {
450- color.rgb = ApplyWaterColor (worldTerrain.z, waterDepth, color);
451- }
461+ color.rgb = ApplyWaterColor (-viewDirection, worldTerrain.z, waterDepth, color);
452462
453463 color.a = 0.01f + (specular*SpecularColor.w);
454464 return color;
@@ -494,14 +504,14 @@ float GeometrySmith(float3 n, float nDotV, float3 l, float roughness)
494504 return gs1 * gs2;
495505}
496506
497- float3 PBR (VS_OUTPUT inV, float4 position, float3 albedo, float3 n, float roughness, float waterDepth) {
507+ float3 PBR (VS_OUTPUT inV, float3 albedo, float3 n, float roughness, float waterDepth) {
498508 // See https://blog.selfshadow.com/publications/s2013-shading-course/
499509
500510 float shadow = 1 ;
501511 if (ShadowsEnabled == 1 ) {
502- float mapShadow = tex2D (UpperAlbedoSampler, position.xy ).w; // 1 where sun is, 0 where shadow is
512+ float terrainShadow = tex2D (UpperAlbedoSampler, TerrainScale * inV.mTexWT ).w; // 1 where sun is, 0 where shadow is
503513 shadow = tex2D (ShadowSampler, inV.mShadow.xy).g; // 1 where sun is, 0 where shadow is
504- shadow *= mapShadow ;
514+ shadow *= terrainShadow ;
505515 }
506516
507517 float facingSpecular = 0.04 ;
@@ -839,7 +849,7 @@ float4 TerrainBasisPS( VS_OUTPUT inV ) : COLOR
839849float4 TerrainBasisPSBiCubic ( VS_OUTPUT inV ) : COLOR
840850{
841851 float4 result;
842- if (IsExperimentalShader ()) {
852+ if (ShaderUsesTerrainInfoTexture ()) {
843853 float4 position = TerrainScale * inV.mTexWT;
844854 result = (float4 (1 , 1 , tex2D (UpperAlbedoSampler, position.xy).xy));
845855 } else {
@@ -959,7 +969,7 @@ float4 TerrainAlbedoXP( VS_OUTPUT pixel) : COLOR
959969 albedo.rgb = light * ( albedo.rgb + specular.rgb );
960970
961971 float waterDepth = tex2D (UtilitySamplerC,pixel.mTexWT*TerrainScale).g;
962- albedo.rgb = ApplyWaterColor (pixel.mTexWT.z, waterDepth, albedo.rgb);
972+ albedo.rgb = ApplyWaterColor (-pixel.mViewDirection, pixel.mTexWT.z, waterDepth, albedo.rgb);
963973
964974 return float4 (albedo.rgb, 0.01f );
965975}
@@ -1339,7 +1349,13 @@ float4 DecalsPS( VS_OUTPUT inV, uniform bool inShadows) : COLOR
13391349
13401350 float waterDepth = tex2Dproj (UtilitySamplerC, inV.mTexWT * TerrainScale).g;
13411351
1342- float3 color = CalculateLighting (normal, inV.mTexWT.xyz, decalAlbedo.xyz, decalSpec.r, waterDepth, inV.mShadow, inShadows).xyz;
1352+ float3 color;
1353+ // We want the decals to behave consistently with the rest of the ground
1354+ if (ShaderUsesPbrRendering ()) {
1355+ color = PBR (inV, decalAlbedo.rgb, normal, 0.9 * (1 -decalSpec.r), waterDepth);
1356+ } else {
1357+ color = CalculateLighting (normal, inV.mTexWT.xyz, decalAlbedo.xyz, decalSpec.r, waterDepth, inV.mShadow, inShadows).xyz;
1358+ }
13431359
13441360 return float4 (color.rgb, decalAlbedo.w * decalMask.w * DecalAlpha);
13451361}
@@ -2021,11 +2037,11 @@ float4 TerrainPBRAlbedoPS ( VS_OUTPUT inV) : COLOR
20212037 float roughness = saturate (albedo.a * mask1.w * 2 + 0.01 );
20222038
20232039 float waterDepth = tex2D (UpperAlbedoSampler, position.xy).b;
2024- float3 color = PBR (inV, position, albedo, normal, roughness, waterDepth);
2025- color = ApplyWaterColorExponentially (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, color);
2040+ float3 color = PBR (inV, albedo, normal, roughness, waterDepth);
2041+ color = ApplyWaterColor (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, color);
20262042
20272043 return float4 (color, 0.01f );
2028- // SpecularColor.ba, LowerNormalTile, Stratum7AlbedoTile and Stratum7NormalTile are unused now
2044+ // SpecularColor.ba, LowerNormalTile and Stratum7AlbedoTile are unused now
20292045 // Candidates for configurable values are the rotation matrix values
20302046}
20312047
@@ -2169,14 +2185,14 @@ float4 Terrain001AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
21692185
21702186 // x = normals-x
21712187 // y = normals-z
2172- // z = unused
2188+ // z = water depth
21732189 // w = shadows
2174- float4 utility = tex2D (UpperAlbedoSampler, coordinates.xy);
2175- float mapShadow = utility .w;
2190+ float4 terrainInfo = tex2D (UpperAlbedoSampler, coordinates.xy);
2191+ float terrainShadow = terrainInfo .w;
21762192
21772193 // disable shadows when game settings tell us to
21782194 if (0 == ShadowsEnabled) {
2179- mapShadow = 1.0f ;
2195+ terrainShadow = 1.0f ;
21802196 }
21812197
21822198 // sample the albedo's
@@ -2203,7 +2219,7 @@ float4 Terrain001AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
22032219
22042220 // compute the shadows, combining the baked and dynamic shadows
22052221 float shadow = tex2D (ShadowSampler, inV.mShadow.xy).g; // 1 where sun is, 0 where shadow is
2206- shadow = shadow * mapShadow ;
2222+ shadow = shadow * terrainShadow ;
22072223
22082224 // normalize the pre-computed normal
22092225 float3 normal = normalize (2 * SampleScreen (NormalSampler,inV.mTexSS).xyz - 1 );
@@ -2222,13 +2238,13 @@ float4 Terrain001AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
22222238
22232239 // compute water ramp intensity
22242240 float waterDepth = tex2Dproj (UtilitySamplerC, coordinates).g;
2225- albedo.rgb = ApplyWaterColorExponentially (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, albedo.rgb);
2241+ albedo.rgb = ApplyWaterColor (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, albedo.rgb);
22262242
22272243 return float4 (albedo.rgb, 0.01f );
22282244}
22292245
22302246/* # Similar to TTerrainXP, but upperAlbedo is used for map-wide #
2231- # textures and we use better water color calculations. #
2247+ # textures. #
22322248 # It is designed to be a drop-in replacement for TTerrainXP. # */
22332249technique Terrain001 <
22342250 string usage = "composite" ;
@@ -2395,14 +2411,14 @@ float4 Terrain003AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
23952411
23962412 // x = normals-x
23972413 // y = normals-z
2398- // z = unused
2414+ // z = water depth
23992415 // w = shadows
2400- float4 utility01 = tex2D (UpperAlbedoSampler, coordinates.xy);
2401- float mapShadow = utility01 .w;
2416+ float4 terrainInfo = tex2D (UpperAlbedoSampler, coordinates.xy);
2417+ float terrainShadow = terrainInfo .w;
24022418
24032419 // disable shadows when game settings tell us to
24042420 if (0 == ShadowsEnabled) {
2405- mapShadow = 1.0f ;
2421+ terrainShadow = 1.0f ;
24062422 }
24072423
24082424 // x = specular
@@ -2437,7 +2453,7 @@ float4 Terrain003AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
24372453
24382454 // compute the shadows, combining the baked and dynamic shadows
24392455 float shadow = tex2D (ShadowSampler, inV.mShadow.xy).g;
2440- shadow = shadow * mapShadow ;
2456+ shadow = shadow * terrainShadow ;
24412457
24422458 // normalize the pre-computed normal
24432459 float3 normal = normalize (2 * SampleScreen (NormalSampler,inV.mTexSS).xyz - 1 );
@@ -2456,7 +2472,7 @@ float4 Terrain003AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
24562472
24572473 // compute water ramp intensity
24582474 float waterDepth = tex2D (UtilitySamplerC, coordinates).g;
2459- albedo.rgb = ApplyWaterColorExponentially (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, albedo.rgb);
2475+ albedo.rgb = ApplyWaterColor (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, albedo.rgb);
24602476
24612477 return float4 (albedo.rgb, 0.01f );
24622478}
@@ -2615,8 +2631,8 @@ float4 Terrain101AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
26152631 float roughness = saturate (albedo.a * mask1.w * 2 + 0.01 );
26162632
26172633 float waterDepth = tex2D (UpperAlbedoSampler, position.xy).b;
2618- float3 color = PBR (inV, position, albedo, normal, roughness, waterDepth);
2619- color = ApplyWaterColorExponentially (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, color);
2634+ float3 color = PBR (inV, albedo, normal, roughness, waterDepth);
2635+ color = ApplyWaterColor (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, color);
26202636
26212637 return float4 (color, 0.01f );
26222638}
@@ -2800,8 +2816,8 @@ float4 Terrain301AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
28002816 float roughness = saturate (albedo.a * mask1.w * 2 + 0.01 );
28012817
28022818 float waterDepth = tex2D (UpperAlbedoSampler, position.xy).b;
2803- float3 color = PBR (inV, position, albedo, normal, roughness, waterDepth);
2804- color = ApplyWaterColorExponentially (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, color);
2819+ float3 color = PBR (inV, albedo, normal, roughness, waterDepth);
2820+ color = ApplyWaterColor (-1 * inV.mViewDirection, inV.mTexWT.z, waterDepth, color);
28052821
28062822 return float4 (color, 0.01f );
28072823}
0 commit comments