This commit is contained in:
bart
2026-11-08 15:42:54 +01:00
parent dfd497d728
commit 5af4581182
80 changed files with 4494 additions and 437 deletions
+240 -42
View File
@@ -1,7 +1,20 @@
#version 400
uniform sampler2D tex; //this is the texture
uniform sampler2D border; //this is the texture
uniform sampler2D rock; //this is the texture
uniform sampler2D texGrass; // Unit 0
uniform sampler2D texBorder; // Unit 1
uniform sampler2D texRock; // Unit 2 (Stone cliffs)
uniform sampler2D texSand; // Unit 3 (Soil beach)
uniform sampler2D texWater; // Unit 4 (Dynamic ocean)
uniform sampler2D texSnow; // Unit 5 (Texturelabs_Water_155XL snow/ice)
uniform sampler2D texTypeMap; // Unit 6 (Biome type map)
uniform sampler2D texSahara; // Unit 7 (Texturelabs_Soil_133L desert sand)
uniform sampler2D texTundra; // Unit 8 (Texturelabs_Soil_135XL tundra soil)
uniform sampler2D texRedSand; // Unit 9 (Texturelabs_RedSand prairie sand)
uniform sampler2D texRedRock; // Unit 10 (Texturelabs_RedRock canyon cliff)
uniform sampler2D texForest; // Unit 11 (Texturelabs_Forest_seamless woodland floor)
uniform float time;
uniform int riverMask;
smooth in vec3 vNormal;
smooth in vec3 vWorldPos;
in vec3 fragVert;
@@ -10,11 +23,8 @@ uniform vec3 cameraPosition;
uniform mat4 modelMatrix;
in vec2 tilePos;
in vec2 fragTexCoord; //this is the texture coord
out vec4 finalColor; //this is the output color of the pixel
in vec2 fragTexCoord;
out vec4 finalColor;
struct SimpleDirectionalLight
{
@@ -23,55 +33,243 @@ struct SimpleDirectionalLight
float fAmbientIntensity;
};
uniform SimpleDirectionalLight sunLight;
vec4 GetDirectionalLightColor(SimpleDirectionalLight dirLight, vec3 vNormal)
vec4 GetDirectionalLightColor(SimpleDirectionalLight dirLight, vec3 norm)
{
float fDiffuseIntensity = dot(vNormal, -dirLight.vDirection);
float fMult = pow(dirLight.fAmbientIntensity+fDiffuseIntensity,1.0);//clamp(dirLight.fAmbientIntensity+fDiffuseIntensity, -1.0, 1.0);
// if(dirLight.iSkybox == 1)fMult = dirLight.fAmbientIntensity;
return vec4(dirLight.vColor*fMult, 1.0);
float fDiffuseIntensity = max(dot(norm, -dirLight.vDirection), 0.0);
float fMult = dirLight.fAmbientIntensity + fDiffuseIntensity * (1.0 - dirLight.fAmbientIntensity * 0.5);
return vec4(dirLight.vColor * fMult, 1.0);
}
vec4 GetSpecularColor(vec3 vWorldPos, vec3 vEyePos, SimpleDirectionalLight dLight, vec3 vNormal)
vec4 GetSpecularColor(vec3 worldPos, vec3 eyePos, SimpleDirectionalLight dLight, vec3 norm, float shininess, float intensity)
{
vec4 vResult = vec4(0.0, 0.0, 0.0, 0.0);
vec3 vReflectedVector = normalize(reflect(dLight.vDirection, norm));
vec3 vVertexToEyeVector = normalize(eyePos - worldPos);
float fSpecularFactor = max(dot(vVertexToEyeVector, vReflectedVector), 0.0);
vec3 vReflectedVector = normalize(reflect(dLight.vDirection, vNormal));
vec3 vVertexToEyeVector = normalize(vEyePos-vWorldPos);
float fSpecularFactor = dot(vVertexToEyeVector, vReflectedVector);
if (fSpecularFactor > 0.0)
{
fSpecularFactor = pow(fSpecularFactor, shininess);
return vec4(dLight.vColor, 1.0) * intensity * fSpecularFactor;
}
return vec4(0.0);
}
if (fSpecularFactor > 0)
{
fSpecularFactor = pow(fSpecularFactor, 1.0);
vResult = vec4(dLight.vColor, 1.0) * 1.0 * fSpecularFactor;
}
float distToSegment(vec2 p, vec2 a, vec2 b) {
vec2 ba = b - a;
vec2 pa = p - a;
float l2 = dot(ba, ba);
if (l2 <= 1e-6) return length(pa);
float h = clamp(dot(pa, ba) / l2, 0.0, 1.0);
return length(pa - ba * h);
}
return vResult;
const vec2 EDGE_MIDPOINTS[6] = vec2[6](
vec2(-0.375, 0.21650635),
vec2( 0.0, 0.43301270),
vec2( 0.375, 0.21650635),
vec2( 0.375, -0.21650635),
vec2( 0.0, -0.43301270),
vec2(-0.375, -0.21650635)
);
float getRiverDistance(vec2 p, int mask) {
if (mask == 0) return 999.0;
int edges[6];
int count = 0;
for (int e = 0; e < 6; ++e) {
if ((mask & (1 << e)) != 0) {
edges[count] = e;
count++;
}
}
if (count == 2) {
vec2 p0 = EDGE_MIDPOINTS[edges[0]];
vec2 p2 = EDGE_MIDPOINTS[edges[1]];
vec2 s0 = p0;
vec2 s1 = 0.5625 * p0 + 0.0625 * p2;
vec2 s2 = 0.2500 * p0 + 0.2500 * p2;
vec2 s3 = 0.0625 * p0 + 0.5625 * p2;
vec2 s4 = p2;
float d0 = distToSegment(p, s0, s1);
float d1 = distToSegment(p, s1, s2);
float d2 = distToSegment(p, s2, s3);
float d3 = distToSegment(p, s3, s4);
return min(min(d0, d1), min(d2, d3));
} else {
float minDist = 999.0;
for (int i = 0; i < count; ++i) {
float d = distToSegment(p, EDGE_MIDPOINTS[edges[i]], vec2(0.0));
minDist = min(minDist, d);
}
return minDist;
}
}
void main() {
vec3 norm = normalize(vNormal);
vec3 surfaceToLight = normalize(sunLight.vDirection);
vec3 surfacePos = vec3(modelMatrix * vec4(fragVert, 1));
vec3 surfaceToCamera = normalize(cameraPosition - surfacePos);
vec4 bcolor = texture(border, vec2(tilePos.x,tilePos.y*1.154734411));
float fDiffuseIntensity = max(0.0, dot(normalize(vNormal), -sunLight.vDirection));
// 1. Biome Typemap Sampling
// World extent: [0..225.0 km, 0..108.22 km]
// Note: QImage row 0 is North (worldY = 108.22), which QOpenGLTexture maps to v = 0.0.
// Invert Y so North samples row 0 and South samples row 1499.
vec2 uvType = vec2(clamp(vWorldPos.x / 225.0, 0.0, 1.0), 1.0 - clamp(vWorldPos.y / 108.22, 0.0, 1.0));
vec4 typePixel = texture(texTypeMap, uvType);
float addval = bcolor.a;
vec4 vSpecularColor = GetSpecularColor(vWorldPos, cameraPosition, sunLight, normalize(vNormal))+ GetDirectionalLightColor(sunLight,normalize(vNormal));
vec4 ground = texture(tex, fragTexCoord);
vec4 rockt = texture(rock, fragTexCoord);
// Compute smooth biome weights from typemap colors:
// 1. Prairie: red dominant (r - g)
float prairieWeight = clamp((typePixel.r - typePixel.g - 0.20) / 0.25, 0.0, 1.0);
// 2. Sahara: yellow (r & g high, b low)
float saharaWeight = clamp((min(typePixel.r, typePixel.g) - 0.45) / 0.25, 0.0, 1.0) * (1.0 - prairieWeight);
// 3. Forest: elevated blue with low red (b > 0.15, r < 0.25)
float forestWeight = clamp((typePixel.b - 0.15) / 0.20, 0.0, 1.0) * clamp((0.25 - typePixel.r) / 0.15, 0.0, 1.0) * (1.0 - prairieWeight) * (1.0 - saharaWeight);
// 4. Tundra: muted slate/olive (low saturation, moderate/low green)
float sat = max(typePixel.r, max(typePixel.g, typePixel.b)) - min(typePixel.r, min(typePixel.g, typePixel.b));
float tundraWeight = clamp((0.25 - sat) / 0.15, 0.0, 1.0) * clamp((0.55 - typePixel.g) / 0.15, 0.0, 1.0) * (1.0 - prairieWeight) * (1.0 - saharaWeight) * (1.0 - forestWeight);
// 5. Grassland: green dominant open plains
float grasslandWeight = clamp(1.0 - (prairieWeight + saharaWeight + forestWeight + tundraWeight), 0.0, 1.0);
float gndfac = 1.0;
if (z_pos>0.3)
gndfac = 0.0;
else if (z_pos>0.1)
gndfac=1.0 - 1.0 / 0.2 * (z_pos-0.1) ;
finalColor = (ground *gndfac+rockt *(1.0-gndfac) +bcolor*addval) * vSpecularColor; //texture(tex, fragTexCoord) * pow(max(0.0, dot(surfaceToCamera, reflect(-surfaceToLight, normal))), 0.5);
// 2. Polar Latitude Calculation (World Y in [0..108.25 km])
float normY = clamp(vWorldPos.y / 108.25, 0.0, 1.0);
float distFromCenter = abs(normY - 0.5) * 2.0; // 0.0 at middle, 1.0 at North/South poles
float poleFactor = smoothstep(0.40, 0.85, distFromCenter);
// (texture(tex, fragTexCoord)+bcolor*addval)*vec4(sunLight.vColor*(sunLight.fAmbientIntensity+fDiffuseIntensity), 1.0);
// Snowline in kilometers: 2.5 (2500m) in temperate zone, dropping to 0.0 (sea level) at poles!
float snowLine = mix(2.5, 0.0, poleFactor);
// 3. Water vs Land detection (z_pos = height in kilometers, 0.0 = sea level)
float oceanWaterFac = 1.0 - smoothstep(0.005, 0.025, z_pos);
// River water detection
float riverDist = getRiverDistance(fragVert.xy, riverMask);
float riverWaterRadius = 0.024;
float riverBankRadius = 0.052;
float riverWaterFac = 1.0 - smoothstep(riverWaterRadius * 0.7, riverWaterRadius, riverDist);
float riverBankFac = (1.0 - smoothstep(riverWaterRadius, riverBankRadius, riverDist)) * (1.0 - riverWaterFac);
// Combined water factor (ocean or river)
float waterFac = max(oceanWaterFac, riverWaterFac);
// 4. Dynamic animated ocean water
vec2 uvW1 = vWorldPos.xy * 0.30 + vec2(time * 0.035, time * 0.020);
vec2 uvW2 = vWorldPos.xy * 0.38 + vec2(-time * 0.025, time * 0.030);
vec2 waveDistort1 = vec2(sin(uvW1.y * 14.0 + time * 2.2), cos(uvW1.x * 14.0 + time * 1.8)) * 0.025;
vec2 waveDistort2 = vec2(cos(uvW2.y * 18.0 - time * 1.5), sin(uvW2.x * 18.0 - time * 2.5)) * 0.020;
vec4 wSample1 = texture(texWater, uvW1 + waveDistort1);
vec4 wSample2 = texture(texWater, uvW2 + waveDistort2);
vec4 waterColor = mix(wSample1, wSample2, 0.5);
waterColor.rgb = mix(waterColor.rgb, vec3(0.05, 0.30, 0.50), 0.30);
vec3 waterNorm = normalize(vec3(
(waveDistort1.x + waveDistort2.x) * 2.5,
(waveDistort1.y + waveDistort2.y) * 2.5,
1.0
));
// 5. Triplanar mapping coordinates for Land, Cliffs & Snow
vec3 blendWeights = pow(abs(norm), vec3(4.0));
blendWeights /= (blendWeights.x + blendWeights.y + blendWeights.z);
vec2 uvX = vWorldPos.yz * 0.35;
vec2 uvY = vWorldPos.xz * 0.35;
vec2 uvZ = vWorldPos.xy * 0.35;
// Rock textures:
// Gray rock (Texturelabs_Stone_136XL_seamless)
vec4 rockGray = texture(texRock, uvX) * blendWeights.x
+ texture(texRock, uvY) * blendWeights.y
+ texture(texRock, uvZ) * blendWeights.z;
// Red rock canyon cliff (Texturelabs_RedRock_seamless)
vec4 rockRed = texture(texRedRock, uvX) * blendWeights.x
+ texture(texRedRock, uvY) * blendWeights.y
+ texture(texRedRock, uvZ) * blendWeights.z;
// Cliff rock: red sandstone in Prairie canyon, gray alpine elsewhere
vec4 cliffRockColor = mix(rockGray, rockRed, prairieWeight);
// Snow / Ice texture (Texturelabs_Water_155XL_seamless)
vec4 snowColor = texture(texSnow, uvX) * blendWeights.x
+ texture(texSnow, uvY) * blendWeights.y
+ texture(texSnow, uvZ) * blendWeights.z;
// Ground textures:
vec4 grassColor = texture(texGrass, uvZ);
vec4 forestColor = texture(texForest, uvZ);
vec4 beachColor = texture(texSand, uvZ);
vec4 saharaColor = texture(texSahara, uvZ);
vec4 tundraColor = texture(texTundra, uvZ);
vec4 redSandColor = texture(texRedSand, uvZ);
// Composite ground texture across all biomes:
vec4 biomeGround = grassColor * grasslandWeight
+ forestColor * forestWeight
+ saharaColor * saharaWeight
+ tundraColor * tundraWeight
+ redSandColor * prairieWeight;
// Shoreline beach: where gentle slopes meet water (sea level up to ~110m, or along rivers)
// Steep slopes (norm.z < 0.55) remain rocky cliffs; gentle slopes (norm.z > 0.80) get a sandy beach
float gentleSlope = smoothstep(0.55, 0.85, norm.z);
float coastBeach = (1.0 - smoothstep(0.015, 0.110, z_pos)) * smoothstep(0.003, 0.015, z_pos) * gentleSlope;
float riverBeach = riverBankFac;
float beachFac = max(coastBeach, riverBeach);
// Suppress beach only at the extreme polar ice sheet edges
float polarIceCover = smoothstep(0.82, 0.96, distFromCenter);
beachFac *= (1.0 - polarIceCover);
// Apply sandy beach across all land types gently meeting water
biomeGround = mix(biomeGround, beachColor, beachFac * 0.90);
// Polar pack ice on cold polar waters
float polarSeaIce = smoothstep(0.72, 0.94, distFromCenter);
waterColor = mix(waterColor, snowColor, polarSeaIce * 0.95);
// 6. Slope & Elevation Blending Rules
// norm.z: 1.0 = flat horizontal ground, < 0.55 = steep slope / vertical cliff
float flatness = clamp((norm.z - 0.55) / 0.25, 0.0, 1.0);
// Mountain rock elevation factor: begins at 1000m (1.0 km), ramps up towards 2200m (2.2 km)
float rockLine = mix(1.0, 0.0, poleFactor);
float mountainAltitude = smoothstep(rockLine, min(snowLine, rockLine + 1.2), z_pos);
// Steep slopes are always rock; flat ground becomes rock as altitude rises above 1000m
float rockWeight = max(1.0 - flatness, mountainAltitude);
// Snow rule: starts above 2500m in temperate zone, dropping to sea level at poles
float snowHeight = smoothstep(snowLine - 0.20, snowLine + 0.30, z_pos);
float snowSlope = clamp((norm.z - 0.28) / 0.25, 0.0, 1.0);
float snowWeight = snowHeight * snowSlope;
// At polar caps, ice covers flat ground at sea level
float polarLandIce = smoothstep(0.72, 0.92, distFromCenter);
snowWeight = max(snowWeight, polarLandIce * snowSlope);
// Composite ground: biome ground -> mountain rock above 1000m & on cliffs -> snow above 2500m
vec4 nonSnowLand = mix(biomeGround, cliffRockColor, rockWeight);
vec4 landColor = mix(nonSnowLand, snowColor, snowWeight);
// 7. Combine Land and Sea
vec4 surfaceColor = mix(landColor, waterColor, waterFac);
// 8. Hexagon grid border outline
vec4 bcolor = texture(texBorder, vec2(tilePos.x, tilePos.y * 1.154734411));
float borderAlpha = bcolor.a * (1.0 - waterFac * 0.7);
// 9. Lighting & Specular glint
vec3 activeNorm = mix(norm, waterNorm, waterFac);
vec4 lightDiffuse = GetDirectionalLightColor(sunLight, activeNorm);
// Specular: crisp sparkle on snow and water
float specShininess = mix(mix(16.0, 32.0, snowWeight), 48.0, waterFac);
float specIntensity = mix(mix(0.12, 0.55, snowWeight), 0.85, waterFac);
vec4 lightSpecular = GetSpecularColor(vWorldPos, cameraPosition, sunLight, activeNorm, specShininess, specIntensity);
finalColor = (surfaceColor + bcolor * borderAlpha) * lightDiffuse + lightSpecular;
}