Skip to content

Commit

Permalink
Rotate every other texture layer (FAForever#5810)
Browse files Browse the repository at this point in the history
I discovered that rotating some texture layers makes the repeating
texture pattern less visible.
Now not all textures are aligned in the same direction and the 30°
rotation from the horizonal/vertical grid also seems to make it harder
for the eye to notice repeating features.
The effect is not amazing, but it's almost free, so it still seems like
a good deal.
The only question is, on which shaders do we want to apply that?

Before:
![Screenshot 2024-01-07
015257](https://github.com/FAForever/fa/assets/52536103/358478f2-ce0b-4d33-b2bf-a7a8fdb111fa)

After:
![Screenshot 2024-01-07
015310](https://github.com/FAForever/fa/assets/52536103/db69370e-aa1e-4571-8c1f-2ba2112fef7e)
  • Loading branch information
BlackYps authored Jun 23, 2024
1 parent 3cccc10 commit 2dd88e5
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 16 deletions.
3 changes: 3 additions & 0 deletions changelog/snippets/graphics.5810.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- (#5810) Rotate every other texture layer in the Terrain301 shader

By rotating every other texture layer by 30° we can make it harder to spot texture repetition. At the moment the Terrain301 shader is only used by the Sunset biome of the map generator. Hand-made maps don't use it yet, because there is no support in the map editor.
38 changes: 22 additions & 16 deletions effects/terrain.fx
Original file line number Diff line number Diff line change
Expand Up @@ -2707,6 +2707,9 @@ technique Terrain151 <
float4 Terrain301NormalsPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
{
float4 position = TerrainScale * inV.mTexWT;
// 30° rotation
float2x2 rotationMatrix = float2x2(float2(0.866, -0.5), float2(0.5, 0.866));
position.zw = mul(position.xy, rotationMatrix);

float4 mask0 = tex2D(UtilitySamplerA, position.xy);
float4 mask1 = tex2D(UtilitySamplerB, position.xy);
Expand All @@ -2717,21 +2720,21 @@ float4 Terrain301NormalsPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
}

float3 lowerNormal = normalize(tex2D(LowerNormalSampler, position.xy * LowerAlbedoTile.xy ).rgb * 2 - 1);
float3 stratum0Normal = normalize(tex2D(Stratum0NormalSampler, position.xy * Stratum0AlbedoTile.xy).rgb * 2 - 1);
float3 stratum0Normal = normalize(tex2D(Stratum0NormalSampler, position.zw * Stratum0AlbedoTile.xy).rgb * 2 - 1);
float3 stratum1Normal = normalize(tex2D(Stratum1NormalSampler, position.xy * Stratum1AlbedoTile.xy).rgb * 2 - 1);
float3 stratum2Normal = normalize(tex2D(Stratum2NormalSampler, position.xy * Stratum2AlbedoTile.xy).rgb * 2 - 1);
float3 stratum2Normal = normalize(tex2D(Stratum2NormalSampler, position.zw * Stratum2AlbedoTile.xy).rgb * 2 - 1);
float3 stratum3Normal = normalize(tex2D(Stratum3NormalSampler, position.xy * Stratum3AlbedoTile.xy).rgb * 2 - 1);
float3 stratum4Normal = normalize(tex2D(Stratum4NormalSampler, position.xy * Stratum4AlbedoTile.xy).rgb * 2 - 1);
float3 stratum4Normal = normalize(tex2D(Stratum4NormalSampler, position.zw * Stratum4AlbedoTile.xy).rgb * 2 - 1);
float3 stratum5Normal = normalize(tex2D(Stratum5NormalSampler, position.xy * Stratum5AlbedoTile.xy).rgb * 2 - 1);
float3 stratum6Normal = normalize(tex2D(Stratum6NormalSampler, position.xy * Stratum6AlbedoTile.xy).rgb * 2 - 1);
float3 stratum6Normal = normalize(tex2D(Stratum6NormalSampler, position.zw * Stratum6AlbedoTile.xy).rgb * 2 - 1);

float stratum0Height = sampleHeight(position.xy, Stratum0AlbedoTile.xy, Stratum0NormalTile.xy, float2(0.5, 0.0), true);
float stratum0Height = sampleHeight(position.zw, Stratum0AlbedoTile.xy, Stratum0NormalTile.xy, float2(0.5, 0.0), true);
float stratum1Height = sampleHeight(position.xy, Stratum1AlbedoTile.xy, Stratum1NormalTile.xy, float2(0.0, 0.5), true);
float stratum2Height = sampleHeight(position.xy, Stratum2AlbedoTile.xy, Stratum2NormalTile.xy, float2(0.5, 0.5), true);
float stratum2Height = sampleHeight(position.zw, Stratum2AlbedoTile.xy, Stratum2NormalTile.xy, float2(0.5, 0.5), true);
float stratum3Height = sampleHeight(position.xy, Stratum3AlbedoTile.xy, Stratum3NormalTile.xy, float2(0.0, 0.0), false);
float stratum4Height = sampleHeight(position.xy, Stratum4AlbedoTile.xy, Stratum4NormalTile.xy, float2(0.5, 0.0), false);
float stratum4Height = sampleHeight(position.zw, Stratum4AlbedoTile.xy, Stratum4NormalTile.xy, float2(0.5, 0.0), false);
float stratum5Height = sampleHeight(position.xy, Stratum5AlbedoTile.xy, Stratum5NormalTile.xy, float2(0.0, 0.5), false);
float stratum6Height = sampleHeight(position.xy, Stratum6AlbedoTile.xy, Stratum6NormalTile.xy, float2(0.5, 0.5), false);
float stratum6Height = sampleHeight(position.zw, Stratum6AlbedoTile.xy, Stratum6NormalTile.xy, float2(0.5, 0.5), false);

float3 normal = lowerNormal;
normal = splatBlendNormal(normal, stratum0Normal, stratum0Height, mask0.x, SpecularColor.r);
Expand All @@ -2749,6 +2752,9 @@ float4 Terrain301AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR
{
// height is now in the z coordinate
float4 position = TerrainScale * inV.mTexWT;
// 30° rotation
float2x2 rotationMatrix = float2x2(float2(0.866, -0.5), float2(0.5, 0.866));
position.zw = mul(position.xy, rotationMatrix);

// do arithmetics to get range from (0, 1) to (-1, 1) as normal maps store their values as (0, 1)
float3 normal = normalize(2 * SampleScreen(NormalSampler,inV.mTexSS).xyz - 1);
Expand All @@ -2763,21 +2769,21 @@ float4 Terrain301AlbedoPS ( VS_OUTPUT inV, uniform bool halfRange ) : COLOR

// This shader wouldn't compile because it would have to store too many variables if we didn't use this trick in the vertex shader
float4 lowerAlbedo = sampleAlbedo(LowerAlbedoSampler, position.xy, LowerAlbedoTile.xy, float2(0.0, 0.0), true);
float4 stratum0Albedo = sampleAlbedo(Stratum0AlbedoSampler, position.xy, inV.nearScales.xx, float2(0.5, 0.0), true);
float4 stratum0Albedo = sampleAlbedo(Stratum0AlbedoSampler, position.zw, inV.nearScales.xx, float2(0.5, 0.0), true);
float4 stratum1Albedo = sampleAlbedo(Stratum1AlbedoSampler, position.xy, inV.nearScales.yy, float2(0.0, 0.5), true);
float4 stratum2Albedo = sampleAlbedo(Stratum2AlbedoSampler, position.xy, inV.nearScales.zz, float2(0.5, 0.5), true);
float4 stratum2Albedo = sampleAlbedo(Stratum2AlbedoSampler, position.zw, inV.nearScales.zz, float2(0.5, 0.5), true);
float4 stratum3Albedo = sampleAlbedo(Stratum3AlbedoSampler, position.xy, inV.nearScales.ww, float2(0.0, 0.0), false);
float4 stratum4Albedo = sampleAlbedo(Stratum4AlbedoSampler, position.xy, Stratum4AlbedoTile.xy, float2(0.5, 0.0), false);
float4 stratum4Albedo = sampleAlbedo(Stratum4AlbedoSampler, position.zw, Stratum4AlbedoTile.xy, float2(0.5, 0.0), false);
float4 stratum5Albedo = sampleAlbedo(Stratum5AlbedoSampler, position.xy, Stratum5AlbedoTile.xy, float2(0.0, 0.5), false);
float4 stratum6Albedo = sampleAlbedo(Stratum6AlbedoSampler, position.xy, Stratum6AlbedoTile.xy, float2(0.5, 0.5), false);
float4 stratum6Albedo = sampleAlbedo(Stratum6AlbedoSampler, position.zw, Stratum6AlbedoTile.xy, float2(0.5, 0.5), false);

float stratum0Height = sampleHeight(position.xy, inV.nearScales.xx, inV.farScales.xx, float2(0.5, 0.0), true);
float stratum0Height = sampleHeight(position.zw, inV.nearScales.xx, inV.farScales.xx, float2(0.5, 0.0), true);
float stratum1Height = sampleHeight(position.xy, inV.nearScales.yy, inV.farScales.yy, float2(0.0, 0.5), true);
float stratum2Height = sampleHeight(position.xy, inV.nearScales.zz, inV.farScales.zz, float2(0.5, 0.5), true);
float stratum2Height = sampleHeight(position.zw, inV.nearScales.zz, inV.farScales.zz, float2(0.5, 0.5), true);
float stratum3Height = sampleHeight(position.xy, inV.nearScales.ww, inV.farScales.ww, float2(0.0, 0.0), false);
float stratum4Height = sampleHeight(position.xy, Stratum4AlbedoTile.xy, Stratum4NormalTile.xy, float2(0.5, 0.0), false);
float stratum4Height = sampleHeight(position.zw, Stratum4AlbedoTile.xy, Stratum4NormalTile.xy, float2(0.5, 0.0), false);
float stratum5Height = sampleHeight(position.xy, Stratum5AlbedoTile.xy, Stratum5NormalTile.xy, float2(0.0, 0.5), false);
float stratum6Height = sampleHeight(position.xy, Stratum6AlbedoTile.xy, Stratum6NormalTile.xy, float2(0.5, 0.5), false);
float stratum6Height = sampleHeight(position.zw, Stratum6AlbedoTile.xy, Stratum6NormalTile.xy, float2(0.5, 0.5), false);

float4 albedo = lowerAlbedo;
albedo = splatLerp(albedo, stratum0Albedo, stratum0Height, mask0.x, SpecularColor.r);
Expand Down

0 comments on commit 2dd88e5

Please sign in to comment.