From d45fbbbc465654868df3b5ba237647ef0805cae1 Mon Sep 17 00:00:00 2001 From: BMagnu <6238428+BMagnu@users.noreply.github.com> Date: Wed, 16 Jul 2025 14:28:16 +0200 Subject: [PATCH 01/11] Remove ambient handling from amin / decal pass --- code/def_files/data/effects/decal-f.sdr | 13 ------------- code/def_files/data/effects/main-f.sdr | 19 +++---------------- code/graphics/decal_draw_list.cpp | 11 ----------- code/graphics/util/uniform_structs.h | 5 +---- 4 files changed, 4 insertions(+), 44 deletions(-) diff --git a/code/def_files/data/effects/decal-f.sdr b/code/def_files/data/effects/decal-f.sdr index 9b2e8bbbf18..138caae0ec5 100644 --- a/code/def_files/data/effects/decal-f.sdr +++ b/code/def_files/data/effects/decal-f.sdr @@ -29,9 +29,6 @@ layout (std140) uniform decalGlobalData { mat4 invViewMatrix; mat4 invProjMatrix; - vec3 ambientLight; - float pad0; - vec2 viewportSize; }; @@ -135,16 +132,6 @@ void main() { // Additive blending diffuse_out = vec4(color.rgb * alpha, 1.0); } - - // The main model shader applies ambient lighting by drawing the ambient part of the texture into the emissive - // texture. We do the same here to make sure the decal material is applied correctly - if (glow_blend_mode == 0) { - // Normal alpha blending - emissive_out = vec4(color.rgb * ambientLight, color.a * alpha); - } else { - // Additive blending - emissive_out = vec4(alpha * color.rgb * ambientLight, 1.0); - } } if (glow_index >= 0) { diff --git a/code/def_files/data/effects/main-f.sdr b/code/def_files/data/effects/main-f.sdr index 26a769eab78..e4fbf72282c 100644 --- a/code/def_files/data/effects/main-f.sdr +++ b/code/def_files/data/effects/main-f.sdr @@ -50,6 +50,7 @@ layout (std140) uniform modelData { int n_lights; float defaultGloss; + //EXCLUSIVELY used for non-deferred rendering vec3 ambientFactor; int desaturate; @@ -85,14 +86,12 @@ layout (std140) uniform modelData { float fardist; int sGlowmapIndex; - int sSpecmapIndex; int sNormalmapIndex; int sAmbientmapIndex; - int sMiscmapIndex; + int sMiscmapIndex; float alphaMult; - int flags; }; @@ -342,19 +341,7 @@ void main() #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC // Lights aren't applied when we are rendering to the G-buffers since that gets handled later - #prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED - #prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT - // Ambient lighting still needs to be done since that counts as an "emissive" color - vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior - emissiveColor.rgb += baseColor.rgb * lightAmbient; - #prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT - #prereplace IF_FLAG MODEL_SDR_FLAG_SPEC - baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb; - #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC - // If there is no lighting then we copy the color data so far into the - emissiveColor.rgb += baseColor.rgb; - #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT - #prereplace ELSE_FLAG //MODEL_SDR_FLAG_DEFERRED + #prereplace IF_NOT_FLAG MODEL_SDR_FLAG_DEFERRED #prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT float shadow = 1.0; #prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS diff --git a/code/graphics/decal_draw_list.cpp b/code/graphics/decal_draw_list.cpp index bcb84f70fab..b0f81848da6 100644 --- a/code/graphics/decal_draw_list.cpp +++ b/code/graphics/decal_draw_list.cpp @@ -82,17 +82,6 @@ void decal_draw_list::prepare_global_data() { header->viewportSize.x = (float) gr_screen.max_w; header->viewportSize.y = (float) gr_screen.max_h; - gr_get_ambient_light(&header->ambientLight); - - // Square the ambient part of the light to match the formula used in the main model shader - header->ambientLight.xyz.x *= header->ambientLight.xyz.x; - header->ambientLight.xyz.y *= header->ambientLight.xyz.y; - header->ambientLight.xyz.z *= header->ambientLight.xyz.z; - - header->ambientLight.xyz.x += gr_light_emission[0]; - header->ambientLight.xyz.y += gr_light_emission[1]; - header->ambientLight.xyz.z += gr_light_emission[2]; - for (auto& [batch_info, draw_info] : _draws) { auto info = aligner.addTypedElement(); info->diffuse_index = batch_info.diffuse < 0 ? -1 : bm_get_array_index(batch_info.diffuse); diff --git a/code/graphics/util/uniform_structs.h b/code/graphics/util/uniform_structs.h index 5c3411e03e5..c290fc812d0 100644 --- a/code/graphics/util/uniform_structs.h +++ b/code/graphics/util/uniform_structs.h @@ -139,7 +139,7 @@ struct model_uniform_data { int sMiscmapIndex; float alphaMult; int flags; - int pad[1]; + float pad; }; const size_t model_uniform_data_size = sizeof(model_uniform_data); @@ -181,9 +181,6 @@ struct decal_globals { matrix4 invViewMatrix; matrix4 invProjMatrix; - vec3d ambientLight; - float pad0; - vec2d viewportSize; float pad1[2]; }; From 8f16dc2326b8f64d97e7de074902e5ccb13cab32 Mon Sep 17 00:00:00 2001 From: BMagnu <6238428+BMagnu@users.noreply.github.com> Date: Wed, 16 Jul 2025 15:06:19 +0200 Subject: [PATCH 02/11] Add ambient light to deferred pass --- code/def_files/data/effects/deferred-f.sdr | 69 ++++++++++++---------- code/def_files/data/effects/lighting.sdr | 1 + code/def_files/data/effects/main-f.sdr | 4 +- code/graphics/light.cpp | 10 ++++ code/graphics/opengl/gropengldeferred.cpp | 17 ++++++ code/lighting/lighting.h | 3 +- 6 files changed, 71 insertions(+), 33 deletions(-) diff --git a/code/def_files/data/effects/deferred-f.sdr b/code/def_files/data/effects/deferred-f.sdr index 3953b00440d..78f34408f29 100644 --- a/code/def_files/data/effects/deferred-f.sdr +++ b/code/def_files/data/effects/deferred-f.sdr @@ -168,43 +168,52 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li void main() { vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight); - vec3 position = texture(PositionBuffer, screenPos).xyz; + vec4 position_buffer = texture(PositionBuffer, screenPos); + vec3 position = position_buffer.xyz; if(abs(dot(position, position)) < nearPlane * nearPlane) discard; vec3 diffColor = texture(ColorBuffer, screenPos).rgb; - vec4 normalData = texture(NormalBuffer, screenPos); - vec4 specColor = texture(SpecBuffer, screenPos); - // The vector in the normal buffer could be longer than the unit vector since decal rendering only adds to the normal buffer - vec3 normal = normalize(normalData.xyz); - float gloss = normalData.a; - float roughness = clamp(1.0f - gloss, 0.0f, 1.0f); - float alpha = roughness * roughness; - float fresnel = specColor.a; - vec3 eyeDir = normalize(-position); + vec4 fragmentColor = vec4(1.0); - vec3 lightDir; - float attenuation; - float area_normalisation; - vec3 reflectDir = reflect(-eyeDir, normal); - GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation); - - if (enable_shadows) { - vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0); - vec4 fragShadowUV[4]; - fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos); - fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos); - fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos); - fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos); - - attenuation *= getShadowValue(shadow_map, -position.z, fragShadowPos.z, fragShadowUV, fardist, middist, - neardist, veryneardist); + if (lightType == LT_AMBIENT) { + float ao = position_buffer.w; + fragmentColor.rgb = diffuseLightColor * ao; + } + else { + vec4 normalData = texture(NormalBuffer, screenPos); + vec4 specColor = texture(SpecBuffer, screenPos); + // The vector in the normal buffer could be longer than the unit vector since decal rendering only adds to the normal buffer + vec3 normal = normalize(normalData.xyz); + float gloss = normalData.a; + float roughness = clamp(1.0f - gloss, 0.0f, 1.0f); + float alpha = roughness * roughness; + float fresnel = specColor.a; + vec3 eyeDir = normalize(-position); + + vec3 lightDir; + float attenuation; + float area_normalisation; + vec3 reflectDir = reflect(-eyeDir, normal); + GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation); + + if (enable_shadows) { + vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0); + vec4 fragShadowUV[4]; + fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos); + fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos); + fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos); + fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos); + + attenuation *= getShadowValue(shadow_map, -position.z, fragShadowPos.z, fragShadowUV, fardist, middist, + neardist, veryneardist); + } + + vec3 halfVec = normalize(lightDir + eyeDir); + float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0); + fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL).rgb * diffuseLightColor * attenuation * area_normalisation; } - vec3 halfVec = normalize(lightDir + eyeDir); - float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0); - vec4 fragmentColor = vec4(1.0); - fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL).rgb * diffuseLightColor * attenuation * area_normalisation; fragOut0 = max(fragmentColor, vec4(0.0)); } diff --git a/code/def_files/data/effects/lighting.sdr b/code/def_files/data/effects/lighting.sdr index 969ff908422..799617b52eb 100644 --- a/code/def_files/data/effects/lighting.sdr +++ b/code/def_files/data/effects/lighting.sdr @@ -3,6 +3,7 @@ const int LT_DIRECTIONAL = 0; // A light like a sun const int LT_POINT = 1; // A point light, like an explosion const int LT_TUBE = 2; // A tube light, like a fluorescent light const int LT_CONE = 3; // A cone light, like a flood light +const int LT_AMBIENT = 4; // Directionless ambient light const float SPEC_FACTOR_NO_SPEC_MAP = 0.1; const float GLOW_MAP_INTENSITY = 1.5; diff --git a/code/def_files/data/effects/main-f.sdr b/code/def_files/data/effects/main-f.sdr index e4fbf72282c..4debb197ec5 100644 --- a/code/def_files/data/effects/main-f.sdr +++ b/code/def_files/data/effects/main-f.sdr @@ -186,7 +186,7 @@ void GetLightInfo(int i, out vec3 lightDir, out float attenuation) vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial, float gloss, float fresnel, float shadow, float aoFactor) { vec3 eyeDir = vec3(normalize(-vertIn.position).xyz); - vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactor; // ambientFactor^2 due to legacy OpenGL compatibility behavior + vec3 lightAmbient = ambientFactor * aoFactor; vec3 lightDiffuse = vec3(0.0, 0.0, 0.0); vec3 lightSpecular = vec3(0.0, 0.0, 0.0); #pragma optionNV unroll all @@ -473,7 +473,7 @@ void main() fragOut0 = baseColor; #prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED - fragOut1 = vec4(vertIn.position.xyz, 1.0); + fragOut1 = vec4(vertIn.position.xyz, aoFactors.x); fragOut2 = vec4(normal, glossData); fragOut3 = vec4(specColor.rgb, fresnelFactor); fragOut4 = emissiveColor; diff --git a/code/graphics/light.cpp b/code/graphics/light.cpp index 77acf272b39..c499fa24f2a 100644 --- a/code/graphics/light.cpp +++ b/code/graphics/light.cpp @@ -344,6 +344,16 @@ void gr_get_ambient_light(vec3d* light_vector) { light_vector->xyz.x = over.handle(abv.handle(gr_light_ambient[0])); light_vector->xyz.y = over.handle(abv.handle(gr_light_ambient[1])); light_vector->xyz.z = over.handle(abv.handle(gr_light_ambient[2])); + + //AmbientFactor^2 due to legacy OpenGL behaviour + *light_vector *= *light_vector; + + //For some reason, emissive is in here as well... + if (Cmdline_emissive) { + light_vector->xyz.x += gr_light_emission[0]; + light_vector->xyz.y += gr_light_emission[1]; + light_vector->xyz.z += gr_light_emission[2]; + } } void gr_lighting_fill_uniforms(void* data_out, size_t buffer_size) { diff --git a/code/graphics/opengl/gropengldeferred.cpp b/code/graphics/opengl/gropengldeferred.cpp index cce19f69bfe..ab25eff0ce4 100644 --- a/code/graphics/opengl/gropengldeferred.cpp +++ b/code/graphics/opengl/gropengldeferred.cpp @@ -9,6 +9,7 @@ #include "gropengltnl.h" #include "graphics/2d.h" +#include "graphics/light.h" #include "graphics/matrix.h" #include "graphics/util/UniformAligner.h" #include "graphics/util/UniformBuffer.h" @@ -286,6 +287,8 @@ void gr_opengl_deferred_lighting_finish() case Light_Type::Tube: cylinder_lights.push_back(l); break; + case Light_Type::Ambient: + UNREACHABLE("Multiple ambient lights are not supported!"); } } { @@ -312,6 +315,20 @@ void gr_opengl_deferred_lighting_finish() header->invScreenHeight = 1.0f / gr_screen.max_h; header->nearPlane = gr_near_plane; + { + //Prepare ambient light + light l; + vec3d ambient; + gr_get_ambient_light(&ambient); + l.r = ambient.xyz.x; + l.g = ambient.xyz.y; + l.b = ambient.xyz.z; + l.type = Light_Type::Ambient; + l.intensity = 1.f; + l.source_radius = 0.f; + prepare_light_uniforms(l, light_uniform_aligner); + } + // Only the first directional light uses shaders so we need to know when we already saw that light bool first_directional = true; diff --git a/code/lighting/lighting.h b/code/lighting/lighting.h index 56e7e4ce714..0fcbc673213 100644 --- a/code/lighting/lighting.h +++ b/code/lighting/lighting.h @@ -32,7 +32,8 @@ enum class Light_Type : int { Directional = 0,// A light like a sun Point = 1, // A point light, like an explosion Tube = 2, // A tube light, like a fluorescent light - Cone = 3 // A cone light, like a flood light + Cone = 3, // A cone light, like a flood light + Ambient = 4 // A directionless and positionless ambient light }; typedef struct light { From 7248caac4e42120e3eb086332fd7040692578b5c Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Wed, 16 Jul 2025 19:29:16 +0200 Subject: [PATCH 03/11] Make decals work and fix double insignia rendering --- code/def_files/data/effects/decal-v.sdr | 3 -- .../data/effects/deferred-clear-f.sdr | 2 +- code/def_files/data/effects/deferred-f.sdr | 2 +- code/def_files/data/effects/deferred-v.sdr | 2 +- code/graphics/opengl/gropengldeferred.cpp | 46 ++++++++++--------- code/model/modelrender.cpp | 4 ++ code/ship/ship.cpp | 4 +- 7 files changed, 33 insertions(+), 30 deletions(-) diff --git a/code/def_files/data/effects/decal-v.sdr b/code/def_files/data/effects/decal-v.sdr index 6a62549bd62..594692c5ec1 100644 --- a/code/def_files/data/effects/decal-v.sdr +++ b/code/def_files/data/effects/decal-v.sdr @@ -14,9 +14,6 @@ layout (std140) uniform decalGlobalData { mat4 invViewMatrix; mat4 invProjMatrix; - vec3 ambientLight; - float pad0; - vec2 viewportSize; }; diff --git a/code/def_files/data/effects/deferred-clear-f.sdr b/code/def_files/data/effects/deferred-clear-f.sdr index ed15e5516b0..4d49695ef90 100644 --- a/code/def_files/data/effects/deferred-clear-f.sdr +++ b/code/def_files/data/effects/deferred-clear-f.sdr @@ -7,7 +7,7 @@ out vec4 fragOut5; void main() { fragOut0 = vec4(0.0, 0.0, 0.0, 1.0); // color - fragOut1 = vec4(0.0, 0.0, -1000000.0, 1.0); // position + fragOut1 = vec4(0.0, 0.0, -1000000.0, 0.0); // position fragOut2 = vec4(0.0, 0.0, 0.0, 1.0); // normal fragOut3 = vec4(0.0, 0.0, 0.0, 0.0); // specular fragOut4 = vec4(0.0, 0.0, 0.0, 1.0); // emissive diff --git a/code/def_files/data/effects/deferred-f.sdr b/code/def_files/data/effects/deferred-f.sdr index 78f34408f29..5289393d6f4 100644 --- a/code/def_files/data/effects/deferred-f.sdr +++ b/code/def_files/data/effects/deferred-f.sdr @@ -179,7 +179,7 @@ void main() if (lightType == LT_AMBIENT) { float ao = position_buffer.w; - fragmentColor.rgb = diffuseLightColor * ao; + fragmentColor.rgb = diffuseLightColor * diffColor * ao; } else { vec4 normalData = texture(NormalBuffer, screenPos); diff --git a/code/def_files/data/effects/deferred-v.sdr b/code/def_files/data/effects/deferred-v.sdr index b454a42a02e..f1633569875 100644 --- a/code/def_files/data/effects/deferred-v.sdr +++ b/code/def_files/data/effects/deferred-v.sdr @@ -29,7 +29,7 @@ layout (std140) uniform lightData { void main() { - if (lightType == LT_DIRECTIONAL) { + if (lightType == LT_DIRECTIONAL || lightType == LT_AMBIENT) { gl_Position = vec4(vertPosition.xyz, 1.0); } else { gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0); diff --git a/code/graphics/opengl/gropengldeferred.cpp b/code/graphics/opengl/gropengldeferred.cpp index ab25eff0ce4..332aeb6ef91 100644 --- a/code/graphics/opengl/gropengldeferred.cpp +++ b/code/graphics/opengl/gropengldeferred.cpp @@ -255,7 +255,7 @@ void gr_opengl_deferred_lighting_finish() using namespace graphics; // We need to precompute how many elements we are going to need - size_t num_data_elements = Lights.size(); + size_t num_data_elements = Lights.size() + 1; // Get a uniform buffer for our data auto light_buffer = gr_get_uniform_buffer(uniform_block_type::Lights, num_data_elements); @@ -317,7 +317,7 @@ void gr_opengl_deferred_lighting_finish() { //Prepare ambient light - light l; + light& l = full_frame_lights.emplace_back(); vec3d ambient; gr_get_ambient_light(&ambient); l.r = ambient.xyz.x; @@ -326,7 +326,6 @@ void gr_opengl_deferred_lighting_finish() l.type = Light_Type::Ambient; l.intensity = 1.f; l.source_radius = 0.f; - prepare_light_uniforms(l, light_uniform_aligner); } // Only the first directional light uses shaders so we need to know when we already saw that light @@ -334,30 +333,33 @@ void gr_opengl_deferred_lighting_finish() for (auto& l : full_frame_lights) { auto light_data = prepare_light_uniforms(l, light_uniform_aligner); - if (Shadow_quality != ShadowQuality::Disabled) { - light_data->enable_shadows = first_directional ? 1 : 0; - } - // Global light direction should match shadow light direction - if (first_directional) { - global_light = &l; - global_light_diffuse = light_data->diffuseLightColor; - } + if (l.type == Light_Type::Directional ) { + if (Shadow_quality != ShadowQuality::Disabled) { + light_data->enable_shadows = first_directional ? 1 : 0; + } - vec4 light_dir; - light_dir.xyzw.x = -l.vec.xyz.x; - light_dir.xyzw.y = -l.vec.xyz.y; - light_dir.xyzw.z = -l.vec.xyz.z; - light_dir.xyzw.w = 0.0f; - vec4 view_dir; + // Global light direction should match shadow light direction + if (first_directional) { + global_light = &l; + global_light_diffuse = light_data->diffuseLightColor; - vm_vec_transform(&view_dir, &light_dir, &gr_view_matrix); + first_directional = false; + } + + vec4 light_dir; + light_dir.xyzw.x = -l.vec.xyz.x; + light_dir.xyzw.y = -l.vec.xyz.y; + light_dir.xyzw.z = -l.vec.xyz.z; + light_dir.xyzw.w = 0.0f; + vec4 view_dir; - light_data->lightDir.xyz.x = view_dir.xyzw.x; - light_data->lightDir.xyz.y = view_dir.xyzw.y; - light_data->lightDir.xyz.z = view_dir.xyzw.z; + vm_vec_transform(&view_dir, &light_dir, &gr_view_matrix); - first_directional = false; + light_data->lightDir.xyz.x = view_dir.xyzw.x; + light_data->lightDir.xyz.y = view_dir.xyzw.y; + light_data->lightDir.xyz.z = view_dir.xyzw.z; + } } for (auto& l : sphere_lights) { auto light_data = prepare_light_uniforms(l, light_uniform_aligner); diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index f72cb518e66..8873dc49df4 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -2971,6 +2971,10 @@ void model_render_queue(const model_render_params* interp, model_draw_list* scen // MARKED! if ( !( model_flags & MR_NO_TEXTURING ) && !( model_flags & MR_NO_INSIGNIA) ) { + decals::creation_info decal { + + }; + decals::addDecal() scene->add_insignia(interp, pm, detail_level, interp->get_insignia_bitmap()); } diff --git a/code/ship/ship.cpp b/code/ship/ship.cpp index 238626cbba2..f7892e7beca 100644 --- a/code/ship/ship.cpp +++ b/code/ship/ship.cpp @@ -8185,8 +8185,7 @@ void ship_render_player_ship(object* objp, const vec3d* cam_offset, const matrix const bool renderShipModel = ( sip->flags[Ship::Info_Flags::Show_ship_model]) && (!Show_ship_only_if_cockpits_enabled || Cockpit_active) - && (!Viewer_mode || (Viewer_mode & VM_PADLOCK_ANY) || (Viewer_mode & VM_OTHER_SHIP) || (Viewer_mode & VM_TRACK) - || !(Viewer_mode & VM_EXTERNAL)); + && (!Viewer_mode || (Viewer_mode & VM_PADLOCK_ANY) || (Viewer_mode & VM_OTHER_SHIP) || (Viewer_mode & VM_TRACK)); Cockpit_active = renderCockpitModel; //Nothing to do @@ -8320,6 +8319,7 @@ void ship_render_player_ship(object* objp, const vec3d* cam_offset, const matrix uint64_t render_flags = MR_NORMAL; render_flags |= MR_NO_FOGGING; + render_flags |= MR_NO_INSIGNIA; if (shipp->flags[Ship::Ship_Flags::Glowmaps_disabled]) { render_flags |= MR_NO_GLOWMAPS; From 7833dfdc66ade78b1ef4c9ba50a5aa87112e9000 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Fri, 18 Jul 2025 21:07:30 +0200 Subject: [PATCH 04/11] Fix decal vertex shader --- code/def_files/data/effects/decal-v.sdr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/def_files/data/effects/decal-v.sdr b/code/def_files/data/effects/decal-v.sdr index 594692c5ec1..d90bddb7aa3 100644 --- a/code/def_files/data/effects/decal-v.sdr +++ b/code/def_files/data/effects/decal-v.sdr @@ -37,6 +37,6 @@ void main() { modelMatrix[2][3] = 0.0; invModelMatrix = inverse(modelMatrix); - decalDirection = mat3(viewMatrix) * vec3(modelMatrix[0][2], modelMatrix[1][2], modelMatrix[2][2]); + decalDirection = mat3(viewMatrix) * vec3(modelMatrix[2][0], modelMatrix[2][1], modelMatrix[2][2]); gl_Position = projMatrix * viewMatrix * modelMatrix * vertPosition; } From 24cdeb3c954f100dc8ef42b0361a44281dcbf75e Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Fri, 18 Jul 2025 14:20:39 +0200 Subject: [PATCH 05/11] render insignias as decals --- code/decals/decals.cpp | 177 +++++++++++++++++++------------------ code/decals/decals.h | 21 +++++ code/math/vecmat.cpp | 13 +++ code/math/vecmat.h | 4 + code/model/modelrender.cpp | 62 +++++++++++-- 5 files changed, 186 insertions(+), 91 deletions(-) diff --git a/code/decals/decals.cpp b/code/decals/decals.cpp index 20d5a5c2da1..424c3807932 100644 --- a/code/decals/decals.cpp +++ b/code/decals/decals.cpp @@ -181,66 +181,52 @@ void parse_decals_table(const char* filename) { } } -struct Decal { - int definition_handle = -1; - object_h object; - int orig_obj_type = OBJ_NONE; - int submodel = -1; - - float creation_time = -1.0f; //!< The mission time at which this decal was created - float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires - - vec3d position = vmd_zero_vector; - vec3d scale; - matrix orientation = vmd_identity_matrix; +Decal::Decal() { + vm_vec_make(&scale, 1.f, 1.f, 1.f); +} - Decal() { - vm_vec_make(&scale, 1.f, 1.f, 1.f); +bool Decal::isValid() const { + if (!object.isValid()) { + return false; + } + if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) { + return false; } - bool isValid() const { - if (!object.isValid()) { - return false; - } - if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) { - return false; - } + if (orig_obj_type != object.objp()->type) { + mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n", + object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type])); + return false; + } - if (orig_obj_type != object.objp()->type) { - mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n", - object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type])); + if (lifetime > 0.0f) { + if (f2fl(Missiontime) >= creation_time + lifetime) { + // Decal has expired return false; } + } - if (lifetime > 0.0f) { - if (f2fl(Missiontime) >= creation_time + lifetime) { - // Decal has expired - return false; - } - } - - auto objp = object.objp(); - if (objp->type == OBJ_SHIP) { - auto shipp = &Ships[objp->instance]; - auto model_instance = model_get_instance(shipp->model_instance_num); + auto objp = object.objp(); + if (objp->type == OBJ_SHIP) { + auto shipp = &Ships[objp->instance]; + auto model_instance = model_get_instance(shipp->model_instance_num); - Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models, - "Invalid submodel number detected!"); - auto smi = &model_instance->submodel[submodel]; + Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models, + "Invalid submodel number detected!"); + auto smi = &model_instance->submodel[submodel]; - if (smi->blown_off) { - return false; - } - } else { - Assertion(false, "Only ships are currently supported for decals!"); + if (smi->blown_off) { return false; } - - return true; + } else { + Assertion(false, "Only ships are currently supported for decals!"); + return false; } -}; -SCP_vector active_decals; + return true; +} + +SCP_vector active_decals, active_single_frame_decals; bool required_string_if_new(const char* token, bool new_entry) { if (!new_entry) { @@ -374,7 +360,7 @@ void initializeMission() { const float DECAL_ANGLE_CUTOFF = fl_radians(45.f); const float DECAL_ANGLE_FADE_START = fl_radians(30.f); -static matrix4 getDecalTransform(Decal& decal, float alpha) { +static matrix4 getDecalTransform(const Decal& decal, float alpha) { Assertion(decal.object.objp()->type == OBJ_SHIP, "Only ships are currently supported for decals!"); auto objp = decal.object.objp(); @@ -418,6 +404,51 @@ static matrix4 getDecalTransform(Decal& decal, float alpha) { return mat4; } +inline static void renderDecal(graphics::decal_draw_list& draw_list, const Decal& decal) { + auto mission_time = f2fl(Missiontime); + + int diffuse_bm = -1; + int glow_bm = -1; + int normal_bm = -1; + + auto decal_time = mission_time - decal.creation_time; + auto progress = decal_time / decal.lifetime; + + float alpha = 1.0f; + if (progress > 0.8) { + // Fade the decal out for the last 20% of its lifetime + alpha = 1.0f - smoothstep(0.8f, 1.0f, progress); + } + + if (std::holds_alternative(decal.definition_handle)) { + int definition_handle = std::get(decal.definition_handle); + Assertion(definition_handle >= 0 && definition_handle < (int) DecalDefinitions.size(), + "Invalid decal handle detected!"); + auto &decalDef = DecalDefinitions[definition_handle]; + + if (decalDef.getDiffuseBitmap() >= 0) { + diffuse_bm = decalDef.getDiffuseBitmap() + + + bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping()); + } + + if (decalDef.getGlowBitmap() >= 0) { + glow_bm = decalDef.getGlowBitmap() + + bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping()); + } + + if (decalDef.getNormalBitmap() >= 0) { + normal_bm = decalDef.getNormalBitmap() + + bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping()); + } + } + else { + std::tie(diffuse_bm, glow_bm, normal_bm) = std::get>(decal.definition_handle); + } + + draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal, alpha)); +} + void renderAll() { if (!Decal_system_active || !Decal_option_active || !gr_is_capable(gr_capability::CAPABILITY_INSTANCED_RENDERING)) { return; @@ -442,51 +473,21 @@ void renderAll() { ++iter; } - if (active_decals.empty()) { + if (active_decals.empty() && active_single_frame_decals.empty()) { return; } - auto mission_time = f2fl(Missiontime); - - graphics::decal_draw_list draw_list; - for (auto& decal : active_decals) { - - Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int)DecalDefinitions.size(), - "Invalid decal handle detected!"); - auto& decalDef = DecalDefinitions[decal.definition_handle]; - int diffuse_bm = -1; - int glow_bm = -1; - int normal_bm = -1; - auto decal_time = mission_time - decal.creation_time; - auto progress = decal_time / decal.lifetime; - - float alpha = 1.0f; - if (progress > 0.8) { - // Fade the decal out for the last 20% of its lifetime - alpha = 1.0f - smoothstep(0.8f, 1.0f, progress); - } - - if (decalDef.getDiffuseBitmap() >= 0) { - diffuse_bm = decalDef.getDiffuseBitmap() - + bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping()); - } - - if (decalDef.getGlowBitmap() >= 0) { - glow_bm = decalDef.getGlowBitmap() - + bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping()); - } - - if (decalDef.getNormalBitmap() >= 0) { - normal_bm = decalDef.getNormalBitmap() - + bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping()); - } - - draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal, alpha)); - } + graphics::decal_draw_list draw_list; + for (auto& decal : active_decals) + renderDecal(draw_list, decal); + for (auto& decal : active_single_frame_decals) + renderDecal(draw_list, decal); draw_list.render(); + + active_single_frame_decals.clear(); } void addDecal(creation_info& info, const object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) { @@ -531,4 +532,8 @@ void addDecal(creation_info& info, const object* host, int submodel, const vec3d active_decals.push_back(newDecal); } +void addSingleFrameDecal(Decal&& info) { + active_single_frame_decals.push_back(info); +} + } diff --git a/code/decals/decals.h b/code/decals/decals.h index a205b67c255..338a4fa14e4 100644 --- a/code/decals/decals.h +++ b/code/decals/decals.h @@ -50,6 +50,25 @@ class DecalDefinition { bool isNormalLooping() const; }; +struct Decal { + //DecalDefinition idx vs immediate diffuse/glow/normal + std::variant> definition_handle = -1; + object_h object; + int orig_obj_type = OBJ_NONE; + int submodel = -1; + + float creation_time = -1.0f; //!< The mission time at which this decal was created + float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires + + vec3d position = vmd_zero_vector; + vec3d scale; + matrix orientation = vmd_identity_matrix; + + Decal(); + + bool isValid() const; +}; + extern SCP_vector DecalDefinitions; extern bool Decal_system_active; extern bool Decal_option_active; @@ -139,4 +158,6 @@ void addDecal(creation_info& info, const vec3d& local_pos, const matrix& local_orient); +void addSingleFrameDecal(Decal&& info); + } diff --git a/code/math/vecmat.cpp b/code/math/vecmat.cpp index 526baf08693..46261d851bc 100644 --- a/code/math/vecmat.cpp +++ b/code/math/vecmat.cpp @@ -276,6 +276,19 @@ vec3d *vm_vec_avg_n(vec3d *dest, int n, const vec3d src[]) return dest; } +//Calculates the componentwise minimum of the two vectors +void vm_vec_min(vec3d* dest, const vec3d* src0, const vec3d* src1) { + dest->xyz.x = std::min(src0->xyz.x, src1->xyz.x); + dest->xyz.y = std::min(src0->xyz.y, src1->xyz.y); + dest->xyz.z = std::min(src0->xyz.z, src1->xyz.z); +} + +//Calculates the componentwise maximum of the two vectors +void vm_vec_max(vec3d* dest, const vec3d* src0, const vec3d* src1) { + dest->xyz.x = std::max(src0->xyz.x, src1->xyz.x); + dest->xyz.y = std::max(src0->xyz.y, src1->xyz.y); + dest->xyz.z = std::max(src0->xyz.z, src1->xyz.z); +} //averages two vectors. returns ptr to dest //dest can equal either source diff --git a/code/math/vecmat.h b/code/math/vecmat.h index 2a6c9cffe34..a0a7f619a6e 100755 --- a/code/math/vecmat.h +++ b/code/math/vecmat.h @@ -145,7 +145,11 @@ void vm_vec_sub2(vec3d *dest, const vec3d *src); //averages n vectors vec3d *vm_vec_avg_n(vec3d *dest, int n, const vec3d src[]); +//Calculates the componentwise minimum of the two vectors +void vm_vec_min(vec3d* dest, const vec3d* src0, const vec3d* src1); +//Calculates the componentwise maximum of the two vectors +void vm_vec_max(vec3d* dest, const vec3d* src0, const vec3d* src1); //averages two vectors. returns ptr to dest //dest can equal either source vec3d *vm_vec_avg(vec3d *dest, const vec3d *src0, const vec3d *src1); diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index 8873dc49df4..3e8bfb4264e 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -2970,12 +2970,64 @@ void model_render_queue(const model_render_params* interp, model_draw_list* scen } // MARKED! - if ( !( model_flags & MR_NO_TEXTURING ) && !( model_flags & MR_NO_INSIGNIA) ) { - decals::creation_info decal { + if ( !( model_flags & MR_NO_TEXTURING ) && !( model_flags & MR_NO_INSIGNIA) && objnum >= 0 ) { + int bitmap_num = interp->get_insignia_bitmap(); + if ( (pm->num_ins > 0) && (bitmap_num >= 0) ) { - }; - decals::addDecal() - scene->add_insignia(interp, pm, detail_level, interp->get_insignia_bitmap()); + for (int idx=0; idxnum_ins; idx++) { + // skip insignias not on our detail level + if (pm->ins[idx].detail_level != detail_level) { + continue; + } + + vec3d min {{{FLT_MAX, FLT_MAX, FLT_MAX}}}; + vec3d max {{{-FLT_MAX, -FLT_MAX, -FLT_MAX}}}; + vec3d avg_total = ZERO_VECTOR; + vec3d avg_normal = ZERO_VECTOR; + for(int s_idx=0; s_idxins[idx].num_faces; s_idx++) { + // get vertex indices + int i1 = pm->ins[idx].faces[s_idx][0]; + int i2 = pm->ins[idx].faces[s_idx][1]; + int i3 = pm->ins[idx].faces[s_idx][2]; + + const vec3d& v1 = pm->ins[idx].vecs[i1]; + const vec3d& v2 = pm->ins[idx].vecs[i2]; + const vec3d& v3 = pm->ins[idx].vecs[i3]; + + vm_vec_min(&min, &min, &v1); + vm_vec_min(&min, &min, &v2); + vm_vec_min(&min, &min, &v3); + vm_vec_max(&max, &max, &v1); + vm_vec_max(&max, &max, &v2); + vm_vec_max(&max, &max, &v3); + + // transform vecs and setup vertices + vec3d avg = (v1 + v2 + v3) * (1.0f / 3.0f); + avg_total += avg; + + const vec3d& u = v2 - v1; + const vec3d& v = v3 - v1; + avg_normal.xyz.x += u.xyz.y * v.xyz.z - u.xyz.z * v.xyz.y; + avg_normal.xyz.y += u.xyz.z * v.xyz.x - u.xyz.x * v.xyz.z; + avg_normal.xyz.z += u.xyz.x * v.xyz.y - u.xyz.y * v.xyz.x; + } + avg_total /= pm->ins[idx].num_faces; + vec3d bb = max - min; + float diameter = std::max({bb.xyz.x, bb.xyz.y, bb.xyz.z}); + + decals::Decal decal; + decal.object = &Objects[objnum]; + decal.position = avg_total + pm->ins[idx].offset; + decal.submodel = -1; + decal.scale = vec3d{{{diameter, diameter, diameter}}}; + decal.orig_obj_type = OBJ_SHIP; + decal.creation_time = f2fl(Missiontime); + decal.lifetime = 1.0f; + vm_vector_2_matrix(&decal.orientation, &avg_normal, &vmd_z_vector); + decal.definition_handle = std::make_tuple(bitmap_num, -1, -1); + decals::addSingleFrameDecal(std::move(decal)); + } + } } if ( (model_flags & MR_AUTOCENTER) && (set_autocen) ) { From fdf98a1f3a39d772756cc4c13638e69e694a04fd Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Fri, 18 Jul 2025 21:47:29 +0200 Subject: [PATCH 06/11] Cleanup of old insignia stuff --- code/def_files/data/effects/decal-v.sdr | 2 +- code/model/modelrender.cpp | 114 ------------------------ code/model/modelrender.h | 5 -- code/object/objectsort.cpp | 1 - 4 files changed, 1 insertion(+), 121 deletions(-) diff --git a/code/def_files/data/effects/decal-v.sdr b/code/def_files/data/effects/decal-v.sdr index d90bddb7aa3..bd3511e0c7e 100644 --- a/code/def_files/data/effects/decal-v.sdr +++ b/code/def_files/data/effects/decal-v.sdr @@ -37,6 +37,6 @@ void main() { modelMatrix[2][3] = 0.0; invModelMatrix = inverse(modelMatrix); - decalDirection = mat3(viewMatrix) * vec3(modelMatrix[2][0], modelMatrix[2][1], modelMatrix[2][2]); + decalDirection = mat3(viewMatrix) * modelMatrix[2].xyz; gl_Position = projMatrix * viewMatrix * modelMatrix * vertPosition; } diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index 3e8bfb4264e..b8f4a138fc4 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -639,51 +639,6 @@ void model_draw_list::render_arcs() gr_zbuffer_set(mode); } -void model_draw_list::add_insignia(const model_render_params *params, const polymodel *pm, int detail_level, int bitmap_num) -{ - insignia_draw_data new_insignia; - - new_insignia.transform = Transformations.get_transform(); - new_insignia.pm = pm; - new_insignia.detail_level = detail_level; - new_insignia.bitmap_num = bitmap_num; - - new_insignia.clip = params->is_clip_plane_set(); - new_insignia.clip_normal = params->get_clip_plane_normal(); - new_insignia.clip_position = params->get_clip_plane_pos(); - - Insignias.push_back(new_insignia); -} - -void model_draw_list::render_insignia(const insignia_draw_data &insignia_info) -{ - if ( insignia_info.clip ) { - vec3d tmp; - vec3d pos; - - vm_matrix4_get_offset(&pos, &insignia_info.transform); - vm_vec_sub(&tmp, &pos, &insignia_info.clip_position); - vm_vec_normalize(&tmp); - - if ( vm_vec_dot(&tmp, &insignia_info.clip_normal) < 0.0f) { - return; - } - } - - g3_start_instance_matrix(&insignia_info.transform); - - model_render_insignias(&insignia_info); - - g3_done_instance(true); -} - -void model_draw_list::render_insignias() -{ - for ( size_t i = 0; i < Insignias.size(); ++i ) { - render_insignia(Insignias[i]); - } -} - void model_draw_list::add_outline(const vertex* vert_array, int n_verts, const color *clr) { outline_draw draw_info; @@ -2425,74 +2380,6 @@ void model_queue_render_thrusters(const model_render_params *interp, const polym } } -void model_render_insignias(const insignia_draw_data *insignia_data) -{ - auto pm = insignia_data->pm; - int detail_level = insignia_data->detail_level; - int bitmap_num = insignia_data->bitmap_num; - - // if the model has no insignias, or we don't have a texture, then bail - if ( (pm->num_ins <= 0) || (bitmap_num < 0) ) - return; - - int idx, s_idx; - vertex vecs[3]; - vec3d t1, t2, t3; - int i1, i2, i3; - - material insignia_material; - insignia_material.set_depth_bias(1); - - // set the proper texture - material_set_unlit(&insignia_material, bitmap_num, 0.65f, true, true); - - if ( insignia_data->clip ) { - insignia_material.set_clip_plane(insignia_data->clip_normal, insignia_data->clip_position); - } - - // otherwise render them - for(idx=0; idxnum_ins; idx++){ - // skip insignias not on our detail level - if(pm->ins[idx].detail_level != detail_level){ - continue; - } - - for(s_idx=0; s_idxins[idx].num_faces; s_idx++){ - // get vertex indices - i1 = pm->ins[idx].faces[s_idx][0]; - i2 = pm->ins[idx].faces[s_idx][1]; - i3 = pm->ins[idx].faces[s_idx][2]; - - // transform vecs and setup vertices - vm_vec_add(&t1, &pm->ins[idx].vecs[i1], &pm->ins[idx].offset); - vm_vec_add(&t2, &pm->ins[idx].vecs[i2], &pm->ins[idx].offset); - vm_vec_add(&t3, &pm->ins[idx].vecs[i3], &pm->ins[idx].offset); - - g3_transfer_vertex(&vecs[0], &t1); - g3_transfer_vertex(&vecs[1], &t2); - g3_transfer_vertex(&vecs[2], &t3); - - // setup texture coords - vecs[0].texture_position.u = pm->ins[idx].u[s_idx][0]; - vecs[0].texture_position.v = pm->ins[idx].v[s_idx][0]; - - vecs[1].texture_position.u = pm->ins[idx].u[s_idx][1]; - vecs[1].texture_position.v = pm->ins[idx].v[s_idx][1]; - - vecs[2].texture_position.u = pm->ins[idx].u[s_idx][2]; - vecs[2].texture_position.v = pm->ins[idx].v[s_idx][2]; - - light_apply_rgb( &vecs[0].r, &vecs[0].g, &vecs[0].b, &pm->ins[idx].vecs[i1], &pm->ins[idx].norm[i1], 1.5f ); - light_apply_rgb( &vecs[1].r, &vecs[1].g, &vecs[1].b, &pm->ins[idx].vecs[i2], &pm->ins[idx].norm[i2], 1.5f ); - light_apply_rgb( &vecs[2].r, &vecs[2].g, &vecs[2].b, &pm->ins[idx].vecs[i3], &pm->ins[idx].norm[i3], 1.5f ); - vecs[0].a = vecs[1].a = vecs[2].a = 255; - - // draw the polygon - g3_render_primitives_colored_textured(&insignia_material, vecs, 3, PRIM_TYPE_TRIFAN, false); - } - } -} - SCP_vector Arc_segment_points; void model_render_arc(const vec3d *v1, const vec3d *v2, const SCP_vector *persistent_arc_points, const color *primary, const color *secondary, float arc_width, ubyte depth_limit) @@ -2652,7 +2539,6 @@ void model_render_immediate(const model_render_params* render_info, int model_nu } model_list.render_outlines(); - model_list.render_insignias(); model_list.render_arcs(); gr_zbias(0); diff --git a/code/model/modelrender.h b/code/model/modelrender.h index 64f041a15ef..1b120fe1d19 100644 --- a/code/model/modelrender.h +++ b/code/model/modelrender.h @@ -254,7 +254,6 @@ class model_draw_list SCP_vector Render_keys; SCP_vector Arcs; - SCP_vector Insignias; SCP_vector Outlines; graphics::util::UniformBuffer _dataBuffer; @@ -287,9 +286,6 @@ class model_draw_list void add_arc(const vec3d *v1, const vec3d *v2, const SCP_vector *persistent_arc_points, const color *primary, const color *secondary, float arc_width, ubyte segment_depth); void render_arcs(); - void add_insignia(const model_render_params *params, const polymodel *pm, int detail_level, int bitmap_num); - void render_insignias(); - void add_outline(const vertex* vert_array, int n_verts, const color *clr); void render_outlines(); @@ -312,7 +308,6 @@ void submodel_render_queue(const model_render_params* render_info, model_draw_li void model_render_buffers(model_draw_list* scene, model_material* rendering_material, const model_render_params* interp, const vertex_buffer* buffer, const polymodel* pm, int mn, int detail_level, uint tmap_flags); bool model_render_check_detail_box(const vec3d* view_pos, const polymodel* pm, int submodel_num, uint64_t flags); void model_render_arc(const vec3d* v1, const vec3d* v2, const SCP_vector *persistent_arc_points, const color* primary, const color* secondary, float arc_width, ubyte depth_limit); -void model_render_insignias(const insignia_draw_data* insignia); void model_render_set_wireframe_color(const color* clr); bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int y2, float zoom, bool lighting, int class_idx, const matrix* orient, const SCP_string& pof_filename = "", float closeup_zoom = 0, const vec3d* closeup_pos = &vmd_zero_vector, const SCP_string& tcolor = ""); diff --git a/code/object/objectsort.cpp b/code/object/objectsort.cpp index 0107c0de30e..f438936d6b6 100644 --- a/code/object/objectsort.cpp +++ b/code/object/objectsort.cpp @@ -388,7 +388,6 @@ void obj_render_queue_all() // render electricity effects and insignias scene.render_outlines(); - scene.render_insignias(); scene.render_arcs(); gr_zbuffer_set(ZBUFFER_TYPE_READ); From 665d7145b65f05c88a7321f4d79ba61b7c28b03a Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Sat, 19 Jul 2025 00:50:26 +0200 Subject: [PATCH 07/11] Move insignia post-processing to model load --- code/model/model.h | 16 ++----- code/model/modelread.cpp | 93 +++++++++++++++++++++++--------------- code/model/modelrender.cpp | 47 +++---------------- 3 files changed, 67 insertions(+), 89 deletions(-) diff --git a/code/model/model.h b/code/model/model.h index 65a6c092bfe..9ca939a602c 100644 --- a/code/model/model.h +++ b/code/model/model.h @@ -724,13 +724,9 @@ typedef struct cross_section { #define MAX_INS_FACES 128 typedef struct insignia { int detail_level; - int num_faces; - int faces[MAX_INS_FACES][MAX_INS_FACE_VECS]; // indices into the vecs array - float u[MAX_INS_FACES][MAX_INS_FACE_VECS]; // u tex coords on a per-face-per-vertex basis - float v[MAX_INS_FACES][MAX_INS_FACE_VECS]; // v tex coords on a per-face-per-vertex bases - vec3d vecs[MAX_INS_VECS]; // vertex list - vec3d offset; // global position offset for this insignia - vec3d norm[MAX_INS_VECS] ; //normal of the insignia-Bobboau + vec3d position; + matrix orientation; + float diameter; } insignia; #define PM_FLAG_ALLOW_TILING (1<<0) // Allow texture tiling @@ -806,7 +802,7 @@ class polymodel n_view_positions(0), rad(0.0f), core_radius(0.0f), n_textures(0), submodel(NULL), n_guns(0), n_missiles(0), n_docks(0), n_thrusters(0), gun_banks(NULL), missile_banks(NULL), docking_bays(NULL), thrusters(NULL), ship_bay(NULL), shield(), shield_collision_tree(NULL), sldc_size(0), n_paths(0), paths(NULL), mass(0), num_xc(0), xc(NULL), num_split_plane(0), - num_ins(0), used_this_mission(0), n_glow_point_banks(0), glow_point_banks(nullptr), + used_this_mission(0), n_glow_point_banks(0), glow_point_banks(nullptr), vert_source() { filename[0] = 0; @@ -819,7 +815,6 @@ class polymodel memset(&bounding_box, 0, 8 * sizeof(vec3d)); memset(&view_positions, 0, MAX_EYES * sizeof(eye)); memset(&split_plane, 0, MAX_SPLIT_PLANE * sizeof(float)); - memset(&ins, 0, MAX_MODEL_INSIGNIAS * sizeof(insignia)); #ifndef NDEBUG ram_used = 0; @@ -894,8 +889,7 @@ class polymodel int num_split_plane; // number of split planes float split_plane[MAX_SPLIT_PLANE]; // actual split plane z coords (for big ship explosions) - insignia ins[MAX_MODEL_INSIGNIAS]; - int num_ins; + SCP_vector ins; #ifndef NDEBUG int ram_used; // How much RAM this model uses diff --git a/code/model/modelread.cpp b/code/model/modelread.cpp index bc26c7c40e1..3638a2b02d5 100644 --- a/code/model/modelread.cpp +++ b/code/model/modelread.cpp @@ -1657,8 +1657,8 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename, memset( &pm->view_positions, 0, sizeof(pm->view_positions) ); - // reset insignia counts - pm->num_ins = 0; + // reset insignia + pm->ins.clear(); // reset glow points!! - Goober5000 pm->n_glow_point_banks = 0; @@ -2806,62 +2806,81 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename, } break; - case ID_INSG: - int num_ins, num_verts, num_faces, idx, idx2, idx3; - + case ID_INSG: { // get the # of insignias - num_ins = cfread_int(fp); - pm->num_ins = num_ins; - + int num_ins = cfread_int(fp); + pm->ins = SCP_vector(num_ins); + // read in the insignias - for(idx=0; idxins[idx]; + // get the detail level - pm->ins[idx].detail_level = cfread_int(fp); - if (pm->ins[idx].detail_level < 0) { - Warning(LOCATION, "Model '%s': insignia uses an invalid LOD (%i)\n", pm->filename, pm->ins[idx].detail_level); + ins.detail_level = cfread_int(fp); + if (ins.detail_level < 0) { + Warning(LOCATION, "Model '%s': insignia uses an invalid LOD (%i)\n", pm->filename, ins.detail_level); } // # of faces - num_faces = cfread_int(fp); - pm->ins[idx].num_faces = num_faces; - Assert(num_faces <= MAX_INS_FACES); + int num_faces = cfread_int(fp); // # of vertices - num_verts = cfread_int(fp); - Assert(num_verts <= MAX_INS_VECS); + int num_verts = cfread_int(fp); + SCP_vector vertices(num_verts); // read in all the vertices - for(idx2=0; idx2ins[idx].vecs[idx2], fp); + for(int idx2 = 0; idx2 < num_verts; idx2++){ + cfread_vector(&vertices[idx2], fp); } + vec3d offset; // read in world offset - cfread_vector(&pm->ins[idx].offset, fp); + cfread_vector(&offset, fp); + + vec3d min {{{FLT_MAX, FLT_MAX, FLT_MAX}}}; + vec3d max {{{-FLT_MAX, -FLT_MAX, -FLT_MAX}}}; + vec3d avg_total = ZERO_VECTOR; + vec3d avg_normal = ZERO_VECTOR; // read in all the faces - for(idx2=0; idx2ins[idx].num_faces; idx2++){ + for(int idx2 = 0; idx2 < num_faces; idx2++){ + std::array faces; // read in 3 vertices - for(idx3=0; idx3<3; idx3++){ - pm->ins[idx].faces[idx2][idx3] = cfread_int(fp); - pm->ins[idx].u[idx2][idx3] = cfread_float(fp); - pm->ins[idx].v[idx2][idx3] = cfread_float(fp); - } - vec3d tempv; - - //get three points (rotated) and compute normal + for(int idx3 = 0; idx3 < 3; idx3++){ + faces[idx3] = cfread_int(fp); - vm_vec_perp(&tempv, - &pm->ins[idx].vecs[pm->ins[idx].faces[idx2][0]], - &pm->ins[idx].vecs[pm->ins[idx].faces[idx2][1]], - &pm->ins[idx].vecs[pm->ins[idx].faces[idx2][2]]); + //UV coords are no longer needed + cfread_float(fp); + cfread_float(fp); + } - vm_vec_normalize_safe(&tempv); + const vec3d& v1 = vertices[faces[0]]; + const vec3d& v2 = vertices[faces[1]]; + const vec3d& v3 = vertices[faces[2]]; - pm->ins[idx].norm[idx2] = tempv; + vec3d normal; + //get three points (rotated) and compute normal + vm_vec_perp(&normal, &v1, &v2, &v3); + + vm_vec_min(&min, &min, &v1); + vm_vec_min(&min, &min, &v2); + vm_vec_min(&min, &min, &v3); + vm_vec_max(&max, &max, &v1); + vm_vec_max(&max, &max, &v2); + vm_vec_max(&max, &max, &v3); + + vec3d avg = (v1 + v2 + v3) * (1.0f / 3.0f); + avg_total += avg; + avg_normal += normal; // mprintf(("insignorm %.2f %.2f %.2f\n",pm->ins[idx].norm[idx2].xyz.x, pm->ins[idx].norm[idx2].xyz.y, pm->ins[idx].norm[idx2].xyz.z)); - } - } + + ins.position = avg_total / num_faces + offset; + vec3d bb = max - min; + ins.diameter = std::max({bb.xyz.x, bb.xyz.y, bb.xyz.z}); + vm_vector_2_matrix(&ins.orientation, &avg_normal, &vmd_z_vector); + } + } break; // autocentering info diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index b8f4a138fc4..545db0023ce 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -2858,58 +2858,23 @@ void model_render_queue(const model_render_params* interp, model_draw_list* scen // MARKED! if ( !( model_flags & MR_NO_TEXTURING ) && !( model_flags & MR_NO_INSIGNIA) && objnum >= 0 ) { int bitmap_num = interp->get_insignia_bitmap(); - if ( (pm->num_ins > 0) && (bitmap_num >= 0) ) { + if ( (!pm->ins.empty()) && (bitmap_num >= 0) ) { - for (int idx=0; idxnum_ins; idx++) { + for (const auto& ins : pm->ins) { // skip insignias not on our detail level - if (pm->ins[idx].detail_level != detail_level) { + if (ins.detail_level != detail_level) { continue; } - vec3d min {{{FLT_MAX, FLT_MAX, FLT_MAX}}}; - vec3d max {{{-FLT_MAX, -FLT_MAX, -FLT_MAX}}}; - vec3d avg_total = ZERO_VECTOR; - vec3d avg_normal = ZERO_VECTOR; - for(int s_idx=0; s_idxins[idx].num_faces; s_idx++) { - // get vertex indices - int i1 = pm->ins[idx].faces[s_idx][0]; - int i2 = pm->ins[idx].faces[s_idx][1]; - int i3 = pm->ins[idx].faces[s_idx][2]; - - const vec3d& v1 = pm->ins[idx].vecs[i1]; - const vec3d& v2 = pm->ins[idx].vecs[i2]; - const vec3d& v3 = pm->ins[idx].vecs[i3]; - - vm_vec_min(&min, &min, &v1); - vm_vec_min(&min, &min, &v2); - vm_vec_min(&min, &min, &v3); - vm_vec_max(&max, &max, &v1); - vm_vec_max(&max, &max, &v2); - vm_vec_max(&max, &max, &v3); - - // transform vecs and setup vertices - vec3d avg = (v1 + v2 + v3) * (1.0f / 3.0f); - avg_total += avg; - - const vec3d& u = v2 - v1; - const vec3d& v = v3 - v1; - avg_normal.xyz.x += u.xyz.y * v.xyz.z - u.xyz.z * v.xyz.y; - avg_normal.xyz.y += u.xyz.z * v.xyz.x - u.xyz.x * v.xyz.z; - avg_normal.xyz.z += u.xyz.x * v.xyz.y - u.xyz.y * v.xyz.x; - } - avg_total /= pm->ins[idx].num_faces; - vec3d bb = max - min; - float diameter = std::max({bb.xyz.x, bb.xyz.y, bb.xyz.z}); - decals::Decal decal; decal.object = &Objects[objnum]; - decal.position = avg_total + pm->ins[idx].offset; + decal.position = ins.position; decal.submodel = -1; - decal.scale = vec3d{{{diameter, diameter, diameter}}}; + decal.scale = vec3d{{{ins.diameter, ins.diameter, ins.diameter}}}; decal.orig_obj_type = OBJ_SHIP; decal.creation_time = f2fl(Missiontime); decal.lifetime = 1.0f; - vm_vector_2_matrix(&decal.orientation, &avg_normal, &vmd_z_vector); + decal.orientation = ins.orientation; decal.definition_handle = std::make_tuple(bitmap_num, -1, -1); decals::addSingleFrameDecal(std::move(decal)); } From 49a787982b1f0b6870806d910bb5ecda4cb876a3 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Sun, 20 Jul 2025 13:21:20 +0200 Subject: [PATCH 08/11] perform envmap lighting in deferred shader --- code/def_files/data/effects/deferred-f.sdr | 84 ++++++++++++++++++---- code/graphics/2d.h | 2 + code/graphics/material.cpp | 4 +- code/graphics/opengl/gropengldeferred.cpp | 15 +++- code/graphics/opengl/gropenglshader.cpp | 2 + 5 files changed, 90 insertions(+), 17 deletions(-) diff --git a/code/def_files/data/effects/deferred-f.sdr b/code/def_files/data/effects/deferred-f.sdr index 5289393d6f4..95349253f6f 100644 --- a/code/def_files/data/effects/deferred-f.sdr +++ b/code/def_files/data/effects/deferred-f.sdr @@ -1,6 +1,6 @@ //? #version 150 #include "lighting.sdr" //! #include "lighting.sdr" - +#include "gamma.sdr" //! #include "gamma.sdr" #include "shadows.sdr" //! #include "shadows.sdr" out vec4 fragOut0; @@ -11,6 +11,11 @@ uniform sampler2D PositionBuffer; uniform sampler2D SpecBuffer; uniform sampler2DArray shadow_map; +#ifdef ENV_MAP +uniform samplerCube sEnvmap; +uniform samplerCube sIrrmap; +#endif + layout (std140) uniform globalDeferredData { mat4 shadow_mv_matrix; mat4 shadow_proj_matrix[4]; @@ -97,7 +102,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li discard; } attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0); - } + } else if (lightType == LT_TUBE) { // Tube light vec3 beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0)); vec3 beamDir = normalize(beamVec); @@ -138,7 +143,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li discard; } attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0); - } + } else if (lightType == LT_CONE) { lightDirOut = lightPosition - position.xyz; float coneDot = dot(normalize(-lightDirOut), coneDir); @@ -165,6 +170,51 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li } } +#ifdef ENV_MAP +void ComputeEnvLight(float alpha, float ao, vec3 light_dir, vec3 eyeDir, vec3 normal, vec4 baseColor, vec4 specColor, out vec3 envLight) { + // Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from + // Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al. + // to determine the mip bias. + // We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html + // 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2) + // so let s = (2/alpha^2 - 2) + // 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1) + + const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes + const float REZ_BIAS = log2(ENV_REZ * sqrt(3)); + + float alphaSqr = alpha * alpha; + float rough_bias = 0.5 * log2(2/alphaSqr - 1); + float mip_bias = REZ_BIAS - rough_bias; + + // Sample light, using mip bias to blur it. + vec3 env_light_dir = vec3(modelViewMatrix * vec4(light_dir, 0.0)); + vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias)); + + vec3 halfVec = normal; + + // Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture + // or properly calculating IBL levels. + // Fresnel calculation as with standard lights. + + vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a); + + // Pseudo-IBL, so use k_IBL + float k = alpha * alpha/ 2.0f; + + float NdotL = max(dot(light_dir, normal),0); + + float g1vNL = GeometrySchlickGGX(NdotL, k); + vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL; + + vec3 kD = vec3(1.0)-fresnel; + kD *= (vec3(1.0) - specColor.rgb); + vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(modelViewMatrix * vec4(normal, 0.0))).rgb); + vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * ao; + envLight = (specEnvLighting + diffEnvLighting) * baseColor.a; +} +#endif + void main() { vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight); @@ -174,28 +224,36 @@ void main() if(abs(dot(position, position)) < nearPlane * nearPlane) discard; - vec3 diffColor = texture(ColorBuffer, screenPos).rgb; + vec4 diffuse = texture(ColorBuffer, screenPos); + vec3 diffColor = diffuse.rgb; + vec4 normalData = texture(NormalBuffer, screenPos); + // The vector in the normal buffer could be longer than the unit vector since decal rendering only adds to the normal buffer + vec3 normal = normalize(normalData.xyz); + float gloss = normalData.a; + float roughness = clamp(1.0f - gloss, 0.0f, 1.0f); + float alpha = roughness * roughness; + vec3 eyeDir = normalize(-position); + vec3 reflectDir = reflect(-eyeDir, normal); + vec4 specColor = texture(SpecBuffer, screenPos); + vec4 fragmentColor = vec4(1.0); if (lightType == LT_AMBIENT) { float ao = position_buffer.w; fragmentColor.rgb = diffuseLightColor * diffColor * ao; + +#ifdef ENV_MAP + vec3 envLight; + ComputeEnvLight(alpha, ao, reflectDir, eyeDir, normal, diffuse, specColor, envLight); + fragmentColor.rgb += envLight; +#endif } else { - vec4 normalData = texture(NormalBuffer, screenPos); - vec4 specColor = texture(SpecBuffer, screenPos); - // The vector in the normal buffer could be longer than the unit vector since decal rendering only adds to the normal buffer - vec3 normal = normalize(normalData.xyz); - float gloss = normalData.a; - float roughness = clamp(1.0f - gloss, 0.0f, 1.0f); - float alpha = roughness * roughness; float fresnel = specColor.a; - vec3 eyeDir = normalize(-position); vec3 lightDir; float attenuation; float area_normalisation; - vec3 reflectDir = reflect(-eyeDir, normal); GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation); if (enable_shadows) { diff --git a/code/graphics/2d.h b/code/graphics/2d.h index 7158fb8075e..b701bdeefc6 100644 --- a/code/graphics/2d.h +++ b/code/graphics/2d.h @@ -239,6 +239,8 @@ enum shader_type { #define SDR_FLAG_TONEMAPPING_LINEAR_OUT (1 << 0) +#define SDR_FLAG_ENV_MAP (1 << 0) + enum class uniform_block_type { Lights = 0, diff --git a/code/graphics/material.cpp b/code/graphics/material.cpp index 6c6ab8ae6d6..996019f36c2 100644 --- a/code/graphics/material.cpp +++ b/code/graphics/material.cpp @@ -774,8 +774,8 @@ int model_material::get_shader_runtime_flags() const { flags |= MODEL_SDR_FLAG_GLOW; if (get_texture_map(TM_SPECULAR_TYPE) > 0 || get_texture_map(TM_SPEC_GLOSS_TYPE) > 0) flags |= MODEL_SDR_FLAG_SPEC; - if (ENVMAP > 0) - flags |= MODEL_SDR_FLAG_ENV; + //if (ENVMAP > 0) + // flags |= MODEL_SDR_FLAG_ENV; if (get_texture_map(TM_NORMAL_TYPE) > 0) flags |= MODEL_SDR_FLAG_NORMAL; if (get_texture_map(TM_AMBIENT_TYPE) > 0) diff --git a/code/graphics/opengl/gropengldeferred.cpp b/code/graphics/opengl/gropengldeferred.cpp index 332aeb6ef91..c571d20a7ee 100644 --- a/code/graphics/opengl/gropengldeferred.cpp +++ b/code/graphics/opengl/gropengldeferred.cpp @@ -224,7 +224,7 @@ void gr_opengl_deferred_lighting_finish() // GL_state.DepthFunc(GL_GREATER); // GL_state.DepthMask(GL_FALSE); - opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_DEFERRED_LIGHTING, 0)); + opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_DEFERRED_LIGHTING, ENVMAP > 0 ? SDR_FLAG_ENV_MAP : 0)); // Render on top of the composite buffer texture glDrawBuffer(GL_COLOR_ATTACHMENT5); @@ -248,6 +248,16 @@ void gr_opengl_deferred_lighting_finish() GL_state.Texture.Enable(4, GL_TEXTURE_2D_ARRAY, Shadow_map_texture); } + if (ENVMAP > 0) { + Current_shader->program->Uniforms.setTextureUniform("sEnvmap", 5); + Current_shader->program->Uniforms.setTextureUniform("sIrrmap", 6); + float u_scale, v_scale; + uint32_t array_index; + gr_opengl_tcache_set(ENVMAP, TCACHE_TYPE_CUBEMAP, &u_scale, &v_scale, &array_index, 5); + gr_opengl_tcache_set(IRRMAP, TCACHE_TYPE_CUBEMAP, &u_scale, &v_scale, &array_index, 6); + Assertion(array_index == 0, "Cube map arrays are not supported yet!"); + } + // We need to use stable sorting here to make sure that the relative ordering of the same light types is the same as // the rest of the code. Otherwise the shadow mapping would be applied while rendering the wrong light which would // lead to flickering lights in some circumstances @@ -408,7 +418,8 @@ void gr_opengl_deferred_lighting_finish() { for (size_t i = 0; i(); + auto matrix_data = matrix_uniform_aligner.addTypedElement(); + matrix_data->modelViewMatrix = gr_env_texture_matrix; } for (auto& l : sphere_lights) { auto matrix_data = matrix_uniform_aligner.addTypedElement(); diff --git a/code/graphics/opengl/gropenglshader.cpp b/code/graphics/opengl/gropenglshader.cpp index 9c1dca46b97..f17cd83ee45 100644 --- a/code/graphics/opengl/gropenglshader.cpp +++ b/code/graphics/opengl/gropenglshader.cpp @@ -190,6 +190,8 @@ static opengl_shader_variant_t GL_shader_variants[] = { {SDR_TYPE_EFFECT_PARTICLE, true, SDR_FLAG_PARTICLE_POINT_GEN, "FLAG_EFFECT_GEOMETRY", {opengl_vert_attrib::UVEC}, "Geometry shader point-based particles"}, + {SDR_TYPE_DEFERRED_LIGHTING, false, SDR_FLAG_ENV_MAP, "ENV_MAP", {}, "Render ambient light with env and irrmaps"}, + {SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_HORIZONTAL, "PASS_0", {}, "Horizontal blur pass"}, {SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_VERTICAL, "PASS_1", {}, "Vertical blur pass"}, From a3419de2da679dd90a13f0bda8496532297b2f61 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Sun, 20 Jul 2025 13:30:52 +0200 Subject: [PATCH 09/11] Remove Envmapping from main shader --- code/def_files/data/effects/main-f.sdr | 57 ------------------- code/def_files/data/effects/main-g.sdr | 17 ------ code/def_files/data/effects/main-v.sdr | 11 ---- .../data/effects/model_shader_flags.h | 23 ++++---- code/graphics/material.cpp | 2 - code/graphics/opengl/gropengltnl.cpp | 10 ---- code/graphics/uniforms.cpp | 10 ---- code/graphics/util/uniform_structs.h | 1 - 8 files changed, 11 insertions(+), 120 deletions(-) diff --git a/code/def_files/data/effects/main-f.sdr b/code/def_files/data/effects/main-f.sdr index 4debb197ec5..e60324df170 100644 --- a/code/def_files/data/effects/main-f.sdr +++ b/code/def_files/data/effects/main-f.sdr @@ -32,7 +32,6 @@ layout (std140) uniform modelData { mat4 textureMatrix; mat4 shadow_mv_matrix; mat4 shadow_proj_matrix[4]; - mat4 envMatrix; vec4 color; @@ -96,10 +95,6 @@ layout (std140) uniform modelData { }; in VertexOutput { -#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV - vec3 envReflect; -#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV - mat3 tangentMatrix; #prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG @@ -125,10 +120,6 @@ uniform sampler2DArray sGlowmap; #prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC uniform sampler2DArray sSpecmap; #prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC -#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV -uniform samplerCube sEnvmap; -uniform samplerCube sIrrmap; -#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV #prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL uniform sampler2DArray sNormalmap; #prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL @@ -355,54 +346,6 @@ void main() #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED - #prereplace IF_FLAG MODEL_SDR_FLAG_ENV - #prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT - // Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from - // Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al. - // to determine the mip bias. - // We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html - // 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2) - // so let s = (2/alpha^2 - 2) - // 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1) - - const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes - const float REZ_BIAS = log2(ENV_REZ * sqrt(3)); - - float roughness = clamp(1.0f - glossData, 0.0f, 1.0f); - float alpha = roughness * roughness; - float alphaSqr = alpha * alpha; - float rough_bias = 0.5 * log2(2/alphaSqr - 1); - float mip_bias = REZ_BIAS - rough_bias; - - // Sample light, using mip bias to blur it. - vec3 light_dir = reflect(-eyeDir, normal); - vec3 env_light_dir = vec3(envMatrix * vec4(light_dir, 0.0)); - vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias)); - - vec3 halfVec = normal; - - // Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture - // or properly calculating IBL levels. - // Fresnel calculation as with standard lights. - - vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a); - - // Pseudo-IBL, so use k_IBL - float k = alpha * alpha/ 2.0f; - - float NdotL = max(dot(light_dir, normal),0); - - float g1vNL = GeometrySchlickGGX(NdotL, k); - vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL; - - vec3 kD = vec3(1.0)-fresnel; - kD *= (vec3(1.0) - specColor.rgb); - vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb); - vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x; - emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a; - #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT - #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV - #prereplace IF_FLAG MODEL_SDR_FLAG_GLOW vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb; #prereplace IF_FLAG MODEL_SDR_FLAG_MISC diff --git a/code/def_files/data/effects/main-g.sdr b/code/def_files/data/effects/main-g.sdr index b869ea5f46d..24db6200630 100644 --- a/code/def_files/data/effects/main-g.sdr +++ b/code/def_files/data/effects/main-g.sdr @@ -39,7 +39,6 @@ layout (std140) uniform modelData { mat4 textureMatrix; mat4 shadow_mv_matrix; mat4 shadow_proj_matrix[4]; - mat4 envMatrix; vec4 color; @@ -103,10 +102,6 @@ layout (std140) uniform modelData { }; in VertexOutput { -#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV - vec3 envReflect; -#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV - mat3 tangentMatrix; #prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG @@ -131,10 +126,6 @@ in VertexOutput { } vertIn[]; out VertexOutput { -#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV - vec3 envReflect; -#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV - mat3 tangentMatrix; #prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG @@ -181,10 +172,6 @@ out VertexOutput { gl_Layer = instanceID; - #prereplace IF_FLAG MODEL_SDR_FLAG_ENV - vertOut.envReflect = vertIn[vert].envReflect; - #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV - #prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL vertOut.tangentMatrix = vertIn[vert].tangentMatrix; #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL @@ -239,10 +226,6 @@ out VertexOutput { vertOut.normal = vertIn[vert].normal; vertOut.texCoord = vertIn[vert].texCoord; - #prereplace IF_FLAG MODEL_SDR_FLAG_ENV - vertOut.envReflect = vertIn[vert].envReflect; - #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV - #prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL vertOut.tangentMatrix = vertIn[vert].tangentMatrix; #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL diff --git a/code/def_files/data/effects/main-v.sdr b/code/def_files/data/effects/main-v.sdr index eaa3185d25c..2033c944165 100644 --- a/code/def_files/data/effects/main-v.sdr +++ b/code/def_files/data/effects/main-v.sdr @@ -34,7 +34,6 @@ layout (std140) uniform modelData { mat4 textureMatrix; mat4 shadow_mv_matrix; mat4 shadow_proj_matrix[4]; - mat4 envMatrix; vec4 color; @@ -102,10 +101,6 @@ uniform samplerBuffer transform_tex; #prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM out VertexOutput { -#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV - vec3 envReflect; -#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV - mat3 tangentMatrix; #prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG @@ -193,12 +188,6 @@ void main() vec3 b = cross(normal, t) * vertTangent.w; vertOut.tangentMatrix = mat3(t, b, normal); - #prereplace IF_FLAG MODEL_SDR_FLAG_ENV - // Environment mapping reflection vector. - vec3 envReflect = reflect(normalize(position.xyz), normal); - vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0)); - #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV - #prereplace IF_FLAG MODEL_SDR_FLAG_FOG vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0); #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG diff --git a/code/def_files/data/effects/model_shader_flags.h b/code/def_files/data/effects/model_shader_flags.h index 51a08ee9f52..a2ebe122e35 100644 --- a/code/def_files/data/effects/model_shader_flags.h +++ b/code/def_files/data/effects/model_shader_flags.h @@ -14,22 +14,21 @@ SDR_FLAG(MODEL_SDR_FLAG_HDR , (1 << 2) , false) SDR_FLAG(MODEL_SDR_FLAG_DIFFUSE , (1 << 3) , false) SDR_FLAG(MODEL_SDR_FLAG_GLOW , (1 << 4) , false) SDR_FLAG(MODEL_SDR_FLAG_SPEC , (1 << 5) , false) -SDR_FLAG(MODEL_SDR_FLAG_ENV , (1 << 6) , false) -SDR_FLAG(MODEL_SDR_FLAG_NORMAL , (1 << 7) , false) -SDR_FLAG(MODEL_SDR_FLAG_AMBIENT , (1 << 8) , false) -SDR_FLAG(MODEL_SDR_FLAG_MISC , (1 << 9) , false) -SDR_FLAG(MODEL_SDR_FLAG_TEAMCOLOR , (1 << 10), false) -SDR_FLAG(MODEL_SDR_FLAG_FOG , (1 << 11), false) -SDR_FLAG(MODEL_SDR_FLAG_TRANSFORM , (1 << 12), false) -SDR_FLAG(MODEL_SDR_FLAG_SHADOWS , (1 << 13), false) -SDR_FLAG(MODEL_SDR_FLAG_THRUSTER , (1 << 14), false) -SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 15), false) +SDR_FLAG(MODEL_SDR_FLAG_NORMAL , (1 << 6) , false) +SDR_FLAG(MODEL_SDR_FLAG_AMBIENT , (1 << 7) , false) +SDR_FLAG(MODEL_SDR_FLAG_MISC , (1 << 8) , false) +SDR_FLAG(MODEL_SDR_FLAG_TEAMCOLOR , (1 << 9), false) +SDR_FLAG(MODEL_SDR_FLAG_FOG , (1 << 10), false) +SDR_FLAG(MODEL_SDR_FLAG_TRANSFORM , (1 << 11), false) +SDR_FLAG(MODEL_SDR_FLAG_SHADOWS , (1 << 12), false) +SDR_FLAG(MODEL_SDR_FLAG_THRUSTER , (1 << 13), false) +SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 14), false) #ifndef MODEL_SDR_FLAG_MODE_GLSL //The following ones are used ONLY as compile-time flags, but they still need to be defined here to ensure no conflict occurs //But since these are checked with ifdefs even for the large shader, they must never be available in GLSL mode -SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 16), true) -SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 17), true) +SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 15), true) +SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 16), true) #endif \ No newline at end of file diff --git a/code/graphics/material.cpp b/code/graphics/material.cpp index 996019f36c2..d4e05cba1a1 100644 --- a/code/graphics/material.cpp +++ b/code/graphics/material.cpp @@ -774,8 +774,6 @@ int model_material::get_shader_runtime_flags() const { flags |= MODEL_SDR_FLAG_GLOW; if (get_texture_map(TM_SPECULAR_TYPE) > 0 || get_texture_map(TM_SPEC_GLOSS_TYPE) > 0) flags |= MODEL_SDR_FLAG_SPEC; - //if (ENVMAP > 0) - // flags |= MODEL_SDR_FLAG_ENV; if (get_texture_map(TM_NORMAL_TYPE) > 0) flags |= MODEL_SDR_FLAG_NORMAL; if (get_texture_map(TM_AMBIENT_TYPE) > 0) diff --git a/code/graphics/opengl/gropengltnl.cpp b/code/graphics/opengl/gropengltnl.cpp index db51f62b7bc..70f97fd3654 100644 --- a/code/graphics/opengl/gropengltnl.cpp +++ b/code/graphics/opengl/gropengltnl.cpp @@ -856,10 +856,6 @@ void opengl_tnl_set_model_material(model_material *material_info) Current_shader->program->Uniforms.setTextureUniform("sGlowmap", 1); if (setAllUniforms || (flags & MODEL_SDR_FLAG_SPEC)) Current_shader->program->Uniforms.setTextureUniform("sSpecmap", 2); - if (setAllUniforms || (flags & MODEL_SDR_FLAG_ENV)) { - Current_shader->program->Uniforms.setTextureUniform("sEnvmap", 3); - Current_shader->program->Uniforms.setTextureUniform("sIrrmap", 11); - } if (setAllUniforms || (flags & MODEL_SDR_FLAG_NORMAL)) Current_shader->program->Uniforms.setTextureUniform("sNormalmap", 4); if (setAllUniforms || (flags & MODEL_SDR_FLAG_AMBIENT)) @@ -912,12 +908,6 @@ void opengl_tnl_set_model_material(model_material *material_info) } } - if (ENVMAP > 0) { - gr_opengl_tcache_set(ENVMAP, TCACHE_TYPE_CUBEMAP, &u_scale, &v_scale, &array_index, 3); - gr_opengl_tcache_set(IRRMAP, TCACHE_TYPE_CUBEMAP, &u_scale, &v_scale, &array_index, 11); - Assertion(array_index == 0, "Cube map arrays are not supported yet!"); - } - if (material_info->get_texture_map(TM_NORMAL_TYPE) > 0) { gr_opengl_tcache_set(material_info->get_texture_map(TM_NORMAL_TYPE), TCACHE_TYPE_NORMAL, diff --git a/code/graphics/uniforms.cpp b/code/graphics/uniforms.cpp index fa7b27258c3..70cef3ea4e9 100644 --- a/code/graphics/uniforms.cpp +++ b/code/graphics/uniforms.cpp @@ -151,16 +151,6 @@ void convert_model_material(model_uniform_data* data_out, data_out->gammaSpec = 0; data_out->alphaGloss = 0; } - - if (ENVMAP > 0) { - if (material.get_texture_map(TM_SPEC_GLOSS_TYPE) > 0) { - data_out->envGloss = 1; - } else { - data_out->envGloss = 0; - } - - data_out->envMatrix = gr_env_texture_matrix; - } if (material.get_texture_map(TM_NORMAL_TYPE) > 0) { data_out->sNormalmapIndex = bm_get_array_index(material.get_texture_map(TM_NORMAL_TYPE)); diff --git a/code/graphics/util/uniform_structs.h b/code/graphics/util/uniform_structs.h index c290fc812d0..391e6d36fa5 100644 --- a/code/graphics/util/uniform_structs.h +++ b/code/graphics/util/uniform_structs.h @@ -81,7 +81,6 @@ struct model_uniform_data { matrix4 textureMatrix; matrix4 shadow_mv_matrix; matrix4 shadow_proj_matrix[4]; - matrix4 envMatrix; vec4 color; From 6b5e4743db39de18f7377fdf877dd46ffb0cfc95 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Sun, 20 Jul 2025 13:56:08 +0200 Subject: [PATCH 10/11] Fix MSVC warning --- code/model/modelread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/model/modelread.cpp b/code/model/modelread.cpp index 3638a2b02d5..66c24c479c5 100644 --- a/code/model/modelread.cpp +++ b/code/model/modelread.cpp @@ -2875,7 +2875,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename, // mprintf(("insignorm %.2f %.2f %.2f\n",pm->ins[idx].norm[idx2].xyz.x, pm->ins[idx].norm[idx2].xyz.y, pm->ins[idx].norm[idx2].xyz.z)); } - ins.position = avg_total / num_faces + offset; + ins.position = avg_total / static_cast(num_faces) + offset; vec3d bb = max - min; ins.diameter = std::max({bb.xyz.x, bb.xyz.y, bb.xyz.z}); vm_vector_2_matrix(&ins.orientation, &avg_normal, &vmd_z_vector); From b280d806ce92af747c5ce3e58dea2f2ef121eb4a Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Sun, 20 Jul 2025 14:26:50 +0200 Subject: [PATCH 11/11] exclude def_files from clang tidy --- ci/linux/clang_tidy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/linux/clang_tidy.sh b/ci/linux/clang_tidy.sh index 4ec7a6a7191..8e514ef40fe 100755 --- a/ci/linux/clang_tidy.sh +++ b/ci/linux/clang_tidy.sh @@ -26,5 +26,5 @@ git diff -U0 --no-color "$BASE_COMMIT..$2" | \ -extra-arg="-DWITH_VULKAN" \ -extra-arg="-DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1" \ -extra-arg="-DVK_NO_PROTOTYPES" \ - -regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test\/src|build|tools)\/.*\.(cpp|h)' \ + -regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)|(\/def_files\/data)))|freespace2|qtfred|test\/src|build|tools)\/.*\.(cpp|h)' \ -clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"