mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Stabilize Vulkan rendering state for minimap, foliage, and water
This commit is contained in:
parent
8efc1548dc
commit
bd0305f6dd
10 changed files with 834 additions and 117 deletions
|
|
@ -38,7 +38,26 @@ layout(location = 0) out vec4 outColor;
|
|||
void main() {
|
||||
vec4 texColor = hasTexture != 0 ? texture(uTexture, TexCoord) : vec4(1.0);
|
||||
|
||||
if (alphaTest != 0 && texColor.a < 0.5) discard;
|
||||
float alphaCutoff = 0.5;
|
||||
if (alphaTest == 2) {
|
||||
// Vegetation cutout: lower threshold to preserve leaf coverage at grazing angles.
|
||||
alphaCutoff = 0.33;
|
||||
} else if (alphaTest != 0) {
|
||||
alphaCutoff = 0.35;
|
||||
}
|
||||
if (alphaTest == 2) {
|
||||
float alpha = texColor.a;
|
||||
float softBand = 0.12;
|
||||
if (alpha < (alphaCutoff - softBand)) discard;
|
||||
if (alpha < alphaCutoff) {
|
||||
vec2 p = floor(gl_FragCoord.xy);
|
||||
float n = fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
|
||||
float keep = clamp((alpha - (alphaCutoff - softBand)) / softBand, 0.0, 1.0);
|
||||
if (n > keep) discard;
|
||||
}
|
||||
} else if (alphaTest != 0 && texColor.a < alphaCutoff) {
|
||||
discard;
|
||||
}
|
||||
if (colorKeyBlack != 0) {
|
||||
float lum = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));
|
||||
if (lum < colorKeyThreshold) discard;
|
||||
|
|
@ -46,10 +65,12 @@ void main() {
|
|||
if (blendMode == 1 && texColor.a < 0.004) discard;
|
||||
|
||||
vec3 norm = normalize(Normal);
|
||||
if (!gl_FrontFacing) norm = -norm;
|
||||
bool foliageTwoSided = (alphaTest == 2);
|
||||
if (!foliageTwoSided && !gl_FrontFacing) norm = -norm;
|
||||
|
||||
vec3 ldir = normalize(-lightDir.xyz);
|
||||
float diff = max(dot(norm, ldir), 0.0);
|
||||
float nDotL = dot(norm, ldir);
|
||||
float diff = foliageTwoSided ? abs(nDotL) : max(nDotL, 0.0);
|
||||
|
||||
vec3 result;
|
||||
if (unlit != 0) {
|
||||
|
|
@ -64,10 +85,11 @@ void main() {
|
|||
vec4 lsPos = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
vec3 proj = lsPos.xyz / lsPos.w * 0.5 + 0.5;
|
||||
if (proj.z <= 1.0) {
|
||||
float bias = max(0.005 * (1.0 - dot(norm, ldir)), 0.001);
|
||||
float bias = max(0.005 * (1.0 - abs(dot(norm, ldir))), 0.001);
|
||||
shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias));
|
||||
}
|
||||
shadow = mix(1.0, shadow, shadowParams.y);
|
||||
if (foliageTwoSided) shadow = max(shadow, 0.45);
|
||||
}
|
||||
|
||||
result = ambientColor.rgb * texColor.rgb
|
||||
|
|
@ -82,5 +104,16 @@ void main() {
|
|||
float fogFactor = clamp((fogParams.y - dist) / (fogParams.y - fogParams.x), 0.0, 1.0);
|
||||
result = mix(fogColor.rgb, result, fogFactor);
|
||||
|
||||
outColor = vec4(result, texColor.a * fadeAlpha);
|
||||
float outAlpha = texColor.a * fadeAlpha;
|
||||
// Cutout materials should not remain partially transparent after discard,
|
||||
// otherwise foliage cards look view-dependent.
|
||||
if (alphaTest != 0 || colorKeyBlack != 0) {
|
||||
outAlpha = fadeAlpha;
|
||||
}
|
||||
// Foliage cutout should stay opaque after alpha discard to avoid
|
||||
// view-angle translucency artifacts.
|
||||
if (alphaTest == 2) {
|
||||
outAlpha = 1.0 * fadeAlpha;
|
||||
}
|
||||
outColor = vec4(result, outAlpha);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,37 +27,96 @@ layout(set = 1, binding = 0) uniform WaterMaterial {
|
|||
float alphaScale;
|
||||
};
|
||||
|
||||
layout(set = 2, binding = 0) uniform sampler2D SceneColor;
|
||||
layout(set = 2, binding = 1) uniform sampler2D SceneDepth;
|
||||
|
||||
layout(location = 0) in vec3 FragPos;
|
||||
layout(location = 1) in vec3 Normal;
|
||||
layout(location = 2) in vec2 TexCoord;
|
||||
layout(location = 3) in float WaveOffset;
|
||||
layout(location = 4) in vec2 ScreenUV;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
vec3 dualScrollWaveNormal(vec2 p, float time) {
|
||||
// Two independently scrolling octaves (normal-map style layering).
|
||||
vec2 d1 = normalize(vec2(0.86, 0.51));
|
||||
vec2 d2 = normalize(vec2(-0.47, 0.88));
|
||||
float f1 = 0.19;
|
||||
float f2 = 0.43;
|
||||
float s1 = 0.95;
|
||||
float s2 = 1.73;
|
||||
float a1 = 0.26;
|
||||
float a2 = 0.12;
|
||||
|
||||
vec2 p1 = p + d1 * (time * s1 * 4.0);
|
||||
vec2 p2 = p + d2 * (time * s2 * 4.0);
|
||||
|
||||
float ph1 = dot(p1, d1) * f1;
|
||||
float ph2 = dot(p2, d2) * f2;
|
||||
|
||||
float c1 = cos(ph1);
|
||||
float c2 = cos(ph2);
|
||||
|
||||
float dHx = c1 * d1.x * f1 * a1 + c2 * d2.x * f2 * a2;
|
||||
float dHz = c1 * d1.y * f1 * a1 + c2 * d2.y * f2 * a2;
|
||||
|
||||
return normalize(vec3(-dHx, 1.0, -dHz));
|
||||
}
|
||||
|
||||
void main() {
|
||||
float time = fogParams.z;
|
||||
vec3 norm = normalize(Normal);
|
||||
vec3 meshNorm = normalize(Normal);
|
||||
vec3 waveNorm = dualScrollWaveNormal(FragPos.xz, time);
|
||||
vec3 norm = normalize(mix(meshNorm, waveNorm, 0.82));
|
||||
|
||||
vec3 viewDir = normalize(viewPos.xyz - FragPos);
|
||||
vec3 ldir = normalize(-lightDir.xyz);
|
||||
float ndotv = max(dot(norm, viewDir), 0.0);
|
||||
|
||||
float diff = max(dot(norm, ldir), 0.0);
|
||||
vec3 halfDir = normalize(ldir + viewDir);
|
||||
float spec = pow(max(dot(norm, halfDir), 0.0), 128.0);
|
||||
float spec = pow(max(dot(norm, halfDir), 0.0), 96.0);
|
||||
float sparkle = sin(FragPos.x * 20.0 + time * 3.0) * sin(FragPos.z * 20.0 + time * 2.5);
|
||||
sparkle = max(0.0, sparkle) * shimmerStrength;
|
||||
|
||||
vec3 color = waterColor.rgb * (ambientColor.rgb + diff * lightColor.rgb)
|
||||
+ spec * lightColor.rgb * 0.5
|
||||
+ sparkle * lightColor.rgb * 0.3;
|
||||
|
||||
float crest = smoothstep(0.3, 1.0, WaveOffset) * 0.15;
|
||||
color += vec3(crest);
|
||||
|
||||
float fresnel = pow(1.0 - max(dot(norm, viewDir), 0.0), 3.0);
|
||||
float alpha = mix(waterAlpha * 0.6, waterAlpha, fresnel) * alphaScale;
|
||||
|
||||
float dist = length(viewPos.xyz - FragPos);
|
||||
alpha *= smoothstep(800.0, 200.0, dist);
|
||||
|
||||
// Beer-Lambert style approximation from view distance.
|
||||
float opticalDepth = 1.0 - exp(-dist * 0.0035);
|
||||
vec3 litTransmission = waterColor.rgb * (ambientColor.rgb * 0.85 + diff * lightColor.rgb * 0.55);
|
||||
vec3 absorbed = mix(litTransmission, waterColor.rgb * 0.52, opticalDepth);
|
||||
absorbed += vec3(crest);
|
||||
|
||||
// Schlick Fresnel with water-like F0.
|
||||
const float F0 = 0.02;
|
||||
float fresnel = F0 + (1.0 - F0) * pow(1.0 - ndotv, 5.0);
|
||||
vec2 refractOffset = norm.xz * (0.012 + 0.02 * fresnel);
|
||||
vec2 refractUV = clamp(ScreenUV + refractOffset, vec2(0.001), vec2(0.999));
|
||||
vec3 sceneRefract = texture(SceneColor, refractUV).rgb;
|
||||
|
||||
float sceneDepth = texture(SceneDepth, refractUV).r;
|
||||
float waterDepth = clamp((sceneDepth - gl_FragCoord.z) * 180.0, 0.0, 1.0);
|
||||
float depthBlend = waterDepth;
|
||||
// Fallback when sampled depth does not provide meaningful separation.
|
||||
if (sceneDepth <= gl_FragCoord.z + 1e-4) {
|
||||
depthBlend = 0.45 + opticalDepth * 0.40;
|
||||
}
|
||||
depthBlend = clamp(depthBlend, 0.28, 1.0);
|
||||
vec3 refractedTint = mix(sceneRefract, absorbed, depthBlend);
|
||||
|
||||
vec3 specular = spec * lightColor.rgb * (0.45 + 0.75 * fresnel)
|
||||
+ sparkle * lightColor.rgb * 0.30;
|
||||
// Add a clear surface reflection lobe at grazing angles.
|
||||
vec3 envReflect = mix(fogColor.rgb, lightColor.rgb, 0.38) * vec3(0.75, 0.86, 1.0);
|
||||
vec3 reflection = envReflect * (0.45 + 0.55 * fresnel) + specular;
|
||||
float reflectWeight = clamp(fresnel * 1.15, 0.0, 0.92);
|
||||
vec3 color = mix(refractedTint, reflection, reflectWeight);
|
||||
|
||||
float alpha = mix(waterAlpha * 1.05, min(1.0, waterAlpha * 1.30), fresnel) * alphaScale;
|
||||
alpha *= smoothstep(1600.0, 350.0, dist);
|
||||
alpha = clamp(alpha, 0.50, 1.0);
|
||||
|
||||
float fogFactor = clamp((fogParams.y - dist) / (fogParams.y - fogParams.x), 0.0, 1.0);
|
||||
color = mix(fogColor.rgb, color, fogFactor);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ layout(location = 0) out vec3 FragPos;
|
|||
layout(location = 1) out vec3 Normal;
|
||||
layout(location = 2) out vec2 TexCoord;
|
||||
layout(location = 3) out float WaveOffset;
|
||||
layout(location = 4) out vec2 ScreenUV;
|
||||
|
||||
float hashGrid(vec2 p) {
|
||||
return fract(sin(dot(floor(p), vec2(127.1, 311.7))) * 43758.5453);
|
||||
|
|
@ -57,5 +58,8 @@ void main() {
|
|||
|
||||
FragPos = worldPos.xyz;
|
||||
TexCoord = aTexCoord;
|
||||
gl_Position = projection * view * worldPos;
|
||||
vec4 clipPos = projection * view * worldPos;
|
||||
gl_Position = clipPos;
|
||||
vec2 ndc = clipPos.xy / max(clipPos.w, 1e-5);
|
||||
ScreenUV = ndc * 0.5 + 0.5;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue