Jack,
I have attached a version of your 16 texture megasplat version. I'm only using 8 textures for this test version, so I have adjusted it for what I am using. You should be able to piece it back together easily enough.
I get 80FPS with Normal Parrallax, 100 FPS with just Normal Mapping and 140 FPS with no normal mapping.
Let me know if you get a chance to mess around with it. BTW, I am using a 4K sized atlas texture, and I get no seams.
ps file
#version 120
uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D texture2;
varying highp vec3 posVarying;
varying mediump vec3 normalVarying;
varying highp vec2 uvVarying;
varying highp vec2 uv1Varying;
varying mediump vec3 lightVarying;
varying mediump vec3 TangentViewPos;
varying mediump vec3 TangentLightPos;
varying mediump vec3 TangentFragPos;
uniform vec2 agk_resolution;
mediump vec3 GetPSLighting( mediump vec3 normal, highp vec3 pos );
mediump vec3 ApplyFog( mediump vec3 color, highp vec3 pointPos );
mediump vec4 blend(mediump vec4 TextureA, float a1, mediump vec4 TextureB, float a2);
mediump vec2 ParallaxMapping( mediump vec2 uvCoord, vec3 viewDir, mediump sampler2D heightMap );
lowp float tx = 0.0;
lowp float ty = 0.0;
mediump vec4 splatMap;
mediump vec4 Color;
mediump vec3 normalMap;
mediump vec3 ambient;
mediump vec3 halfwayDir;
mediump vec3 specular;
mediump vec2 texCoords0;
void main()
{
float diff;
float spec;
vec2 newuv;
vec3 viewDir = normalize( TangentViewPos - TangentFragPos );
viewDir = normalize(viewDir);
vec3 lightDir = normalize( TangentLightPos - TangentFragPos );
lightDir = normalize(lightDir);
float slope = 1.0-normalVarying.y;
float slopeblend = clamp( (slope/.5)*1.7, 0.0, 1.0 );
//texCoords0 = ParallaxMapping( uvVarying, viewDir, texture2 );
//Color = texture2D(texture2, texCoords0);
ty = 0.0; //1st row
splatMap = texture2D(texture0, uvVarying);
if (splatMap.g > 0.001) {
tx = 0.0; //first column
newuv.x = tx + (fract(uv1Varying.x * 4.0) * 0.25);
newuv.y = ty + (fract(uv1Varying.y * 4.0) * 0.25);
texCoords0 = ParallaxMapping( newuv, viewDir, texture1 );
if(texCoords0.x > .2499) texCoords0.x = .2499;
if(texCoords0.y > .2499) texCoords0.y = .2499;
if(texCoords0.x < .0001) texCoords0.x = .0001;
if(texCoords0.y < .0001) texCoords0.y = .0001;
mediump vec4 greenColor = texture2D(texture1, texCoords0);
newuv.y = .25 + (fract(newuv.y * 4.0) * 0.25);
texCoords0 = ParallaxMapping( newuv, viewDir, texture1 );
if(texCoords0.x > .2499) texCoords0.x = .2499;
if(texCoords0.y > .4999) texCoords0.y = .4999;
if(texCoords0.x < .0001) texCoords0.x = .0001;
if(texCoords0.y < .2501) texCoords0.y = .2501;
ambient = 0.1 * greenColor.rgb;
normalMap = texture2D(texture1, texCoords0).rgb;
normalMap = normalize(normalMap*2.0-1.0);
diff = max(dot(lightDir, normalMap), 0.0);
greenColor = diff*greenColor;
//spec
halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normalMap, halfwayDir), 0.0), 32.0);
specular = vec3(0.2) * spec;
greenColor = greenColor+vec4(specular,1.0)+vec4(ambient,1.0);
Color = blend(Color,(1.0-splatMap.g), greenColor,splatMap.g);
}
if (splatMap.r > 0.001) {
tx = 0.25; //second column
newuv.x = tx + (fract(uv1Varying.x * 4.0) * 0.25);
newuv.y = ty + (fract(uv1Varying.y * 4.0) * 0.25);
texCoords0 = ParallaxMapping( newuv, viewDir, texture1 );
if(texCoords0.x > .4999) texCoords0.x = .4999;
if(texCoords0.y > .2499) texCoords0.y = .2499;
if(texCoords0.x < .2501) texCoords0.x = .2501;
if(texCoords0.y < .0001) texCoords0.y = .0001;
mediump vec4 redColor = texture2D(texture1, texCoords0);
newuv.y = .25 + (fract(newuv.y * 4.0) * 0.25);
texCoords0 = ParallaxMapping( newuv, viewDir, texture1 );
if(texCoords0.x > .4999) texCoords0.x = .4999;
if(texCoords0.y > .4999) texCoords0.y = .4999;
if(texCoords0.x < .2501) texCoords0.x = .2501;
if(texCoords0.y < .2501) texCoords0.y = .2501;
ambient = 0.25 * redColor.rgb;
normalMap = texture2D(texture1, texCoords0).rgb;
normalMap = normalize(normalMap*2.0-1.0);
diff = max(dot(lightDir, normalMap), 0.0);
redColor = diff*redColor;
//spec
halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normalMap, halfwayDir), 0.0), 32.0);
specular = vec3(0.2) * spec;
redColor = redColor+vec4(specular,1.0)+vec4(ambient,1.0);
Color = blend(Color,(1.0-splatMap.r), redColor,splatMap.r);
}
if (splatMap.b > 0.0001) {
tx = 0.5; //3rd column
newuv.x = tx + (fract(uv1Varying.x * 4.0) * 0.25);
newuv.y = ty + (fract(uv1Varying.y * 4.0) * 0.25);
texCoords0 = ParallaxMapping( newuv, viewDir, texture1 );
if(texCoords0.x > .7499) texCoords0.x = .7499;
if(texCoords0.y > .2499) texCoords0.y = .2499;
if(texCoords0.x < .5001) texCoords0.x = .5001;
if(texCoords0.y < .0001) texCoords0.y = .0001;
mediump vec4 blueColor = texture2D(texture1, texCoords0);
newuv.y = .25 + (fract(newuv.y * 4.0) * 0.25);
texCoords0 = ParallaxMapping( newuv, viewDir, texture1 );
if(texCoords0.x > .74999) texCoords0.x = .74999;
if(texCoords0.y > .4999) texCoords0.y = .4999;
if(texCoords0.x < .5001) texCoords0.x = .5001;
if(texCoords0.y < .2501) texCoords0.y = .2501;
ambient = 0.1 * blueColor.rgb;
normalMap = texture2D(texture1, texCoords0).rgb;
normalMap = normalize(normalMap*2.0-1.0);
diff = max(dot(lightDir, normalMap), 0.0);
blueColor = diff*blueColor;
//spec
halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normalMap, halfwayDir), 0.0), 32.0);
specular = vec3(0.2) * spec;
blueColor = blueColor+vec4(specular,1.0)+vec4(ambient,1.0);
Color = blend(Color,(1.0-splatMap.b), blueColor,splatMap.b);
}
if (slopeblend > .0001) {
tx = 0.75;
newuv.x = tx + (fract(uv1Varying.x * 4.0) * 0.25);
newuv.y = ty + (fract(uv1Varying.y * 4.0) * 0.25);
texCoords0 = ParallaxMapping( newuv, viewDir, texture1 );
if(texCoords0.x > .9999) texCoords0.x = .9999;
if(texCoords0.y > .2499) texCoords0.y = .2499;
if(texCoords0.x < .7501) texCoords0.x = .7501;
if(texCoords0.y < .0001) texCoords0.y = .0001;
mediump vec4 steepColor = texture2D(texture1, texCoords0);
newuv.y = .25 + (fract(newuv.y * 4.0) * 0.25);
texCoords0 = ParallaxMapping( newuv, viewDir, texture1 );
if(texCoords0.x > .9999) texCoords0.x = .9999;
if(texCoords0.y > .4999) texCoords0.y = .4999;
if(texCoords0.x < .7501) texCoords0.x = .7501;
if(texCoords0.y < .2501) texCoords0.y = .2501;
ambient = 0.1 * steepColor.rgb;
normalMap = texture2D(texture1, texCoords0).rgb;
normalMap = normalize(normalMap*2.0-1.0);
diff = max(dot(lightDir, normalMap), 0.0);
steepColor = diff*steepColor;
//spec
halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normalMap, halfwayDir), 0.0), 32.0);
specular = vec3(0.2) * spec;
steepColor = steepColor+vec4(specular,1.0)+vec4(ambient,1.0);
Color = blend(Color,(1.0-slopeblend), steepColor,slopeblend);
}
if (posVarying.y < -.65)
{
Color = mix( Color, vec4(0.1098, .6627, .7882, 1.0), clamp(abs((posVarying.y+.65))/1.0, 0.0, 1.0 ) );
}
mediump vec3 norm = normalize(normalVarying);
mediump vec3 light = lightVarying + GetPSLighting( norm, posVarying );
Color.rgb = ApplyFog( Color.rgb * light, posVarying );
// final output
gl_FragColor = Color;
}
mediump vec4 blend(mediump vec4 TextureA, float a1, mediump vec4 TextureB, float a2)
{
float depth = 0.2;
float ma = max(TextureA.a + a1, TextureB.a + a2) - depth;
float b1 = max(TextureA.a + a1 - ma, 0);
float b2 = max(TextureB.a + a2 - ma, 0);
return (TextureA.rgba * b1 + TextureB.rgba * b2) / (b1 + b2);
}
vec2 ParallaxMapping( mediump vec2 texCoords, mediump vec3 viewDir, mediump sampler2D heightMap )
{
vec2 ScaleBias = vec2(0.02, 0.01);
float height = texture2D(heightMap, texCoords).a;
float HSB = height * ScaleBias.x - ScaleBias.y;
vec2 textOffset = texCoords + (viewDir.xy * HSB)*.25;
return textOffset;
}
vs file
#version 120
attribute highp vec3 position;
attribute mediump vec3 normal;
attribute mediump vec2 uv;
varying highp vec3 posVarying;
varying mediump vec3 TangentViewPos;
varying mediump vec3 TangentLightPos;
varying mediump vec3 TangentFragPos;
varying mediump vec3 normalVarying;
varying highp vec2 uvVarying;
varying highp vec2 uv1Varying;
varying mediump vec3 lightVarying;
mediump vec3 GetVSLighting( mediump vec3 normal, highp vec3 pos );
uniform highp mat3 agk_WorldNormal;
uniform highp mat4 agk_World;
uniform highp mat4 agk_ViewProj;
uniform mediump vec3 agk_CameraPos;
uniform mediump vec4 uvBounds0;
uniform mediump vec4 uvBounds1;
uniform mediump vec4 uvBounds2;
uniform mediump vec4 uvBounds3;
uniform mediump vec4 uvBounds4;
uniform mediump vec4 uvBounds5;
void main()
{
uvVarying = uv * uvBounds0.xy + uvBounds0.zw;
uv1Varying = uv * uvBounds1.xy + uvBounds1.zw;
highp vec4 pos = agk_World * vec4(position,1.0);
gl_Position = agk_ViewProj * pos;
mediump vec3 norm = normalize(agk_WorldNormal * normal);
posVarying = pos.xyz;
normalVarying = norm;
lightVarying = GetVSLighting( norm, posVarying );
mediump vec3 Normal = normalize(normal*2.0-1.0);
mediump vec3 tangent;
if ( length(c1) > length(c2) ) { tangent = c1; } else { tangent = c2;}
tangent = normalize(tangent);
vec3 T = normalize(mat3(agk_World)*tangent);
vec3 N = normalize(mat3(agk_World)*normal);
T = normalize(T-dot(T,N)*N);
mediump vec3 binormal = normalize(cross(N, T));
vec3 B = normalize(mat3(agk_World)*binormal);
mediump mat3 TBN = transpose(mat3( T, B, N ));
TangentViewPos = TBN*agk_CameraPos;
TangentLightPos = TBN*vec3(20.0,45.0,-75.0);//(agk_CameraPos+vec3(-5.0,40.0,-30.0) );
TangentFragPos = TBN*posVarying;
}
edit: I made a typo on the TBN matrix. Also added 'the Gram-Schmidt process". Source: https://learnopengl.com/Advanced-Lighting/Normal-Mapping