From 4b42bf8d7b351d1821c72302b8160e56ff8d9567 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Sun, 10 Sep 2023 14:50:54 -0400 Subject: [PATCH 1/7] Split up water shaders --- data/CMakeLists.txt | 2 + data/base/shaders/terrain_water_high.frag | 104 +++++++++++++++ data/base/shaders/terrain_water_high.vert | 54 ++++++++ data/base/shaders/vk/terrain_water.vert | 1 - data/base/shaders/vk/terrain_water_high.frag | 94 +++++++++++++ data/base/shaders/vk/terrain_water_high.vert | 50 +++++++ data/base/shaders/vk/water.frag | 48 +------ data/base/shaders/water.frag | 48 +------ lib/ivis_opengl/gfx_api.h | 31 +++-- lib/ivis_opengl/gfx_api_gl.cpp | 34 ++++- lib/ivis_opengl/gfx_api_gl.h | 1 + lib/ivis_opengl/gfx_api_vk.cpp | 2 +- src/terrain.cpp | 133 ++++++++++++++++--- 13 files changed, 474 insertions(+), 128 deletions(-) create mode 100644 data/base/shaders/terrain_water_high.frag create mode 100644 data/base/shaders/terrain_water_high.vert create mode 100644 data/base/shaders/vk/terrain_water_high.frag create mode 100644 data/base/shaders/vk/terrain_water_high.vert diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 43bd835e484..d904cc66fce 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -83,6 +83,7 @@ file(GLOB VK_SHADERS "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/terrain_depth.vert" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/terrain_depth_only.vert" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/terrain_water.vert" + "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/terrain_water_high.vert" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/terrain_water_classic.vert" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/decals.vert" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/nolight.vert" @@ -103,6 +104,7 @@ file(GLOB VK_SHADERS "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/terraindepth.frag" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/terrain_depth_only.frag" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/water.frag" + "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/terrain_water_high.frag" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/terrain_water_classic.frag" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/decals.frag" "${CMAKE_CURRENT_SOURCE_DIR}/base/shaders/vk/nolight.frag" diff --git a/data/base/shaders/terrain_water_high.frag b/data/base/shaders/terrain_water_high.frag new file mode 100644 index 00000000000..49b1b9ae05c --- /dev/null +++ b/data/base/shaders/terrain_water_high.frag @@ -0,0 +1,104 @@ +// Version directive is set by Warzone when loading the shader +// (This shader supports GLSL 1.20 - 1.50 core.) + +// constants overridden by WZ when loading shaders (do not modify here in the shader source!) +#define WZ_MIP_LOAD_BIAS 0.f +// + +uniform sampler2D tex1; +uniform sampler2D tex2; +uniform sampler2D tex1_nm; +uniform sampler2D tex2_nm; +uniform sampler2D tex1_sm; +uniform sampler2D tex2_sm; +uniform sampler2D lightmap_tex; + +// light colors/intensity: +uniform vec4 emissiveLight; +uniform vec4 ambientLight; +uniform vec4 diffuseLight; +uniform vec4 specularLight; + +uniform vec4 fogColor; +uniform int fogEnabled; // whether fog is enabled +uniform float fogEnd; +uniform float fogStart; + +#if (!defined(GL_ES) && (__VERSION__ >= 130)) || (defined(GL_ES) && (__VERSION__ >= 300)) +#define NEWGL +#define FRAGMENT_INPUT in +#else +#define texture(tex,uv,bias) texture2D(tex,uv,bias) +#define FRAGMENT_INPUT varying +#endif + +FRAGMENT_INPUT vec4 uv1_uv2; +FRAGMENT_INPUT vec2 uvLightmap; +FRAGMENT_INPUT float depth; +FRAGMENT_INPUT float depth2; +FRAGMENT_INPUT float vertexDistance; +// light in modelSpace: +FRAGMENT_INPUT vec3 lightDir; +FRAGMENT_INPUT vec3 halfVec; + +#ifdef NEWGL +out vec4 FragColor; +#else +#define FragColor gl_FragColor +#endif + +vec3 blendAddEffectLighting(vec3 a, vec3 b) { + return min(a + b, vec3(1.0)); +} + +vec4 main_bumpMapping() +{ + vec2 uv1 = uv1_uv2.xy; + vec2 uv2 = uv1_uv2.zw; + + vec3 N1 = texture(tex1_nm, uv2, WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace + vec3 N2 = texture(tex2_nm, uv1, WZ_MIP_LOAD_BIAS).xzy; + vec3 N; //use overlay blending to mix normal maps properly + N.x = N1.x < 0.5 ? (2.0 * N1.x * N2.x) : (1.0 - 2.0 * (1.0 - N1.x) * (1.0 - N2.x)); + N.z = N1.z < 0.5 ? (2.0 * N1.z * N2.z) : (1.0 - 2.0 * (1.0 - N1.z) * (1.0 - N2.z)); + N.y = N1.y < 0.5 ? (2.0 * N1.y * N2.y) : (1.0 - 2.0 * (1.0 - N1.y) * (1.0 - N2.y)); + if (N == vec3(0.0,0.0,0.0)) { + N = vec3(0.0,1.0,0.0); + } else { + N = normalize(N * 2.0 - 1.0); + } + + float lambertTerm = max(dot(N, lightDir), 0.0); // diffuse lighting + + // Gaussian specular term computation + float gloss = texture(tex1_sm, uv1, WZ_MIP_LOAD_BIAS).r * texture(tex2_sm, uv2, WZ_MIP_LOAD_BIAS).r; + vec3 H = normalize(halfVec); + float exponent = acos(dot(H, N)) / (gloss + 0.05); + float gaussianTerm = exp(-(exponent * exponent)); + + vec4 fragColor = (texture(tex1, uv1, WZ_MIP_LOAD_BIAS)+texture(tex2, uv2, WZ_MIP_LOAD_BIAS)) * (gloss+vec4(0.08,0.13,0.15,1.0)); + fragColor = fragColor*(ambientLight+diffuseLight*lambertTerm) + specularLight*(1.0-gloss)*gaussianTerm*vec4(1.0,0.843,0.686,1.0); + vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap, 0.f); + vec4 color = fragColor * vec4(vec3(lightmap_vec4.a), 1.f); // ... * tile brightness / ambient occlusion (stored in lightmap.a); + color.rgb = blendAddEffectLighting(color.rgb, (lightmap_vec4.rgb / 1.5f)); // additive color (from environmental point lights / effects) + return color; +} + +void main() +{ + vec4 fragColor = main_bumpMapping(); + fragColor = mix(fragColor, fragColor-depth*0.0007, depth*0.0009); + fragColor.a = mix(0.25, 1.0, depth2*0.005); + + if (fogEnabled > 0) + { + // Calculate linear fog + float fogFactor = (fogEnd - vertexDistance) / (fogEnd - fogStart); + fogFactor = clamp(fogFactor, 0.0, 1.0); + + // Return fragment color + fragColor = mix(fragColor, fogColor, fogFactor); + } + + FragColor = fragColor; +} diff --git a/data/base/shaders/terrain_water_high.vert b/data/base/shaders/terrain_water_high.vert new file mode 100644 index 00000000000..3759c9fbaec --- /dev/null +++ b/data/base/shaders/terrain_water_high.vert @@ -0,0 +1,54 @@ +// Version directive is set by Warzone when loading the shader +// (This shader supports GLSL 1.20 - 1.50 core.) + +#if (!defined(GL_ES) && (__VERSION__ >= 130)) || (defined(GL_ES) && (__VERSION__ >= 300)) +#define NEWGL +#endif + +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ModelUVLightmapMatrix; +uniform mat4 ModelUV1Matrix; +uniform mat4 ModelUV2Matrix; + +uniform float timeSec; + +uniform vec4 cameraPos; // in modelSpace +uniform vec4 sunPos; // in modelSpace, normalized + +#ifdef NEWGL +#define VERTEX_INPUT in +#define VERTEX_OUTPUT out +#else +#define VERTEX_INPUT attribute +#define VERTEX_OUTPUT varying +#endif + +VERTEX_INPUT vec4 vertex; // w is depth + +VERTEX_OUTPUT vec4 uv1_uv2; +VERTEX_OUTPUT vec2 uvLightmap; +VERTEX_OUTPUT float depth; +VERTEX_OUTPUT float depth2; +VERTEX_OUTPUT float vertexDistance; +// light in modelSpace: +VERTEX_OUTPUT vec3 lightDir; +VERTEX_OUTPUT vec3 halfVec; + +void main() +{ + uvLightmap = (ModelUVLightmapMatrix * vec4(vertex.xyz, 1.f)).xy; + depth = vertex.w; + depth2 = length(vertex.y - vertex.w); + + vec2 uv1 = vec2(vertex.x/4.f/128.f + timeSec/80.f, -vertex.z/4.f/128.f + timeSec/40.f); // (ModelUV1Matrix * vertex).xy; + vec2 uv2 = vec2(vertex.x/4.f/128.f, -vertex.z/4.f/128.f - timeSec/40.f); // (ModelUV2Matrix * vertex).xy; + uv1_uv2 = vec4(uv1.x, uv1.y, uv2.x, uv2.y); + + vec3 eyeVec = normalize(cameraPos.xyz - vertex.xyz); + lightDir = sunPos.xyz; + halfVec = lightDir + eyeVec; + + vec4 position = ModelViewProjectionMatrix * vec4(vertex.xyz, 1.f); + vertexDistance = position.z; + gl_Position = position; +} diff --git a/data/base/shaders/vk/terrain_water.vert b/data/base/shaders/vk/terrain_water.vert index 6d45230460c..e0e0479ca98 100644 --- a/data/base/shaders/vk/terrain_water.vert +++ b/data/base/shaders/vk/terrain_water.vert @@ -16,7 +16,6 @@ layout(std140, set = 0, binding = 0) uniform cbuffer { float fogEnd; float fogStart; float timeSec; - int quality; }; layout(location = 0) in vec4 vertex; // .w is depth diff --git a/data/base/shaders/vk/terrain_water_high.frag b/data/base/shaders/vk/terrain_water_high.frag new file mode 100644 index 00000000000..a881aa4a5cd --- /dev/null +++ b/data/base/shaders/vk/terrain_water_high.frag @@ -0,0 +1,94 @@ +#version 450 + +layout (constant_id = 0) const float WZ_MIP_LOAD_BIAS = 0.f; + +layout(set = 1, binding = 0) uniform sampler2D tex1; +layout(set = 1, binding = 1) uniform sampler2D tex2; +layout(set = 1, binding = 2) uniform sampler2D tex1_nm; +layout(set = 1, binding = 3) uniform sampler2D tex2_nm; +layout(set = 1, binding = 4) uniform sampler2D tex1_sm; +layout(set = 1, binding = 5) uniform sampler2D tex2_sm; +layout(set = 1, binding = 6) uniform sampler2D lightmap_tex; + +layout(std140, set = 0, binding = 0) uniform cbuffer { + mat4 ModelViewProjectionMatrix; + mat4 ModelUVLightmapMatrix; + mat4 ModelUV1Matrix; + mat4 ModelUV2Matrix; + vec4 cameraPos; // in modelSpace + vec4 sunPos; // in modelSpace, normalized + vec4 emissiveLight; // light colors/intensity + vec4 ambientLight; + vec4 diffuseLight; + vec4 specularLight; + vec4 fogColor; + int fogEnabled; // whether fog is enabled + float fogEnd; + float fogStart; + float timeSec; +}; + +layout(location = 1) in vec4 uv1_uv2; +layout(location = 2) in vec2 uvLightmap; +layout(location = 3) in float vertexDistance; +layout(location = 4) in vec3 lightDir; +layout(location = 5) in vec3 halfVec; +layout(location = 6) in float depth; +layout(location = 7) in float depth2; + +layout(location = 0) out vec4 FragColor; + +vec3 blendAddEffectLighting(vec3 a, vec3 b) { + return min(a + b, vec3(1.0)); +} + +vec4 main_bumpMapping() +{ + vec2 uv1 = uv1_uv2.xy; + vec2 uv2 = uv1_uv2.zw; + + vec3 N1 = texture(tex1_nm, uv2, WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace + vec3 N2 = texture(tex2_nm, uv1, WZ_MIP_LOAD_BIAS).xzy; + vec3 N; //use overlay blending to mix normal maps properly + N.x = N1.x < 0.5 ? (2.0 * N1.x * N2.x) : (1.0 - 2.0 * (1.0 - N1.x) * (1.0 - N2.x)); + N.z = N1.z < 0.5 ? (2.0 * N1.z * N2.z) : (1.0 - 2.0 * (1.0 - N1.z) * (1.0 - N2.z)); + N.y = N1.y < 0.5 ? (2.0 * N1.y * N2.y) : (1.0 - 2.0 * (1.0 - N1.y) * (1.0 - N2.y)); + if (N == vec3(0.0,0.0,0.0)) { + N = vec3(0.0,1.0,0.0); + } else { + N = normalize(N * 2.0 - 1.0); + } + float lambertTerm = max(dot(N, lightDir), 0.0); // diffuse lighting + + // Gaussian specular term computation + float gloss = texture(tex1_sm, uv1, WZ_MIP_LOAD_BIAS).r * texture(tex2_sm, uv2, WZ_MIP_LOAD_BIAS).r; + vec3 H = normalize(halfVec); + float exponent = acos(dot(H, N)) / (gloss + 0.05); + float gaussianTerm = exp(-(exponent * exponent)); + + vec4 fragColor = (texture(tex1, uv1, WZ_MIP_LOAD_BIAS)+texture(tex2, uv2, WZ_MIP_LOAD_BIAS)) * (gloss+vec4(0.08,0.13,0.15,1.0)); + fragColor = fragColor*(ambientLight+diffuseLight*lambertTerm) + specularLight*(1.0-gloss)*gaussianTerm*vec4(1.0,0.843,0.686,1.0); + vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap, 0.f); + vec4 color = fragColor * vec4(vec3(lightmap_vec4.a), 1.f); // ... * tile brightness / ambient occlusion (stored in lightmap.a); + color.rgb = blendAddEffectLighting(color.rgb, (lightmap_vec4.rgb / 1.5f)); // additive color (from environmental point lights / effects) + return color; +} + +void main() +{ + vec4 fragColor = main_bumpMapping(); + fragColor = mix(fragColor, fragColor-depth*0.0007, depth*0.0009); + fragColor.a = mix(0.25, 1.0, depth2*0.005); + + if (fogEnabled > 0) + { + // Calculate linear fog + float fogFactor = (fogEnd - vertexDistance) / (fogEnd - fogStart); + fogFactor = clamp(fogFactor, 0.0, 1.0); + + // Return fragment color + fragColor = mix(fragColor, fogColor, fogFactor); + } + + FragColor = fragColor; +} diff --git a/data/base/shaders/vk/terrain_water_high.vert b/data/base/shaders/vk/terrain_water_high.vert new file mode 100644 index 00000000000..e0e0479ca98 --- /dev/null +++ b/data/base/shaders/vk/terrain_water_high.vert @@ -0,0 +1,50 @@ +#version 450 + +layout(std140, set = 0, binding = 0) uniform cbuffer { + mat4 ModelViewProjectionMatrix; + mat4 ModelUVLightmapMatrix; + mat4 ModelUV1Matrix; + mat4 ModelUV2Matrix; + vec4 cameraPos; // in modelSpace + vec4 sunPos; // in modelSpace, normalized + vec4 emissiveLight; // light colors/intensity + vec4 ambientLight; + vec4 diffuseLight; + vec4 specularLight; + vec4 fogColor; + int fogEnabled; // whether fog is enabled + float fogEnd; + float fogStart; + float timeSec; +}; + +layout(location = 0) in vec4 vertex; // .w is depth + +layout(location = 1) out vec4 uv1_uv2; +layout(location = 2) out vec2 uvLightmap; +layout(location = 3) out float vertexDistance; +layout(location = 4) out vec3 lightDir; +layout(location = 5) out vec3 halfVec; +layout(location = 6) out float depth; +layout(location = 7) out float depth2; + +void main() +{ + uvLightmap = (ModelUVLightmapMatrix * vec4(vertex.xyz, 1.f)).xy; + depth = vertex.w; + depth2 = length(vertex.y - vertex.w); + + vec2 uv1 = vec2(vertex.x/4.f/128.f + timeSec/80.f, -vertex.z/4.f/128.f + timeSec/40.f); // (ModelUV1Matrix * vertex).xy; + vec2 uv2 = vec2(vertex.x/4.f/128.f, -vertex.z/4.f/128.f - timeSec/40.f); // (ModelUV2Matrix * vertex).xy; + uv1_uv2 = vec4(uv1.x, uv1.y, uv2.x, uv2.y); + + vec3 eyeVec = normalize(cameraPos.xyz - vertex.xyz); + lightDir = sunPos.xyz; + halfVec = lightDir + eyeVec; + + vec4 position = ModelViewProjectionMatrix * vec4(vertex.xyz, 1.f); + vertexDistance = position.z; + gl_Position = position; + gl_Position.y *= -1.; + gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0; +} diff --git a/data/base/shaders/vk/water.frag b/data/base/shaders/vk/water.frag index aa4a560e929..063b23afc30 100644 --- a/data/base/shaders/vk/water.frag +++ b/data/base/shaders/vk/water.frag @@ -4,11 +4,7 @@ layout (constant_id = 0) const float WZ_MIP_LOAD_BIAS = 0.f; layout(set = 1, binding = 0) uniform sampler2D tex1; layout(set = 1, binding = 1) uniform sampler2D tex2; -layout(set = 1, binding = 2) uniform sampler2D tex1_nm; -layout(set = 1, binding = 3) uniform sampler2D tex2_nm; -layout(set = 1, binding = 4) uniform sampler2D tex1_sm; -layout(set = 1, binding = 5) uniform sampler2D tex2_sm; -layout(set = 1, binding = 6) uniform sampler2D lightmap_tex; +layout(set = 1, binding = 2) uniform sampler2D lightmap_tex; layout(std140, set = 0, binding = 0) uniform cbuffer { mat4 ModelViewProjectionMatrix; @@ -26,7 +22,6 @@ layout(std140, set = 0, binding = 0) uniform cbuffer { float fogEnd; float fogStart; float timeSec; - int quality; }; layout(location = 1) in vec4 uv1_uv2; @@ -53,48 +48,9 @@ vec3 blendAddEffectLighting(vec3 a, vec3 b) { return min(a + b, vec3(1.0)); } -vec4 main_bumpMapping() -{ - vec2 uv1 = uv1_uv2.xy; - vec2 uv2 = uv1_uv2.zw; - - vec3 N1 = texture(tex1_nm, uv2, WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace - vec3 N2 = texture(tex2_nm, uv1, WZ_MIP_LOAD_BIAS).xzy; - vec3 N; //use overlay blending to mix normal maps properly - N.x = N1.x < 0.5 ? (2.0 * N1.x * N2.x) : (1.0 - 2.0 * (1.0 - N1.x) * (1.0 - N2.x)); - N.z = N1.z < 0.5 ? (2.0 * N1.z * N2.z) : (1.0 - 2.0 * (1.0 - N1.z) * (1.0 - N2.z)); - N.y = N1.y < 0.5 ? (2.0 * N1.y * N2.y) : (1.0 - 2.0 * (1.0 - N1.y) * (1.0 - N2.y)); - if (N == vec3(0.0,0.0,0.0)) { - N = vec3(0.0,1.0,0.0); - } else { - N = normalize(N * 2.0 - 1.0); - } - float lambertTerm = max(dot(N, lightDir), 0.0); // diffuse lighting - - // Gaussian specular term computation - float gloss = texture(tex1_sm, uv1, WZ_MIP_LOAD_BIAS).r * texture(tex2_sm, uv2, WZ_MIP_LOAD_BIAS).r; - vec3 H = normalize(halfVec); - float exponent = acos(dot(H, N)) / (gloss + 0.05); - float gaussianTerm = exp(-(exponent * exponent)); - - vec4 fragColor = (texture(tex1, uv1, WZ_MIP_LOAD_BIAS)+texture(tex2, uv2, WZ_MIP_LOAD_BIAS)) * (gloss+vec4(0.08,0.13,0.15,1.0)); - fragColor = fragColor*(ambientLight+diffuseLight*lambertTerm) + specularLight*(1.0-gloss)*gaussianTerm*vec4(1.0,0.843,0.686,1.0); - vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap, 0.f); - vec4 color = fragColor * vec4(vec3(lightmap_vec4.a), 1.f); // ... * tile brightness / ambient occlusion (stored in lightmap.a); - color.rgb = blendAddEffectLighting(color.rgb, (lightmap_vec4.rgb / 1.5f)); // additive color (from environmental point lights / effects) - return color; -} - void main() { - vec4 fragColor; - if (quality == 2) { - fragColor = main_bumpMapping(); - fragColor = mix(fragColor, fragColor-depth*0.0007, depth*0.0009); - fragColor.a = mix(0.25, 1.0, depth2*0.005); - } else { - fragColor = main_medium(); - } + vec4 fragColor = main_medium(); if (fogEnabled > 0) { diff --git a/data/base/shaders/water.frag b/data/base/shaders/water.frag index e2117aef709..b15c64b8f34 100644 --- a/data/base/shaders/water.frag +++ b/data/base/shaders/water.frag @@ -7,10 +7,6 @@ uniform sampler2D tex1; uniform sampler2D tex2; -uniform sampler2D tex1_nm; -uniform sampler2D tex2_nm; -uniform sampler2D tex1_sm; -uniform sampler2D tex2_sm; uniform sampler2D lightmap_tex; // light colors/intensity: @@ -24,8 +20,6 @@ uniform int fogEnabled; // whether fog is enabled uniform float fogEnd; uniform float fogStart; -uniform int quality; // 0-classic, 1-bumpmapping - #if (!defined(GL_ES) && (__VERSION__ >= 130)) || (defined(GL_ES) && (__VERSION__ >= 300)) #define NEWGL #define FRAGMENT_INPUT in @@ -63,49 +57,9 @@ vec3 blendAddEffectLighting(vec3 a, vec3 b) { return min(a + b, vec3(1.0)); } -vec4 main_bumpMapping() -{ - vec2 uv1 = uv1_uv2.xy; - vec2 uv2 = uv1_uv2.zw; - - vec3 N1 = texture(tex1_nm, uv2, WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace - vec3 N2 = texture(tex2_nm, uv1, WZ_MIP_LOAD_BIAS).xzy; - vec3 N; //use overlay blending to mix normal maps properly - N.x = N1.x < 0.5 ? (2.0 * N1.x * N2.x) : (1.0 - 2.0 * (1.0 - N1.x) * (1.0 - N2.x)); - N.z = N1.z < 0.5 ? (2.0 * N1.z * N2.z) : (1.0 - 2.0 * (1.0 - N1.z) * (1.0 - N2.z)); - N.y = N1.y < 0.5 ? (2.0 * N1.y * N2.y) : (1.0 - 2.0 * (1.0 - N1.y) * (1.0 - N2.y)); - if (N == vec3(0.0,0.0,0.0)) { - N = vec3(0.0,1.0,0.0); - } else { - N = normalize(N * 2.0 - 1.0); - } - - float lambertTerm = max(dot(N, lightDir), 0.0); // diffuse lighting - - // Gaussian specular term computation - float gloss = texture(tex1_sm, uv1, WZ_MIP_LOAD_BIAS).r * texture(tex2_sm, uv2, WZ_MIP_LOAD_BIAS).r; - vec3 H = normalize(halfVec); - float exponent = acos(dot(H, N)) / (gloss + 0.05); - float gaussianTerm = exp(-(exponent * exponent)); - - vec4 fragColor = (texture(tex1, uv1, WZ_MIP_LOAD_BIAS)+texture(tex2, uv2, WZ_MIP_LOAD_BIAS)) * (gloss+vec4(0.08,0.13,0.15,1.0)); - fragColor = fragColor*(ambientLight+diffuseLight*lambertTerm) + specularLight*(1.0-gloss)*gaussianTerm*vec4(1.0,0.843,0.686,1.0); - vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap, 0.f); - vec4 color = fragColor * vec4(vec3(lightmap_vec4.a), 1.f); // ... * tile brightness / ambient occlusion (stored in lightmap.a); - color.rgb = blendAddEffectLighting(color.rgb, (lightmap_vec4.rgb / 1.5f)); // additive color (from environmental point lights / effects) - return color; -} - void main() { - vec4 fragColor; - if (quality == 2) { - fragColor = main_bumpMapping(); - fragColor = mix(fragColor, fragColor-depth*0.0007, depth*0.0009); - fragColor.a = mix(0.25, 1.0, depth2*0.005); - } else { - fragColor = main_medium(); - } + vec4 fragColor = main_medium(); if (fogEnabled > 0) { diff --git a/lib/ivis_opengl/gfx_api.h b/lib/ivis_opengl/gfx_api.h index 8520cb223a0..b8c66e37ca8 100644 --- a/lib/ivis_opengl/gfx_api.h +++ b/lib/ivis_opengl/gfx_api.h @@ -1043,7 +1043,6 @@ namespace gfx_api float fog_begin; float fog_end; float timeSec; - int quality; }; using WaterPSO = typename gfx_api::pipeline_state_helper, primitive_type::triangles, index_type::u32, @@ -1053,15 +1052,31 @@ namespace gfx_api >, std::tuple< texture_description<0, sampler_type::anisotropic_repeat>, // tex1 texture_description<1, sampler_type::anisotropic_repeat>, // tex2 - texture_description<2, sampler_type::anisotropic_repeat>, // normal map1 - texture_description<3, sampler_type::anisotropic_repeat>, // normal map2 - texture_description<4, sampler_type::anisotropic_repeat>, // specular map1 - texture_description<5, sampler_type::anisotropic_repeat>, // specular map2 - texture_description<6, sampler_type::bilinear> // lightmap + texture_description<2, sampler_type::bilinear> // lightmap >, SHADER_WATER>; + template<> + struct constant_buffer_type + { + glm::mat4 ModelViewProjectionMatrix; + glm::mat4 ModelUVLightmapMatrix; + glm::mat4 ModelUV1Matrix; + glm::mat4 ModelUV2Matrix; + glm::vec4 cameraPos; // in modelSpace + glm::vec4 sunPos; // in modelSpace + glm::vec4 emissiveLight; // light colors/intensity + glm::vec4 ambientLight; + glm::vec4 diffuseLight; + glm::vec4 specularLight; + glm::vec4 fog_colour; + int fog_enabled; + float fog_begin; + float fog_end; + float timeSec; + }; + using WaterHighPSO = typename gfx_api::pipeline_state_helper, primitive_type::triangles, index_type::u32, - std::tuple>, + std::tuple>, std::tuple< vertex_buffer_description<16, gfx_api::vertex_attribute_input_rate::vertex, vertex_attribute_description> // WaterVertex, w is depth >, std::tuple< @@ -1072,7 +1087,7 @@ namespace gfx_api texture_description<4, sampler_type::anisotropic_repeat>, // specular map1 texture_description<5, sampler_type::anisotropic_repeat>, // specular map2 texture_description<6, sampler_type::bilinear> // lightmap - >, SHADER_WATER>; + >, SHADER_WATER_HIGH>; template<> struct constant_buffer_type diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index 6812127a5e3..da0cb73d932 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -713,13 +713,13 @@ static const std::map shader_to_file_table = { "ModelViewProjectionMatrix", "ModelUVLightmapMatrix", "ModelUV1Matrix", "ModelUV2Matrix", "cameraPos", "sunPos", "emissiveLight", "ambientLight", "diffuseLight", "specularLight", - "fogColor", "fogEnabled", "fogEnd", "fogStart", "timeSec", "quality", - "tex1", "tex2", "tex1_nm", "tex2_nm", "tex1_sm", "tex2_sm", "lightmap_tex" } }), - std::make_pair(SHADER_WATER_HIGH, program_data{ "high water program", "shaders/terrain_water.vert", "shaders/water.frag", + "fogColor", "fogEnabled", "fogEnd", "fogStart", "timeSec", + "tex1", "tex2", "lightmap_tex" } }), + std::make_pair(SHADER_WATER_HIGH, program_data{ "high water program", "shaders/terrain_water_high.vert", "shaders/terrain_water_high.frag", { "ModelViewProjectionMatrix", "ModelUVLightmapMatrix", "ModelUV1Matrix", "ModelUV2Matrix", "cameraPos", "sunPos", "emissiveLight", "ambientLight", "diffuseLight", "specularLight", - "fogColor", "fogEnabled", "fogEnd", "fogStart", "timeSec", "quality", + "fogColor", "fogEnabled", "fogEnd", "fogStart", "timeSec", "tex1", "tex2", "tex1_nm", "tex2_nm", "tex1_sm", "tex2_sm", "lightmap_tex" } }), std::make_pair(SHADER_WATER_CLASSIC, program_data{ "classic water program", "shaders/terrain_water_classic.vert", "shaders/terrain_water_classic.frag", { "ModelViewProjectionMatrix", "ModelUVLightmapMatrix", "ShadowMapMVPMatrix", "ModelUV1Matrix", "ModelUV2Matrix", @@ -1016,6 +1016,7 @@ desc(createInfo.state_desc), vertex_buffer_desc(createInfo.attribute_description uniform_binding_entry(), uniform_setting_func(), uniform_binding_entry(), + uniform_binding_entry(), uniform_binding_entry(), uniform_binding_entry(), uniform_binding_entry(), @@ -1998,7 +1999,30 @@ void gl_pipeline_state_object::set_constants(const gfx_api::constant_buffer_type setUniforms(i++, cbuf.fog_begin); setUniforms(i++, cbuf.fog_end); setUniforms(i++, cbuf.timeSec); - setUniforms(i++, cbuf.quality); + // textures: + setUniforms(i++, 0); + setUniforms(i++, 1); + setUniforms(i++, 2); // lightmap_tex +} + +void gl_pipeline_state_object::set_constants(const gfx_api::constant_buffer_type& cbuf) +{ + int i = 0; + setUniforms(i++, cbuf.ModelViewProjectionMatrix); + setUniforms(i++, cbuf.ModelUVLightmapMatrix); + setUniforms(i++, cbuf.ModelUV1Matrix); + setUniforms(i++, cbuf.ModelUV2Matrix); + setUniforms(i++, cbuf.cameraPos); + setUniforms(i++, cbuf.sunPos); + setUniforms(i++, cbuf.emissiveLight); + setUniforms(i++, cbuf.ambientLight); + setUniforms(i++, cbuf.diffuseLight); + setUniforms(i++, cbuf.specularLight); + setUniforms(i++, cbuf.fog_colour); + setUniforms(i++, cbuf.fog_enabled); + setUniforms(i++, cbuf.fog_begin); + setUniforms(i++, cbuf.fog_end); + setUniforms(i++, cbuf.timeSec); // textures: setUniforms(i++, 0); setUniforms(i++, 1); diff --git a/lib/ivis_opengl/gfx_api_gl.h b/lib/ivis_opengl/gfx_api_gl.h index 98df99b8f42..fd52b9bd2d4 100644 --- a/lib/ivis_opengl/gfx_api_gl.h +++ b/lib/ivis_opengl/gfx_api_gl.h @@ -241,6 +241,7 @@ struct gl_pipeline_state_object final : public gfx_api::pipeline_state_object void set_constants(const gfx_api::constant_buffer_type& cbuf); void set_constants(const gfx_api::TerrainCombinedUniforms& cbuf); void set_constants(const gfx_api::constant_buffer_type& cbuf); + void set_constants(const gfx_api::constant_buffer_type& cbuf); void set_constants(const gfx_api::constant_buffer_type& cbuf); void set_constants(const gfx_api::constant_buffer_type& cbuf); void set_constants(const gfx_api::constant_buffer_type& cbuf); diff --git a/lib/ivis_opengl/gfx_api_vk.cpp b/lib/ivis_opengl/gfx_api_vk.cpp index fa14d5bbaf7..f6c6903499a 100644 --- a/lib/ivis_opengl/gfx_api_vk.cpp +++ b/lib/ivis_opengl/gfx_api_vk.cpp @@ -1128,7 +1128,7 @@ static const std::map spv_files std::make_pair(SHADER_TERRAIN_COMBINED_MEDIUM, shader_infos{ "shaders/vk/terrain_combined.vert.spv", "shaders/vk/terrain_combined_medium.frag.spv", true, true, true, true }), std::make_pair(SHADER_TERRAIN_COMBINED_HIGH, shader_infos{ "shaders/vk/terrain_combined.vert.spv", "shaders/vk/terrain_combined_high.frag.spv", true, true, true, true }), std::make_pair(SHADER_WATER, shader_infos{ "shaders/vk/terrain_water.vert.spv", "shaders/vk/water.frag.spv", true }), - std::make_pair(SHADER_WATER_HIGH, shader_infos{ "shaders/vk/terrain_water.vert.spv", "shaders/vk/water.frag.spv", true }), + std::make_pair(SHADER_WATER_HIGH, shader_infos{ "shaders/vk/terrain_water_high.vert.spv", "shaders/vk/terrain_water_high.frag.spv", true }), std::make_pair(SHADER_WATER_CLASSIC, shader_infos{ "shaders/vk/terrain_water_classic.vert.spv", "shaders/vk/terrain_water_classic.frag.spv", true }), std::make_pair(SHADER_RECT, shader_infos{ "shaders/vk/rect.vert.spv", "shaders/vk/rect.frag.spv" }), std::make_pair(SHADER_RECT_INSTANCED, shader_infos{ "shaders/vk/rect_instanced.vert.spv", "shaders/vk/rect_instanced.frag.spv" }), diff --git a/src/terrain.cpp b/src/terrain.cpp index 1d805158eff..1311959c730 100644 --- a/src/terrain.cpp +++ b/src/terrain.cpp @@ -797,7 +797,20 @@ static gfx_api::texture_array* groundNormalArr = nullptr; static gfx_api::texture_array* groundSpecularArr = nullptr; static gfx_api::texture_array* groundHeightArr = nullptr; -struct WaterTextures +struct WaterTextures_Normal +{ + gfx_api::texture* tex1 = nullptr; + gfx_api::texture* tex2 = nullptr; + +public: + void clear() + { + delete tex1; tex1 = nullptr; + delete tex2; tex2 = nullptr; + } +}; + +struct WaterTextures_High { gfx_api::texture* tex1 = nullptr; gfx_api::texture* tex2 = nullptr; @@ -818,7 +831,9 @@ struct WaterTextures delete tex2_sm; tex2_sm = nullptr; } }; -static WaterTextures waterTextures; + +static WaterTextures_Normal waterTexturesNormal; +static WaterTextures_High waterTexturesHigh; static gfx_api::texture* waterClassicTexture = nullptr; // only used for classic mode gfx_api::texture* getWaterClassicTexture() @@ -838,9 +853,9 @@ gfx_api::texture* getWaterClassicTexture() void loadWaterTextures(int maxTerrainTextureSize) { - waterTextures.clear(); + waterTexturesNormal.clear(); + waterTexturesHigh.clear(); - // load water textures auto checkTex = [maxTerrainTextureSize](const WzString &fileName, gfx_api::texture_type type) -> gfx_api::texture* { WzString fullName = "texpages/" + fileName; auto imageLoadFilename = gfx_api::imageLoadFilenameFromInputFilename(fullName); @@ -850,13 +865,26 @@ void loadWaterTextures(int maxTerrainTextureSize) } return gfx_api::context::get().loadTextureFromFile(imageLoadFilename.toUtf8().c_str(), type, maxTerrainTextureSize, maxTerrainTextureSize); }; - waterTextures.tex1 = checkTex("page-80-water-1.png", gfx_api::texture_type::game_texture); - waterTextures.tex2 = checkTex("page-81-water-2.png", (terrainShaderQuality != TerrainShaderQuality::NORMAL_MAPPING) ? gfx_api::texture_type::specular_map : gfx_api::texture_type::game_texture); - // check water optional textures - waterTextures.tex1_nm = checkTex("page-80-water-1_nm.png", gfx_api::texture_type::normal_map); - waterTextures.tex2_nm = checkTex("page-81-water-2_nm.png", gfx_api::texture_type::normal_map); - waterTextures.tex1_sm = checkTex("page-80-water-1_sm.png", gfx_api::texture_type::specular_map); - waterTextures.tex2_sm = checkTex("page-81-water-2_sm.png", gfx_api::texture_type::specular_map); + + if (terrainShaderQuality == TerrainShaderQuality::MEDIUM) + { + waterTexturesNormal.tex1 = checkTex("page-80-water-1.png", gfx_api::texture_type::game_texture); + waterTexturesNormal.tex2 = checkTex("page-81-water-2.png", gfx_api::texture_type::specular_map); + } + else if (terrainShaderQuality == TerrainShaderQuality::NORMAL_MAPPING) + { + waterTexturesHigh.tex1 = checkTex("page-80-water-1.png", gfx_api::texture_type::game_texture); + waterTexturesHigh.tex2 = checkTex("page-81-water-2.png", gfx_api::texture_type::game_texture); + // check water optional textures + waterTexturesHigh.tex1_nm = checkTex("page-80-water-1_nm.png", gfx_api::texture_type::normal_map); + waterTexturesHigh.tex2_nm = checkTex("page-81-water-2_nm.png", gfx_api::texture_type::normal_map); + waterTexturesHigh.tex1_sm = checkTex("page-80-water-1_sm.png", gfx_api::texture_type::specular_map); + waterTexturesHigh.tex2_sm = checkTex("page-81-water-2_sm.png", gfx_api::texture_type::specular_map); + } + else + { + ASSERT_OR_RETURN(, false, "Unexpected terrainShaderQuality: %u", static_cast(terrainShaderQuality)); + } } void loadTerrainTextures_SinglePass(MAP_TILESET mapTileset) @@ -1444,7 +1472,8 @@ void shutdownTerrain() delete groundSpecularArr; groundSpecularArr = nullptr; delete groundHeightArr; groundHeightArr = nullptr; - waterTextures.clear(); + waterTexturesNormal.clear(); + waterTexturesHigh.clear(); delete waterClassicTexture; waterClassicTexture = nullptr; delete decalTexArr; decalTexArr = nullptr; @@ -1908,7 +1937,7 @@ void drawTerrain(const glm::mat4 &mvp, const glm::mat4& viewMatrix, const Vector * sunPos and cameraPos in Model=WorldSpace */ template -void drawWaterImpl(const glm::mat4 &ModelViewProjection, const Vector3f &cameraPos, const Vector3f &sunPos) +void drawWaterNormalImpl(const glm::mat4 &ModelViewProjection, const Vector3f &cameraPos, const Vector3f &sunPos) { if (!waterIndexVBO) { @@ -1929,13 +1958,11 @@ void drawWaterImpl(const glm::mat4 &ModelViewProjection, const Vector3f &cameraP const auto ModelUV2 = glm::transpose(glm::mat4(paramsX2, paramsY2, glm::vec4(0,0,1,0), glm::vec4(0,0,0,1))); const auto &renderState = getCurrentRenderState(); - ASSERT_OR_RETURN(, waterTextures.tex1 && waterTextures.tex2, "Failed to load water texture"); + ASSERT_OR_RETURN(, waterTexturesNormal.tex1 && waterTexturesNormal.tex2, "Failed to load water texture"); PSO::get().bind(); PSO::get().bind_textures( - waterTextures.tex1, waterTextures.tex2, - waterTextures.tex1_nm, waterTextures.tex2_nm, - waterTextures.tex1_sm, waterTextures.tex2_sm, + waterTexturesNormal.tex1, waterTexturesNormal.tex2, lightmap_texture); PSO::get().bind_vertex_buffers(waterVBO); PSO::get().bind_constants({ @@ -1943,7 +1970,7 @@ void drawWaterImpl(const glm::mat4 &ModelViewProjection, const Vector3f &cameraP glm::vec4(cameraPos, 0), glm::vec4(glm::normalize(sunPos), 0), pie_GetLighting0(LIGHT_EMISSIVE), pie_GetLighting0(LIGHT_AMBIENT), pie_GetLighting0(LIGHT_DIFFUSE), pie_GetLighting0(LIGHT_SPECULAR), getFogColorVec4(), renderState.fogEnabled, renderState.fogBegin, renderState.fogEnd, - waterOffset*10, static_cast(terrainShaderQuality) + waterOffset*10 }); gfx_api::context::get().bind_index_buffer(*waterIndexVBO, gfx_api::index_type::u32); @@ -1973,6 +2000,72 @@ void drawWaterImpl(const glm::mat4 &ModelViewProjection, const Vector3f &cameraP } } +template +void drawWaterHighImpl(const glm::mat4 &ModelViewProjection, const Vector3f &cameraPos, const Vector3f &sunPos) +{ + if (!waterIndexVBO) + { + return; // no water + } + + const glm::vec4 paramsXLight(1.0f / world_coord(mapWidth) *((float)mapWidth / (float)lightmapWidth), 0, 0, 0); + const glm::vec4 paramsYLight(0, 0, -1.0f / world_coord(mapHeight) *((float)mapHeight / (float)lightmapHeight), 0); + // shift the lightmap half a tile as lights are supposed to be placed at the center of a tile + const glm::mat4 lightMatrix = glm::translate(glm::vec3(1.f / (float)lightmapWidth / 2, 1.f / (float)lightmapHeight / 2, 0.f)); + const auto ModelUVLightmap = lightMatrix * glm::transpose(glm::mat4(paramsXLight, paramsYLight, glm::vec4(0,0,1,0), glm::vec4(0,0,0,1))); + + const glm::vec4 paramsX(0, 0, -1.0f / world_coord(4), 0); + const glm::vec4 paramsY(1.0f / world_coord(4), 0, 0, 0); + const glm::vec4 paramsX2(0, 0, -1.0f / world_coord(5), 0); + const glm::vec4 paramsY2(1.0f / world_coord(5), 0, 0, 0); + const auto ModelUV1 = glm::translate(glm::vec3(waterOffset, 0.f, 0.f)) * glm::transpose(glm::mat4(paramsX, paramsY, glm::vec4(0,0,1,0), glm::vec4(0,0,0,1))); + const auto ModelUV2 = glm::transpose(glm::mat4(paramsX2, paramsY2, glm::vec4(0,0,1,0), glm::vec4(0,0,0,1))); + const auto &renderState = getCurrentRenderState(); + + ASSERT_OR_RETURN(, waterTexturesHigh.tex1 && waterTexturesHigh.tex2, "Failed to load water texture"); + PSO::get().bind(); + + PSO::get().bind_textures( + waterTexturesHigh.tex1, waterTexturesHigh.tex2, + waterTexturesHigh.tex1_nm, waterTexturesHigh.tex2_nm, + waterTexturesHigh.tex1_sm, waterTexturesHigh.tex2_sm, + lightmap_texture); + PSO::get().bind_vertex_buffers(waterVBO); + PSO::get().bind_constants({ + ModelViewProjection, ModelUVLightmap, ModelUV1, ModelUV2, + glm::vec4(cameraPos, 0), glm::vec4(glm::normalize(sunPos), 0), + pie_GetLighting0(LIGHT_EMISSIVE), pie_GetLighting0(LIGHT_AMBIENT), pie_GetLighting0(LIGHT_DIFFUSE), pie_GetLighting0(LIGHT_SPECULAR), + getFogColorVec4(), renderState.fogEnabled, renderState.fogBegin, renderState.fogEnd, + waterOffset*10 + }); + + gfx_api::context::get().bind_index_buffer(*waterIndexVBO, gfx_api::index_type::u32); + + for (int x = 0; x < xSectors; x++) + { + for (int y = 0; y < ySectors; y++) + { + if (sectors[x * ySectors + y].draw) + { + addDrawRangeElements( + sectors[x * ySectors + y].geometryOffset, + sectors[x * ySectors + y].geometryOffset + sectors[x * ySectors + y].geometrySize, + sectors[x * ySectors + y].waterIndexSize, + sectors[x * ySectors + y].waterIndexOffset); + } + } + } + finishDrawRangeElements(); + PSO::get().unbind_vertex_buffers(waterVBO); + gfx_api::context::get().unbind_index_buffer(*waterIndexVBO); + + // move the water + if (!gamePaused()) + { + waterOffset += graphicsTimeAdjustedIncrement(0.1f); + } +} + void drawWaterClassic(const glm::mat4 &ModelViewProjection, const glm::mat4 &ModelUVLightmap, const Vector3f &cameraPos, const Vector3f &sunPos) { if (!waterIndexVBO) @@ -2039,10 +2132,10 @@ void drawWater(const glm::mat4 &ModelViewProjection, const Vector3f &cameraPos, // already drawn return; case TerrainShaderQuality::MEDIUM: - drawWaterImpl(ModelViewProjection, cameraPos, sunPos); + drawWaterNormalImpl(ModelViewProjection, cameraPos, sunPos); return; case TerrainShaderQuality::NORMAL_MAPPING: - drawWaterImpl(ModelViewProjection, cameraPos, sunPos); + drawWaterHighImpl(ModelViewProjection, cameraPos, sunPos); return; } } From 2380690c97f2d068652675a09ee356f69279cf19 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Sun, 10 Sep 2023 15:33:49 -0400 Subject: [PATCH 2/7] Use texture arrays in the high water shader --- data/base/shaders/terrain_water_high.frag | 18 ++- data/base/shaders/vk/terrain_water_high.frag | 19 ++- lib/ivis_opengl/gfx_api.h | 11 +- lib/ivis_opengl/gfx_api_gl.cpp | 7 +- src/terrain.cpp | 123 ++++++++++++++----- 5 files changed, 111 insertions(+), 67 deletions(-) diff --git a/data/base/shaders/terrain_water_high.frag b/data/base/shaders/terrain_water_high.frag index 49b1b9ae05c..b1a09173d82 100644 --- a/data/base/shaders/terrain_water_high.frag +++ b/data/base/shaders/terrain_water_high.frag @@ -5,12 +5,9 @@ #define WZ_MIP_LOAD_BIAS 0.f // -uniform sampler2D tex1; -uniform sampler2D tex2; -uniform sampler2D tex1_nm; -uniform sampler2D tex2_nm; -uniform sampler2D tex1_sm; -uniform sampler2D tex2_sm; +uniform sampler2DArray tex; +uniform sampler2DArray tex_nm; +uniform sampler2DArray tex_sm; uniform sampler2D lightmap_tex; // light colors/intensity: @@ -27,6 +24,7 @@ uniform float fogStart; #if (!defined(GL_ES) && (__VERSION__ >= 130)) || (defined(GL_ES) && (__VERSION__ >= 300)) #define NEWGL #define FRAGMENT_INPUT in +#define texture2DArray(tex,coord,bias) texture(tex,coord,bias) #else #define texture(tex,uv,bias) texture2D(tex,uv,bias) #define FRAGMENT_INPUT varying @@ -56,8 +54,8 @@ vec4 main_bumpMapping() vec2 uv1 = uv1_uv2.xy; vec2 uv2 = uv1_uv2.zw; - vec3 N1 = texture(tex1_nm, uv2, WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace - vec3 N2 = texture(tex2_nm, uv1, WZ_MIP_LOAD_BIAS).xzy; + vec3 N1 = texture2DArray(tex_nm, vec3(uv2, 0.f), WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace + vec3 N2 = texture2DArray(tex_nm, vec3(uv1, 1.f), WZ_MIP_LOAD_BIAS).xzy; vec3 N; //use overlay blending to mix normal maps properly N.x = N1.x < 0.5 ? (2.0 * N1.x * N2.x) : (1.0 - 2.0 * (1.0 - N1.x) * (1.0 - N2.x)); N.z = N1.z < 0.5 ? (2.0 * N1.z * N2.z) : (1.0 - 2.0 * (1.0 - N1.z) * (1.0 - N2.z)); @@ -71,12 +69,12 @@ vec4 main_bumpMapping() float lambertTerm = max(dot(N, lightDir), 0.0); // diffuse lighting // Gaussian specular term computation - float gloss = texture(tex1_sm, uv1, WZ_MIP_LOAD_BIAS).r * texture(tex2_sm, uv2, WZ_MIP_LOAD_BIAS).r; + float gloss = texture2DArray(tex_sm, vec3(uv1, 0.f), WZ_MIP_LOAD_BIAS).r * texture2DArray(tex_sm, vec3(uv2, 1.f), WZ_MIP_LOAD_BIAS).r; vec3 H = normalize(halfVec); float exponent = acos(dot(H, N)) / (gloss + 0.05); float gaussianTerm = exp(-(exponent * exponent)); - vec4 fragColor = (texture(tex1, uv1, WZ_MIP_LOAD_BIAS)+texture(tex2, uv2, WZ_MIP_LOAD_BIAS)) * (gloss+vec4(0.08,0.13,0.15,1.0)); + vec4 fragColor = (texture2DArray(tex, vec3(uv1, 0.f), WZ_MIP_LOAD_BIAS)+texture2DArray(tex, vec3(uv2, 1.f), WZ_MIP_LOAD_BIAS)) * (gloss+vec4(0.08,0.13,0.15,1.0)); fragColor = fragColor*(ambientLight+diffuseLight*lambertTerm) + specularLight*(1.0-gloss)*gaussianTerm*vec4(1.0,0.843,0.686,1.0); vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap, 0.f); vec4 color = fragColor * vec4(vec3(lightmap_vec4.a), 1.f); // ... * tile brightness / ambient occlusion (stored in lightmap.a); diff --git a/data/base/shaders/vk/terrain_water_high.frag b/data/base/shaders/vk/terrain_water_high.frag index a881aa4a5cd..0dc63317b9c 100644 --- a/data/base/shaders/vk/terrain_water_high.frag +++ b/data/base/shaders/vk/terrain_water_high.frag @@ -2,13 +2,10 @@ layout (constant_id = 0) const float WZ_MIP_LOAD_BIAS = 0.f; -layout(set = 1, binding = 0) uniform sampler2D tex1; -layout(set = 1, binding = 1) uniform sampler2D tex2; -layout(set = 1, binding = 2) uniform sampler2D tex1_nm; -layout(set = 1, binding = 3) uniform sampler2D tex2_nm; -layout(set = 1, binding = 4) uniform sampler2D tex1_sm; -layout(set = 1, binding = 5) uniform sampler2D tex2_sm; -layout(set = 1, binding = 6) uniform sampler2D lightmap_tex; +layout(set = 1, binding = 0) uniform sampler2DArray tex; +layout(set = 1, binding = 1) uniform sampler2DArray tex_nm; +layout(set = 1, binding = 2) uniform sampler2DArray tex_sm; +layout(set = 1, binding = 3) uniform sampler2D lightmap_tex; layout(std140, set = 0, binding = 0) uniform cbuffer { mat4 ModelViewProjectionMatrix; @@ -47,8 +44,8 @@ vec4 main_bumpMapping() vec2 uv1 = uv1_uv2.xy; vec2 uv2 = uv1_uv2.zw; - vec3 N1 = texture(tex1_nm, uv2, WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace - vec3 N2 = texture(tex2_nm, uv1, WZ_MIP_LOAD_BIAS).xzy; + vec3 N1 = texture(tex_nm, vec3(uv2, 0.f), WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace + vec3 N2 = texture(tex_nm, vec3(uv1, 1.f), WZ_MIP_LOAD_BIAS).xzy; vec3 N; //use overlay blending to mix normal maps properly N.x = N1.x < 0.5 ? (2.0 * N1.x * N2.x) : (1.0 - 2.0 * (1.0 - N1.x) * (1.0 - N2.x)); N.z = N1.z < 0.5 ? (2.0 * N1.z * N2.z) : (1.0 - 2.0 * (1.0 - N1.z) * (1.0 - N2.z)); @@ -61,12 +58,12 @@ vec4 main_bumpMapping() float lambertTerm = max(dot(N, lightDir), 0.0); // diffuse lighting // Gaussian specular term computation - float gloss = texture(tex1_sm, uv1, WZ_MIP_LOAD_BIAS).r * texture(tex2_sm, uv2, WZ_MIP_LOAD_BIAS).r; + float gloss = texture(tex_sm, vec3(uv1, 0.f), WZ_MIP_LOAD_BIAS).r * texture(tex_sm, vec3(uv2, 1.f), WZ_MIP_LOAD_BIAS).r; vec3 H = normalize(halfVec); float exponent = acos(dot(H, N)) / (gloss + 0.05); float gaussianTerm = exp(-(exponent * exponent)); - vec4 fragColor = (texture(tex1, uv1, WZ_MIP_LOAD_BIAS)+texture(tex2, uv2, WZ_MIP_LOAD_BIAS)) * (gloss+vec4(0.08,0.13,0.15,1.0)); + vec4 fragColor = (texture(tex, vec3(uv1, 0.f), WZ_MIP_LOAD_BIAS)+texture(tex, vec3(uv2, 1.f), WZ_MIP_LOAD_BIAS)) * (gloss+vec4(0.08,0.13,0.15,1.0)); fragColor = fragColor*(ambientLight+diffuseLight*lambertTerm) + specularLight*(1.0-gloss)*gaussianTerm*vec4(1.0,0.843,0.686,1.0); vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap, 0.f); vec4 color = fragColor * vec4(vec3(lightmap_vec4.a), 1.f); // ... * tile brightness / ambient occlusion (stored in lightmap.a); diff --git a/lib/ivis_opengl/gfx_api.h b/lib/ivis_opengl/gfx_api.h index b8c66e37ca8..0c8a358356c 100644 --- a/lib/ivis_opengl/gfx_api.h +++ b/lib/ivis_opengl/gfx_api.h @@ -1080,13 +1080,10 @@ namespace gfx_api std::tuple< vertex_buffer_description<16, gfx_api::vertex_attribute_input_rate::vertex, vertex_attribute_description> // WaterVertex, w is depth >, std::tuple< - texture_description<0, sampler_type::anisotropic_repeat>, // tex1 - texture_description<1, sampler_type::anisotropic_repeat>, // tex2 - texture_description<2, sampler_type::anisotropic_repeat>, // normal map1 - texture_description<3, sampler_type::anisotropic_repeat>, // normal map2 - texture_description<4, sampler_type::anisotropic_repeat>, // specular map1 - texture_description<5, sampler_type::anisotropic_repeat>, // specular map2 - texture_description<6, sampler_type::bilinear> // lightmap + texture_description<0, sampler_type::anisotropic_repeat, pixel_format_target::texture_2d_array>, // textures + texture_description<1, sampler_type::anisotropic_repeat, pixel_format_target::texture_2d_array>, // normal maps + texture_description<2, sampler_type::anisotropic_repeat, pixel_format_target::texture_2d_array>, // specular maps + texture_description<3, sampler_type::bilinear> // lightmap >, SHADER_WATER_HIGH>; template<> diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index da0cb73d932..034a49eefec 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -720,7 +720,7 @@ static const std::map shader_to_file_table = "cameraPos", "sunPos", "emissiveLight", "ambientLight", "diffuseLight", "specularLight", "fogColor", "fogEnabled", "fogEnd", "fogStart", "timeSec", - "tex1", "tex2", "tex1_nm", "tex2_nm", "tex1_sm", "tex2_sm", "lightmap_tex" } }), + "tex", "tex_nm", "tex_sm", "lightmap_tex" } }), std::make_pair(SHADER_WATER_CLASSIC, program_data{ "classic water program", "shaders/terrain_water_classic.vert", "shaders/terrain_water_classic.frag", { "ModelViewProjectionMatrix", "ModelUVLightmapMatrix", "ShadowMapMVPMatrix", "ModelUV1Matrix", "ModelUV2Matrix", "cameraPos", "sunPos", @@ -2027,10 +2027,7 @@ void gl_pipeline_state_object::set_constants(const gfx_api::constant_buffer_type setUniforms(i++, 0); setUniforms(i++, 1); setUniforms(i++, 2); - setUniforms(i++, 3); - setUniforms(i++, 4); - setUniforms(i++, 5); - setUniforms(i++, 6); // lightmap_tex + setUniforms(i++, 3); // lightmap_tex } void gl_pipeline_state_object::set_constants(const gfx_api::constant_buffer_type& cbuf) diff --git a/src/terrain.cpp b/src/terrain.cpp index 1311959c730..9e1ba953e41 100644 --- a/src/terrain.cpp +++ b/src/terrain.cpp @@ -812,23 +812,16 @@ struct WaterTextures_Normal struct WaterTextures_High { - gfx_api::texture* tex1 = nullptr; - gfx_api::texture* tex2 = nullptr; - // water optional textures. null if none - gfx_api::texture* tex1_nm = nullptr; - gfx_api::texture* tex2_nm = nullptr; - gfx_api::texture* tex1_sm = nullptr; - gfx_api::texture* tex2_sm = nullptr; + gfx_api::texture_array* tex = nullptr; + gfx_api::texture_array* tex_nm = nullptr; + gfx_api::texture_array* tex_sm = nullptr; public: void clear() { - delete tex1; tex1 = nullptr; - delete tex2; tex2 = nullptr; - delete tex1_nm; tex1_nm = nullptr; - delete tex2_nm; tex2_nm = nullptr; - delete tex1_sm; tex1_sm = nullptr; - delete tex2_sm; tex2_sm = nullptr; + delete tex; tex = nullptr; + delete tex_nm; tex_nm = nullptr; + delete tex_sm; tex_sm = nullptr; } }; @@ -856,30 +849,92 @@ void loadWaterTextures(int maxTerrainTextureSize) waterTexturesNormal.clear(); waterTexturesHigh.clear(); - auto checkTex = [maxTerrainTextureSize](const WzString &fileName, gfx_api::texture_type type) -> gfx_api::texture* { - WzString fullName = "texpages/" + fileName; - auto imageLoadFilename = gfx_api::imageLoadFilenameFromInputFilename(fullName); - if (!PHYSFS_exists(imageLoadFilename)) - { - return nullptr; - } - return gfx_api::context::get().loadTextureFromFile(imageLoadFilename.toUtf8().c_str(), type, maxTerrainTextureSize, maxTerrainTextureSize); - }; - if (terrainShaderQuality == TerrainShaderQuality::MEDIUM) { + auto checkTex = [maxTerrainTextureSize](const WzString &fileName, gfx_api::texture_type type) -> gfx_api::texture* { + WzString fullName = "texpages/" + fileName; + auto imageLoadFilename = gfx_api::imageLoadFilenameFromInputFilename(fullName); + if (!PHYSFS_exists(imageLoadFilename)) + { + return nullptr; + } + return gfx_api::context::get().loadTextureFromFile(imageLoadFilename.toUtf8().c_str(), type, maxTerrainTextureSize, maxTerrainTextureSize); + }; + waterTexturesNormal.tex1 = checkTex("page-80-water-1.png", gfx_api::texture_type::game_texture); waterTexturesNormal.tex2 = checkTex("page-81-water-2.png", gfx_api::texture_type::specular_map); } else if (terrainShaderQuality == TerrainShaderQuality::NORMAL_MAPPING) { - waterTexturesHigh.tex1 = checkTex("page-80-water-1.png", gfx_api::texture_type::game_texture); - waterTexturesHigh.tex2 = checkTex("page-81-water-2.png", gfx_api::texture_type::game_texture); - // check water optional textures - waterTexturesHigh.tex1_nm = checkTex("page-80-water-1_nm.png", gfx_api::texture_type::normal_map); - waterTexturesHigh.tex2_nm = checkTex("page-81-water-2_nm.png", gfx_api::texture_type::normal_map); - waterTexturesHigh.tex1_sm = checkTex("page-80-water-1_sm.png", gfx_api::texture_type::specular_map); - waterTexturesHigh.tex2_sm = checkTex("page-81-water-2_sm.png", gfx_api::texture_type::specular_map); + std::vector waterTextureFilenames; + std::vector waterTextureFilenames_nm; + std::vector waterTextureFilenames_sm; + + auto optTexturenameToPath = [](const WzString& textureFilename) -> WzString { + if (textureFilename.isEmpty()) + { + return WzString(); + } + WzString fullName = "texpages/" + textureFilename; + auto imageLoadFilename = gfx_api::imageLoadFilenameFromInputFilename(fullName); + if (!PHYSFS_exists(imageLoadFilename)) + { + return WzString(); + } + return fullName; + }; + + // check water optional textures.push_back(optTexturenameToPath("page-80-water-1.png")); + waterTextureFilenames.push_back(optTexturenameToPath("page-81-water-2.png")); + waterTextureFilenames_nm.push_back(optTexturenameToPath("page-80-water-1_nm.png")); + waterTextureFilenames_nm.push_back(optTexturenameToPath("page-81-water-2_nm.png")); + waterTextureFilenames_sm.push_back(optTexturenameToPath("page-80-water-1_sm.png")); + waterTextureFilenames_sm.push_back(optTexturenameToPath("page-81-water-2_sm.png")); + + if (!std::all_of(waterTextureFilenames.begin(), waterTextureFilenames.end(), [](const WzString& texturePath) -> bool { return !texturePath.isEmpty(); })) + { + debug(LOG_FATAL, "Missing one or more base water textures?"); + return; + } + + waterTexturesHigh.tex = gfx_api::context::get().loadTextureArrayFromFiles(waterTextureFilenames, gfx_api::texture_type::game_texture, maxTerrainTextureSize, maxTerrainTextureSize, nullptr, []() { resDoResLoadCallback(); }); + waterTexturesHigh.tex_nm = nullptr; + waterTexturesHigh.tex_sm = nullptr; + + if (std::any_of(waterTextureFilenames_nm.begin(), waterTextureFilenames_nm.end(), [](const WzString& filename) { + return !filename.isEmpty(); + })) + { + waterTexturesHigh.tex_nm = gfx_api::context::get().loadTextureArrayFromFiles(waterTextureFilenames_nm, gfx_api::texture_type::normal_map, maxTerrainTextureSize, maxTerrainTextureSize, [](int width, int height, int channels) -> std::unique_ptr { + std::unique_ptr pDefaultNormalMap = std::unique_ptr(new iV_Image); + pDefaultNormalMap->allocate(width, height, channels, true); + // default normal map: (0,0,1) + unsigned char* pBmpWrite = pDefaultNormalMap->bmp_w(); + memset(pBmpWrite, 0x7f, pDefaultNormalMap->data_size()); + if (channels >= 3) + { + size_t pixelIncrement = static_cast(channels); + for (size_t b = 0; b < pDefaultNormalMap->data_size(); b += pixelIncrement) + { + pBmpWrite[b+2] = 0xff; // blue=z + } + } + return pDefaultNormalMap; + }, []() { resDoResLoadCallback(); }); + ASSERT(waterTexturesHigh.tex_nm != nullptr, "Failed to load water normals"); + } + if (std::any_of(waterTextureFilenames_sm.begin(), waterTextureFilenames_sm.end(), [](const WzString& filename) { + return !filename.isEmpty(); + })) + { + waterTexturesHigh.tex_sm = gfx_api::context::get().loadTextureArrayFromFiles(waterTextureFilenames_sm, gfx_api::texture_type::specular_map, maxTerrainTextureSize, maxTerrainTextureSize, [](int width, int height, int channels) -> std::unique_ptr { + std::unique_ptr pDefaultSpecularMap = std::unique_ptr(new iV_Image); + // default specular map: 0 + pDefaultSpecularMap->allocate(width, height, channels, true); + return pDefaultSpecularMap; + }, []() { resDoResLoadCallback(); }); + ASSERT(waterTexturesHigh.tex_sm != nullptr, "Failed to load water specular maps"); + } } else { @@ -2022,13 +2077,13 @@ void drawWaterHighImpl(const glm::mat4 &ModelViewProjection, const Vector3f &cam const auto ModelUV2 = glm::transpose(glm::mat4(paramsX2, paramsY2, glm::vec4(0,0,1,0), glm::vec4(0,0,0,1))); const auto &renderState = getCurrentRenderState(); - ASSERT_OR_RETURN(, waterTexturesHigh.tex1 && waterTexturesHigh.tex2, "Failed to load water texture"); + ASSERT_OR_RETURN(, waterTexturesHigh.tex, "Failed to load water textures"); PSO::get().bind(); PSO::get().bind_textures( - waterTexturesHigh.tex1, waterTexturesHigh.tex2, - waterTexturesHigh.tex1_nm, waterTexturesHigh.tex2_nm, - waterTexturesHigh.tex1_sm, waterTexturesHigh.tex2_sm, + waterTexturesHigh.tex, + waterTexturesHigh.tex_nm, + waterTexturesHigh.tex_sm, lightmap_texture); PSO::get().bind_vertex_buffers(waterVBO); PSO::get().bind_constants({ From 76065badc94d0896e27e2bf2f6836f9a8b5f7239 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Sun, 10 Sep 2023 17:51:14 -0400 Subject: [PATCH 3/7] Remove some branches in high water shader --- data/base/shaders/terrain_water_high.frag | 16 +++++++--------- data/base/shaders/vk/terrain_water_high.frag | 17 ++++++++--------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/data/base/shaders/terrain_water_high.frag b/data/base/shaders/terrain_water_high.frag index b1a09173d82..de18ea15fda 100644 --- a/data/base/shaders/terrain_water_high.frag +++ b/data/base/shaders/terrain_water_high.frag @@ -56,15 +56,13 @@ vec4 main_bumpMapping() vec3 N1 = texture2DArray(tex_nm, vec3(uv2, 0.f), WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace vec3 N2 = texture2DArray(tex_nm, vec3(uv1, 1.f), WZ_MIP_LOAD_BIAS).xzy; - vec3 N; //use overlay blending to mix normal maps properly - N.x = N1.x < 0.5 ? (2.0 * N1.x * N2.x) : (1.0 - 2.0 * (1.0 - N1.x) * (1.0 - N2.x)); - N.z = N1.z < 0.5 ? (2.0 * N1.z * N2.z) : (1.0 - 2.0 * (1.0 - N1.z) * (1.0 - N2.z)); - N.y = N1.y < 0.5 ? (2.0 * N1.y * N2.y) : (1.0 - 2.0 * (1.0 - N1.y) * (1.0 - N2.y)); - if (N == vec3(0.0,0.0,0.0)) { - N = vec3(0.0,1.0,0.0); - } else { - N = normalize(N * 2.0 - 1.0); - } + //use overlay blending to mix normal maps properly + bvec3 computedN_select = lessThan(N1, vec3(0.5)); + vec3 computedN_multiply = 2.f * N1 * N2; + vec3 computedN_screen = vec3(1.f) - 2.f * (vec3(1.f) - N1) * (vec3(1.f) - N2); + vec3 N = mix(computedN_screen, computedN_multiply, vec3(computedN_select)); + + N = mix(normalize(N * 2.f - 1.f), vec3(0.f,1.f,0.f), vec3(float(N == vec3(0.f,0.f,0.f)))); float lambertTerm = max(dot(N, lightDir), 0.0); // diffuse lighting diff --git a/data/base/shaders/vk/terrain_water_high.frag b/data/base/shaders/vk/terrain_water_high.frag index 0dc63317b9c..d0e02eae159 100644 --- a/data/base/shaders/vk/terrain_water_high.frag +++ b/data/base/shaders/vk/terrain_water_high.frag @@ -46,15 +46,14 @@ vec4 main_bumpMapping() vec3 N1 = texture(tex_nm, vec3(uv2, 0.f), WZ_MIP_LOAD_BIAS).xzy; // y is up in modelSpace vec3 N2 = texture(tex_nm, vec3(uv1, 1.f), WZ_MIP_LOAD_BIAS).xzy; - vec3 N; //use overlay blending to mix normal maps properly - N.x = N1.x < 0.5 ? (2.0 * N1.x * N2.x) : (1.0 - 2.0 * (1.0 - N1.x) * (1.0 - N2.x)); - N.z = N1.z < 0.5 ? (2.0 * N1.z * N2.z) : (1.0 - 2.0 * (1.0 - N1.z) * (1.0 - N2.z)); - N.y = N1.y < 0.5 ? (2.0 * N1.y * N2.y) : (1.0 - 2.0 * (1.0 - N1.y) * (1.0 - N2.y)); - if (N == vec3(0.0,0.0,0.0)) { - N = vec3(0.0,1.0,0.0); - } else { - N = normalize(N * 2.0 - 1.0); - } + //use overlay blending to mix normal maps properly + bvec3 computedN_select = lessThan(N1, vec3(0.5)); + vec3 computedN_multiply = 2.f * N1 * N2; + vec3 computedN_screen = vec3(1.f) - 2.f * (vec3(1.f) - N1) * (vec3(1.f) - N2); + vec3 N = mix(computedN_screen, computedN_multiply, vec3(computedN_select)); + + N = mix(normalize(N * 2.f - 1.f), vec3(0.f,1.f,0.f), vec3(float(N == vec3(0.f,0.f,0.f)))); + float lambertTerm = max(dot(N, lightDir), 0.0); // diffuse lighting // Gaussian specular term computation From 4f98c78c9cf5a7bc6a30430f771af0cd468bba5d Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:56:58 -0400 Subject: [PATCH 4/7] Tweak reloadTerrainTextures logic --- src/terrain.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/terrain.cpp b/src/terrain.cpp index 9e1ba953e41..d0ab0723cb6 100644 --- a/src/terrain.cpp +++ b/src/terrain.cpp @@ -2304,12 +2304,10 @@ bool setTerrainShaderQuality(TerrainShaderQuality newValue, bool force, bool for auto priorNumGroundTypes = getNumGroundTypes(); reloadTileTextures(); mapReloadGroundTypes(); - if (priorValue == TerrainShaderQuality::NORMAL_MAPPING - || terrainShaderQuality == TerrainShaderQuality::NORMAL_MAPPING + if (priorValue != terrainShaderQuality || priorNumGroundTypes != getNumGroundTypes() || forceReloadTextures) { - // when switching to & from the High / Normal-mapping mode, reload base terrain / ground textures reloadTerrainTextures(); } } From 7525e1eab7b41e5644e2c8d26e50758836685f76 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:57:10 -0400 Subject: [PATCH 5/7] Preload classic water texture --- src/terrain.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/terrain.cpp b/src/terrain.cpp index d0ab0723cb6..6e87707c1d4 100644 --- a/src/terrain.cpp +++ b/src/terrain.cpp @@ -936,6 +936,12 @@ void loadWaterTextures(int maxTerrainTextureSize) ASSERT(waterTexturesHigh.tex_sm != nullptr, "Failed to load water specular maps"); } } + else if (terrainShaderQuality == TerrainShaderQuality::CLASSIC) + { + // preload classic water texture + auto pWaterTexClassic = getWaterClassicTexture(); + ASSERT_OR_RETURN(, pWaterTexClassic != nullptr, "Failed to load classic water texture?"); + } else { ASSERT_OR_RETURN(, false, "Unexpected terrainShaderQuality: %u", static_cast(terrainShaderQuality)); From c9f428bd50360ac6b3227930e0ecf5064ab42e71 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Sun, 10 Sep 2023 19:33:34 -0400 Subject: [PATCH 6/7] terrain.cpp: Cache some lightmap-related calculations --- src/terrain.cpp | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/terrain.cpp b/src/terrain.cpp index 6e87707c1d4..85e6ff7e265 100644 --- a/src/terrain.cpp +++ b/src/terrain.cpp @@ -116,6 +116,15 @@ static size_t lightmapWidth; static size_t lightmapHeight; /// Lightmap image static std::unique_ptr lightmapPixmap; +/// Lightmap values +struct LightmapCalculatedValues +{ + glm::vec4 paramsXLight = glm::vec4(); + glm::vec4 paramsYLight = glm::vec4(); + glm::mat4 lightMatrix = glm::mat4(); // shift the lightmap half a tile as lights are supposed to be placed at the center of a tile + glm::mat4 ModelUVLightmap = glm::mat4(); +}; +static LightmapCalculatedValues lightmapValues; /// Ticks per lightmap refresh static const unsigned int LIGHTMAP_REFRESH = 80; @@ -1467,6 +1476,13 @@ bool initTerrain() debug(LOG_TERRAIN, "the size of the map is %ix%i", mapWidth, mapHeight); debug(LOG_TERRAIN, "lightmap texture size is %zu x %zu", lightmapWidth, lightmapHeight); + lightmapValues.paramsXLight = glm::vec4(1.0f / world_coord(mapWidth) *((float)mapWidth / (float)lightmapWidth), 0, 0, 0); + lightmapValues.paramsYLight = glm::vec4(0, 0, -1.0f / world_coord(mapHeight) *((float)mapHeight / (float)lightmapHeight), 0); + + // shift the lightmap half a tile as lights are supposed to be placed at the center of a tile + lightmapValues.lightMatrix = glm::translate(glm::vec3(1.f / (float)lightmapWidth / 2, 1.f / (float)lightmapHeight / 2, 0.f)); + lightmapValues.ModelUVLightmap = lightmapValues.lightMatrix * glm::transpose(glm::mat4(lightmapValues.paramsXLight, lightmapValues.paramsYLight, glm::vec4(0,0,1,0), glm::vec4(0,0,0,1))); + // Prepare the lightmap pixmap and texture lightmapPixmap = std::unique_ptr(new iV_Image()); @@ -1942,9 +1958,7 @@ void perFrameTerrainUpdates() void drawTerrainDepthOnly(const glm::mat4 &mvp) { - const glm::vec4 paramsXLight(1.0f / world_coord(mapWidth) *((float)mapWidth / (float)lightmapWidth), 0, 0, 0); - const glm::vec4 paramsYLight(0, 0, -1.0f / world_coord(mapHeight) *((float)mapHeight / (float)lightmapHeight), 0); - drawDepthOnlyForDepthMap(mvp, paramsXLight, paramsYLight, false); + drawDepthOnlyForDepthMap(mvp, lightmapValues.paramsXLight, lightmapValues.paramsYLight, false); } /** @@ -1954,12 +1968,10 @@ void drawTerrainDepthOnly(const glm::mat4 &mvp) */ void drawTerrain(const glm::mat4 &mvp, const glm::mat4& viewMatrix, const Vector3f &cameraPos, const Vector3f &sunPos, const ShadowCascadesInfo& shadowCascades) { - const glm::vec4 paramsXLight(1.0f / world_coord(mapWidth) *((float)mapWidth / (float)lightmapWidth), 0, 0, 0); - const glm::vec4 paramsYLight(0, 0, -1.0f / world_coord(mapHeight) *((float)mapHeight / (float)lightmapHeight), 0); - - // shift the lightmap half a tile as lights are supposed to be placed at the center of a tile - const glm::mat4 lightMatrix = glm::translate(glm::vec3(1.f / (float)lightmapWidth / 2, 1.f / (float)lightmapHeight / 2, 0.f)); - const auto ModelUVLightmap = lightMatrix * glm::transpose(glm::mat4(paramsXLight, paramsYLight, glm::vec4(0,0,1,0), glm::vec4(0,0,0,1))); + const glm::vec4& paramsXLight = lightmapValues.paramsXLight; + const glm::vec4& paramsYLight = lightmapValues.paramsYLight; + const glm::mat4& lightMatrix = lightmapValues.lightMatrix; + const glm::mat4& ModelUVLightmap = lightmapValues.ModelUVLightmap; if (true) { @@ -2005,12 +2017,6 @@ void drawWaterNormalImpl(const glm::mat4 &ModelViewProjection, const Vector3f &c return; // no water } - const glm::vec4 paramsXLight(1.0f / world_coord(mapWidth) *((float)mapWidth / (float)lightmapWidth), 0, 0, 0); - const glm::vec4 paramsYLight(0, 0, -1.0f / world_coord(mapHeight) *((float)mapHeight / (float)lightmapHeight), 0); - // shift the lightmap half a tile as lights are supposed to be placed at the center of a tile - const glm::mat4 lightMatrix = glm::translate(glm::vec3(1.f / (float)lightmapWidth / 2, 1.f / (float)lightmapHeight / 2, 0.f)); - const auto ModelUVLightmap = lightMatrix * glm::transpose(glm::mat4(paramsXLight, paramsYLight, glm::vec4(0,0,1,0), glm::vec4(0,0,0,1))); - const glm::vec4 paramsX(0, 0, -1.0f / world_coord(4), 0); const glm::vec4 paramsY(1.0f / world_coord(4), 0, 0, 0); const glm::vec4 paramsX2(0, 0, -1.0f / world_coord(5), 0); @@ -2027,7 +2033,7 @@ void drawWaterNormalImpl(const glm::mat4 &ModelViewProjection, const Vector3f &c lightmap_texture); PSO::get().bind_vertex_buffers(waterVBO); PSO::get().bind_constants({ - ModelViewProjection, ModelUVLightmap, ModelUV1, ModelUV2, + ModelViewProjection, lightmapValues.ModelUVLightmap, ModelUV1, ModelUV2, glm::vec4(cameraPos, 0), glm::vec4(glm::normalize(sunPos), 0), pie_GetLighting0(LIGHT_EMISSIVE), pie_GetLighting0(LIGHT_AMBIENT), pie_GetLighting0(LIGHT_DIFFUSE), pie_GetLighting0(LIGHT_SPECULAR), getFogColorVec4(), renderState.fogEnabled, renderState.fogBegin, renderState.fogEnd, @@ -2069,12 +2075,6 @@ void drawWaterHighImpl(const glm::mat4 &ModelViewProjection, const Vector3f &cam return; // no water } - const glm::vec4 paramsXLight(1.0f / world_coord(mapWidth) *((float)mapWidth / (float)lightmapWidth), 0, 0, 0); - const glm::vec4 paramsYLight(0, 0, -1.0f / world_coord(mapHeight) *((float)mapHeight / (float)lightmapHeight), 0); - // shift the lightmap half a tile as lights are supposed to be placed at the center of a tile - const glm::mat4 lightMatrix = glm::translate(glm::vec3(1.f / (float)lightmapWidth / 2, 1.f / (float)lightmapHeight / 2, 0.f)); - const auto ModelUVLightmap = lightMatrix * glm::transpose(glm::mat4(paramsXLight, paramsYLight, glm::vec4(0,0,1,0), glm::vec4(0,0,0,1))); - const glm::vec4 paramsX(0, 0, -1.0f / world_coord(4), 0); const glm::vec4 paramsY(1.0f / world_coord(4), 0, 0, 0); const glm::vec4 paramsX2(0, 0, -1.0f / world_coord(5), 0); @@ -2093,7 +2093,7 @@ void drawWaterHighImpl(const glm::mat4 &ModelViewProjection, const Vector3f &cam lightmap_texture); PSO::get().bind_vertex_buffers(waterVBO); PSO::get().bind_constants({ - ModelViewProjection, ModelUVLightmap, ModelUV1, ModelUV2, + ModelViewProjection, lightmapValues.ModelUVLightmap, ModelUV1, ModelUV2, glm::vec4(cameraPos, 0), glm::vec4(glm::normalize(sunPos), 0), pie_GetLighting0(LIGHT_EMISSIVE), pie_GetLighting0(LIGHT_AMBIENT), pie_GetLighting0(LIGHT_DIFFUSE), pie_GetLighting0(LIGHT_SPECULAR), getFogColorVec4(), renderState.fogEnabled, renderState.fogBegin, renderState.fogEnd, From 428e219486ffe8a3306f6949ebeff2895474d594 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:03:53 -0400 Subject: [PATCH 7/7] Remove some branches in high terrain shader --- data/base/shaders/terrain_combined_high.frag | 14 +++----------- data/base/shaders/vk/terrain_combined_high.frag | 14 +++----------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/data/base/shaders/terrain_combined_high.frag b/data/base/shaders/terrain_combined_high.frag index 3353607bfef..203cd548694 100644 --- a/data/base/shaders/terrain_combined_high.frag +++ b/data/base/shaders/terrain_combined_high.frag @@ -109,11 +109,7 @@ void getGroundBM(int i, inout BumpData res) { float w = fgroundWeights[i]; res.color += texture2DArray(groundTex, uv, WZ_MIP_LOAD_BIAS) * w; vec3 N = texture2DArray(groundNormal, uv, WZ_MIP_LOAD_BIAS).xyz; - if (N == vec3(0.f)) { - N = vec3(0.f,0.f,1.f); - } else { - N = normalize(N * 2.f - 1.f); - } + N = mix(normalize(N * 2.f - 1.f), vec3(0.f,0.f,1.f), vec3(float(N == vec3(0.f,0.f,0.f)))); res.N += N * w; res.gloss += texture2DArray(groundSpecular, uv, WZ_MIP_LOAD_BIAS).r * w; } @@ -166,12 +162,8 @@ vec4 main_bumpMapping() { // blend color, normal and gloss with ground ones based on alpha bump.color = (1.f - a)*bump.color + a*vec4(decalColor.rgb, 1.f); vec3 n = texture2DArray(decalNormal, uv, WZ_MIP_LOAD_BIAS).xyz; - if (n == vec3(0.f)) { - n = vec3(0.f,0.f,1.f); - } else { - n = normalize(n * 2.f - 1.f); - n = vec3(n.xy * decal2groundMat2, n.z); - } + vec3 n_normalized = normalize(n * 2.f - 1.f); + n = mix(vec3(n_normalized.xy * decal2groundMat2, n_normalized.z), vec3(0.f,0.f,1.f), vec3(float(n == vec3(0.f,0.f,0.f)))); bump.N = (1.f - a)*bump.N + a*n; bump.gloss = (1.f - a)*bump.gloss + a*texture2DArray(decalSpecular, uv, WZ_MIP_LOAD_BIAS).r; } diff --git a/data/base/shaders/vk/terrain_combined_high.frag b/data/base/shaders/vk/terrain_combined_high.frag index d701552e4a3..f133b4a197b 100644 --- a/data/base/shaders/vk/terrain_combined_high.frag +++ b/data/base/shaders/vk/terrain_combined_high.frag @@ -51,11 +51,7 @@ void getGroundBM(int i, inout BumpData res) { float w = frag.groundWeights[i]; res.color += texture(groundTex, uv, WZ_MIP_LOAD_BIAS) * w; vec3 N = texture(groundNormal, uv, WZ_MIP_LOAD_BIAS).xyz; - if (N == vec3(0)) { - N = vec3(0,0,1); - } else { - N = normalize(N * 2 - 1); - } + N = mix(normalize(N * 2.f - 1.f), vec3(0.f,0.f,1.f), vec3(float(N == vec3(0.f,0.f,0.f)))); res.N += N * w; res.gloss += texture(groundSpecular, uv, WZ_MIP_LOAD_BIAS).r * w; } @@ -108,12 +104,8 @@ vec4 main_bumpMapping() { // blend color, normal and gloss with ground ones based on alpha bump.color = (1-a)*bump.color + a*vec4(decalColor.rgb, 1); vec3 n = texture(decalNormal, uv, WZ_MIP_LOAD_BIAS).xyz; - if (n == vec3(0)) { - n = vec3(0,0,1); - } else { - n = normalize(n * 2 - 1); - n = vec3(n.xy * frag.decal2groundMat2, n.z); - } + vec3 n_normalized = normalize(n * 2.f - 1.f); + n = mix(vec3(n_normalized.xy * frag.decal2groundMat2, n_normalized.z), vec3(0.f,0.f,1.f), vec3(float(n == vec3(0.f,0.f,0.f)))); bump.N = (1-a)*bump.N + a*n; bump.gloss = (1-a)*bump.gloss + a*texture(decalSpecular, uv, WZ_MIP_LOAD_BIAS).r; }