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; } }