diff --git a/code/def_files/data/effects/deferred-clear-f.sdr b/code/def_files/data/effects/deferred-clear-f.sdr index ed15e5516b0..0e60ec56fed 100644 --- a/code/def_files/data/effects/deferred-clear-f.sdr +++ b/code/def_files/data/effects/deferred-clear-f.sdr @@ -4,12 +4,14 @@ out vec4 fragOut2; out vec4 fragOut3; out vec4 fragOut4; out vec4 fragOut5; +out vec4 fragOut6; void main() { fragOut0 = vec4(0.0, 0.0, 0.0, 1.0); // color fragOut1 = vec4(0.0, 0.0, -1000000.0, 1.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 - fragOut5 = vec4(0.0, 0.0, 0.0, 1.0); // composite + fragOut4 = vec4(0.0, 0.0, 0.0, 1.0); // bent + fragOut5 = vec4(0.0, 0.0, 0.0, 1.0); // emissive + fragOut6 = vec4(0.0, 0.0, 0.0, 1.0); // composite } diff --git a/code/def_files/data/effects/deferred-f.sdr b/code/def_files/data/effects/deferred-f.sdr index 3953b00440d..75667b0b61c 100644 --- a/code/def_files/data/effects/deferred-f.sdr +++ b/code/def_files/data/effects/deferred-f.sdr @@ -9,6 +9,7 @@ uniform sampler2D ColorBuffer; uniform sampler2D NormalBuffer; uniform sampler2D PositionBuffer; uniform sampler2D SpecBuffer; +uniform sampler2D BentBuffer; uniform sampler2DArray shadow_map; layout (std140) uniform globalDeferredData { @@ -168,7 +169,8 @@ 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 positionBufferData = texture(PositionBuffer, screenPos); + vec3 position = positionBufferData.xyz; if(abs(dot(position, position)) < nearPlane * nearPlane) discard; @@ -178,11 +180,15 @@ void main() 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); + + vec4 bentNormalBufferData = texture(BentBuffer, screenPos); + vec3 bentNormal = normalize(bentNormalBufferData.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); + float ambientOcclusion = bentNormalBufferData.a; vec3 lightDir; float attenuation; @@ -204,7 +210,12 @@ void main() vec3 halfVec = normalize(lightDir + eyeDir); float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0); + + float NdotV = clamp(dot(normal, eyeDir), 0.0, 1.0); + float BdotL = clamp(dot(bentNormal, lightDir), 0.0, 1.0); + float occlusionShadow = GetVisibilityFromMaterialOcclusion(ambientOcclusion, gloss, NdotV, BdotL); + vec4 fragmentColor = vec4(1.0); - fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL).rgb * diffuseLightColor * attenuation * area_normalisation; + fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL ).rgb * diffuseLightColor * attenuation * area_normalisation * occlusionShadow ; fragOut0 = max(fragmentColor, vec4(0.0)); -} +} \ No newline at end of file diff --git a/code/def_files/data/effects/lighting.sdr b/code/def_files/data/effects/lighting.sdr index 969ff908422..2f19ee4d0fc 100644 --- a/code/def_files/data/effects/lighting.sdr +++ b/code/def_files/data/effects/lighting.sdr @@ -9,6 +9,33 @@ const float GLOW_MAP_INTENSITY = 1.5; const float GLOW_MAP_SRGB_MULTIPLIER = 3.0; const float PI = 3.14159f; +// https://www.activision.com/cdn/research/siggraph_2018_opt.pdf +float AdjustCosConeAngle ( float cosConeAngle , float gloss , float NdotV ) +{ + // The cone is an especially poor approximation to actual visibility for high gloss values . + // This is an ad hoc adjustment . + // Gloss above 0.67 is unaffected by the cone , i .e .\ we set to full cone angle . + //gloss = clamp( gloss * 1.5, 0.0, 1.0 ); // Optionally , omit this line . + float gloss2 = gloss * gloss ; + float gloss4 = gloss2 * gloss2 ; + float gloss8 = gloss4 * gloss4 ; + float oneMinusNdotV2 = ( 1 - NdotV ) * ( 1 - NdotV ); + float oneMinusNdotV4 = oneMinusNdotV2 * oneMinusNdotV2 ; + // We lerp towards full cone angle based on gloss and NdotV . + cosConeAngle = mix( 0, cosConeAngle , ( 1 - gloss8 ) * ( 1 - oneMinusNdotV4 ) ); + return cosConeAngle ; +} + + +float GetVisibilityFromMaterialOcclusion( float materialOcclusion, float gloss, float NdotV, float BdotL ) +{ + float vis = materialOcclusion; + float cosConeAngle = sqrt( 1 - vis ) ; + float adjustedCosConeAngle = AdjustCosConeAngle( cosConeAngle , gloss , NdotV ) ; + adjustedCosConeAngle = max( adjustedCosConeAngle , 0.001 ); + vis = clamp( BdotL / adjustedCosConeAngle, 0.0, 1.0 ); + return vis ; // * vis +} vec3 FresnelSchlick(vec3 halfVec, vec3 view, vec3 specColor) { @@ -69,9 +96,9 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha vec3 computeLighting(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float roughness, float fresnelFactor, float dotNL) { #ifdef FLAG_LIGHT_MODEL_BLINN_PHONG - return SpecularBlinnPhong(specColor, light, normal, halfVec, 32, fresnelFactor, dotNL); + return SpecularBlinnPhong(specColor, light, normal, halfVec, 32, fresnelFactor, dotNL ); #else - return ComputeGGX(specColor, diffColor, light, normal, halfVec, view, roughness, fresnelFactor, dotNL); + return ComputeGGX(specColor, diffColor, light, normal, halfVec, view, roughness, fresnelFactor, dotNL ); #endif } diff --git a/code/def_files/data/effects/main-f.sdr b/code/def_files/data/effects/main-f.sdr index 26a769eab78..81c5d28573a 100644 --- a/code/def_files/data/effects/main-f.sdr +++ b/code/def_files/data/effects/main-f.sdr @@ -92,8 +92,8 @@ layout (std140) uniform modelData { int sMiscmapIndex; float alphaMult; - int flags; + int sBentmapIndex; }; in VertexOutput { @@ -140,6 +140,9 @@ uniform sampler2D sFramebuffer; #prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_MISC uniform sampler2DArray sMiscmap; #prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_MISC +#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_BENT +uniform sampler2DArray sBentmap; +#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_BENT #prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS uniform sampler2DArray shadow_map; #prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS @@ -151,6 +154,7 @@ out vec4 fragOut1; out vec4 fragOut2; out vec4 fragOut3; out vec4 fragOut4; +out vec4 fragOut5; #endif vec3 FresnelLazarovEnv(vec3 specColor, vec3 view, vec3 normal, float gloss) @@ -184,10 +188,10 @@ void GetLightInfo(int i, out vec3 lightDir, out float attenuation) attenuation = 1.0 / (1.0 + lights[i].attenuation * dist); } } -vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial, float gloss, float fresnel, float shadow, float aoFactor) +vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial, float gloss, float fresnel, float shadow, vec2 aoFactor, vec3 bentNormal) { vec3 eyeDir = vec3(normalize(-vertIn.position).xyz); - vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactor; // ambientFactor^2 due to legacy OpenGL compatibility behavior + vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactor.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior vec3 lightDiffuse = vec3(0.0, 0.0, 0.0); vec3 lightSpecular = vec3(0.0, 0.0, 0.0); #pragma optionNV unroll all @@ -203,13 +207,34 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial, GetLightInfo(i, lightDir, attenuation); vec3 halfVec = normalize(lightDir + eyeDir); float NdotL = clamp(dot(normal, lightDir), 0.0f, 1.0f); + float BdotL = clamp(dot(bentNormal, lightDir), 0.0f, 1.0f); + float NdotV = clamp(dot(normal, eyeDir), 0.0f, 1.0f); + float occlusionShadow = GetVisibilityFromMaterialOcclusion(aoFactor.y, gloss, NdotV, BdotL); // Ambient, Diffuse, and Specular - lightDiffuse += (lights[i].diffuse_color.rgb * diffuseFactor * NdotL * attenuation) * shadow; - lightSpecular += lights[i].diffuse_color.rgb * computeLighting(specularMaterial, diffuseMaterial, lightDir, normal, halfVec, eyeDir, roughness, fresnel, NdotL) * attenuation * shadow; + lightSpecular += lights[i].diffuse_color.rgb * computeLighting(specularMaterial, diffuseMaterial, lightDir, normal, halfVec, eyeDir, roughness, fresnel, NdotL) * attenuation * shadow * occlusionShadow ; } return diffuseMaterial * lightAmbient + lightSpecular; } +// Normal map - convert from DXT5nm +vec3 unpackNormalMap(vec3 unitNormal, sampler2DArray sampler, int index, vec2 texCoord) +{ + vec2 normalSample; + vec3 result = vec3(1.0); + + result.rg = normalSample = (texture(sampler, vec3(texCoord, float(index))).ag * 2.0) - 1.0; + result.b = clamp(sqrt(1.0 - dot(result.rg, result.rg)), 0.0001, 1.0); + result = vertIn.tangentMatrix * result; + float normLen = length(result); + // prevent breaking of normal maps + if (normLen > 0.0) + result /= normLen; + else + result = unitNormal; + + return result; +} + void main() { #ifdef MODEL_SDR_FLAG_SHADOW_MAP @@ -231,6 +256,7 @@ void main() vec2 aoFactors = vec2(1.0, 1.0); vec3 unitNormal = normalize(vertIn.normal); vec3 normal = unitNormal; + vec3 bentNormal = unitNormal; #prereplace IF_FLAG MODEL_SDR_FLAG_AMBIENT // red channel is ambient occlusion factor which only affects ambient lighting. @@ -240,16 +266,7 @@ void main() #prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL // Normal map - convert from DXT5nm - vec2 normalSample; - normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0; - normal.b = clamp(sqrt(1.0 - dot(normal.rg, normal.rg)), 0.0001, 1.0); - normal = vertIn.tangentMatrix * normal; - float norm = length(normal); - // prevent breaking of normal maps - if (norm > 0.0) - normal /= norm; - else - normal = unitNormal; + normal = unpackNormalMap(unitNormal, sNormalmap, sNormalmapIndex, texCoord); #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL vec2 distort = vec2(0.0, 0.0); @@ -307,9 +324,6 @@ void main() #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC - baseColor.rgb *= aoFactors.y; - specColor.rgb *= aoFactors.y; - vec4 teamMask = vec4(0.0); vec3 team_color_glow = vec3(0.0); @@ -341,6 +355,11 @@ void main() #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TEAMCOLOR #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC + #prereplace IF_FLAG MODEL_SDR_FLAG_BENT + // Bent Normal map + bentNormal = unpackNormalMap(unitNormal, sBentmap, sBentmapIndex, texCoord); + #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_BENT + // 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 @@ -360,7 +379,7 @@ void main() #prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowPos.z, vertIn.shadowUV, fardist, middist, neardist, veryneardist); #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS - baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x); + baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors, bentNormal); #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; @@ -408,9 +427,15 @@ void main() float g1vNL = GeometrySchlickGGX(NdotL, k); vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL; + vec3 irr_normal_dir = vec3(envMatrix * vec4(normal,0.0)); + #prereplace IF_FLAG MODEL_SDR_FLAG_BENT + specEnvLighting *= mix(max(dot(light_dir, bentNormal), 0), 1.0, aoFactors.x); + irr_normal_dir = vec3(envMatrix * vec4(bentNormal, 0.0)); + #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_BENT + 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 diffEnvColor = srgb_to_linear(texture(sIrrmap, irr_normal_dir).rgb); vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x; emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a; #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT @@ -489,7 +514,8 @@ void main() fragOut1 = vec4(vertIn.position.xyz, 1.0); fragOut2 = vec4(normal, glossData); fragOut3 = vec4(specColor.rgb, fresnelFactor); - fragOut4 = emissiveColor; + fragOut4 = vec4(bentNormal, aoFactors.y); + fragOut5 = emissiveColor; #prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED #endif diff --git a/code/def_files/data/effects/main-g.sdr b/code/def_files/data/effects/main-g.sdr index b869ea5f46d..bf2b176300d 100644 --- a/code/def_files/data/effects/main-g.sdr +++ b/code/def_files/data/effects/main-g.sdr @@ -100,6 +100,7 @@ layout (std140) uniform modelData { float alphaMult; int flags; + int sBentmapIndex; }; in VertexOutput { diff --git a/code/def_files/data/effects/main-v.sdr b/code/def_files/data/effects/main-v.sdr index eaa3185d25c..e796e9e8908 100644 --- a/code/def_files/data/effects/main-v.sdr +++ b/code/def_files/data/effects/main-v.sdr @@ -95,6 +95,7 @@ layout (std140) uniform modelData { float alphaMult; int flags; + int sBentmapIndex; }; #prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM diff --git a/code/def_files/data/effects/model_shader_flags.h b/code/def_files/data/effects/model_shader_flags.h index 51a08ee9f52..27f7dc39703 100644 --- a/code/def_files/data/effects/model_shader_flags.h +++ b/code/def_files/data/effects/model_shader_flags.h @@ -24,12 +24,13 @@ 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_BENT , (1 << 16), 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 << 17), true) +SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 18), true) #endif \ No newline at end of file diff --git a/code/def_files/data/effects/msaa-f.sdr b/code/def_files/data/effects/msaa-f.sdr index b4565968be4..6b0cb97669f 100644 --- a/code/def_files/data/effects/msaa-f.sdr +++ b/code/def_files/data/effects/msaa-f.sdr @@ -5,11 +5,13 @@ out vec4 fragOut2; out vec4 fragOut3; out vec4 fragOut4; out vec4 fragOut5; +out vec4 fragOut6; uniform sampler2DMS texColor; uniform sampler2DMS texPos; uniform sampler2DMS texNormal; uniform sampler2DMS texSpecular; +uniform sampler2DMS texBent; uniform sampler2DMS texEmissive; uniform sampler2DMS texDepth; @@ -167,6 +169,7 @@ void main() vec4 color = vec4(0); vec4 pos = vec4(0); vec4 normal = vec4(0); + vec4 bent = vec4(0); vec4 specular = vec4(0); vec4 emissive = vec4(0); float depth = 0; @@ -183,6 +186,7 @@ void main() pos += localPos * localWeight; color += texelFetch(texColor, texel, i) * localWeight; normal += texelFetch(texNormal, texel, i) * localWeight; + bent += texelFetch(texBent, texel, i) * localWeight; specular += texelFetch(texSpecular, texel, i) * localWeight; emissive += texelFetch(texEmissive, texel, i) * localWeight; depth += texelFetch(texDepth, texel, i).x * localWeight; @@ -193,6 +197,7 @@ void main() fragOut1 = pos / weight; fragOut2 = vec4(normalize(normal.xyz), normal.a / weight); fragOut3 = specular / weight; - fragOut4 = emissive / weight; + fragOut4 = vec4(normalize(bent.xyz), bent.a / weight); + fragOut5 = emissive / weight; gl_FragDepth = depth / weight; } diff --git a/code/graphics/material.cpp b/code/graphics/material.cpp index 6c6ab8ae6d6..b379a38856f 100644 --- a/code/graphics/material.cpp +++ b/code/graphics/material.cpp @@ -248,6 +248,7 @@ Depth_bias(0) Texture_maps[TM_MISC_TYPE] = -1; Texture_maps[TM_SPEC_GLOSS_TYPE] = -1; Texture_maps[TM_AMBIENT_TYPE] = -1; + Texture_maps[TM_BENT_NORMAL_TYPE] = -1; Clip_params.enabled = false; @@ -298,7 +299,8 @@ bool material::is_textured() const Texture_maps[TM_NORMAL_TYPE] > -1 || Texture_maps[TM_HEIGHT_TYPE] > -1 || Texture_maps[TM_AMBIENT_TYPE] > -1 || - Texture_maps[TM_MISC_TYPE] > -1; + Texture_maps[TM_MISC_TYPE] > -1 || + Texture_maps[TM_BENT_NORMAL_TYPE] > -1; } void material::set_texture_type(texture_type t_type) @@ -784,6 +786,8 @@ int model_material::get_shader_runtime_flags() const { flags |= MODEL_SDR_FLAG_MISC; if (get_texture_map(TM_MISC_TYPE) > 0 && is_team_color_set()) flags |= MODEL_SDR_FLAG_TEAMCOLOR; + if (get_texture_map(TM_BENT_NORMAL_TYPE) > 0) + flags |= MODEL_SDR_FLAG_BENT; if (is_fogged()) flags |= MODEL_SDR_FLAG_FOG; if (is_shadow_receiving()) diff --git a/code/graphics/opengl/gropengldeferred.cpp b/code/graphics/opengl/gropengldeferred.cpp index a83136af5d7..f9e7c50ba71 100644 --- a/code/graphics/opengl/gropengldeferred.cpp +++ b/code/graphics/opengl/gropengldeferred.cpp @@ -68,12 +68,12 @@ void gr_opengl_deferred_lighting_begin(bool clearNonColorBufs) Deferred_lighting = true; GL_state.ColorMask(true, true, true, true); - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 }; + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5, GL_COLOR_ATTACHMENT6 }; if (Cmdline_msaa_enabled > 0) { //Ensure MSAA Mode if necessary GL_state.BindFrameBuffer(Scene_framebuffer_ms); - glDrawBuffer(GL_COLOR_ATTACHMENT4); + glDrawBuffer(GL_COLOR_ATTACHMENT5); opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_COPY, 0)); GL_state.Texture.Enable(0, GL_TEXTURE_2D, Scene_color_texture); @@ -84,19 +84,20 @@ void gr_opengl_deferred_lighting_begin(bool clearNonColorBufs) } else { // Copy the existing color data into the emissive part of the G-buffer since everything that already existed is // treated as emissive - glDrawBuffer(GL_COLOR_ATTACHMENT4); + glDrawBuffer(GL_COLOR_ATTACHMENT5); glReadBuffer(GL_COLOR_ATTACHMENT0); glBlitFramebuffer(0, 0, gr_screen.max_w, gr_screen.max_h, 0, 0, gr_screen.max_w, gr_screen.max_h, GL_COLOR_BUFFER_BIT, GL_NEAREST); } - glDrawBuffers(6, buffers); + glDrawBuffers(7, buffers); glClearBufferfv(GL_COLOR, 0, black); if (clearNonColorBufs) { glClearBufferfv(GL_COLOR, 1, black); glClearBufferfv(GL_COLOR, 2, black); glClearBufferfv(GL_COLOR, 3, black); - glClearBufferfv(GL_COLOR, 5, black); + glClearBufferfv(GL_COLOR, 4, black); + glClearBufferfv(GL_COLOR, 6, black); } } @@ -115,8 +116,9 @@ void gr_opengl_deferred_lighting_msaa() GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, - GL_COLOR_ATTACHMENT4}; - glDrawBuffers(5, buffers); + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5,}; + glDrawBuffers(6, buffers); int msaa_resolve_flags = 0; switch (Cmdline_msaa_enabled) { @@ -139,14 +141,16 @@ void gr_opengl_deferred_lighting_msaa() GL_state.Texture.Enable(1, GL_TEXTURE_2D_MULTISAMPLE, Scene_position_texture_ms); GL_state.Texture.Enable(2, GL_TEXTURE_2D_MULTISAMPLE, Scene_normal_texture_ms); GL_state.Texture.Enable(3, GL_TEXTURE_2D_MULTISAMPLE, Scene_specular_texture_ms); - GL_state.Texture.Enable(4, GL_TEXTURE_2D_MULTISAMPLE, Scene_emissive_texture_ms); - GL_state.Texture.Enable(5, GL_TEXTURE_2D_MULTISAMPLE, Scene_depth_texture_ms); + GL_state.Texture.Enable(4, GL_TEXTURE_2D_MULTISAMPLE, Scene_bent_texture_ms); + GL_state.Texture.Enable(5, GL_TEXTURE_2D_MULTISAMPLE, Scene_emissive_texture_ms); + GL_state.Texture.Enable(6, GL_TEXTURE_2D_MULTISAMPLE, Scene_depth_texture_ms); Current_shader->program->Uniforms.setTextureUniform("texColor", 0); Current_shader->program->Uniforms.setTextureUniform("texPos", 1); Current_shader->program->Uniforms.setTextureUniform("texNormal", 2); Current_shader->program->Uniforms.setTextureUniform("texSpecular", 3); - Current_shader->program->Uniforms.setTextureUniform("texEmissive", 4); - Current_shader->program->Uniforms.setTextureUniform("texDepth", 5); + Current_shader->program->Uniforms.setTextureUniform("texBent", 4); + Current_shader->program->Uniforms.setTextureUniform("texEmissive", 5); + Current_shader->program->Uniforms.setTextureUniform("texDepth", 6); opengl_set_generic_uniform_data( [&](graphics::generic_data::msaa_data* data) { data->samples = Cmdline_msaa_enabled; @@ -226,8 +230,8 @@ void gr_opengl_deferred_lighting_finish() opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_DEFERRED_LIGHTING, 0)); // Render on top of the composite buffer texture - glDrawBuffer(GL_COLOR_ATTACHMENT5); - glReadBuffer(GL_COLOR_ATTACHMENT4); + glDrawBuffer(GL_COLOR_ATTACHMENT6); + glReadBuffer(GL_COLOR_ATTACHMENT5); glBlitFramebuffer(0, 0, gr_screen.max_w, @@ -243,8 +247,9 @@ void gr_opengl_deferred_lighting_finish() GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_normal_texture); GL_state.Texture.Enable(2, GL_TEXTURE_2D, Scene_position_texture); GL_state.Texture.Enable(3, GL_TEXTURE_2D, Scene_specular_texture); + GL_state.Texture.Enable(4, GL_TEXTURE_2D, Scene_bent_texture); if (Shadow_quality != ShadowQuality::Disabled) { - GL_state.Texture.Enable(4, GL_TEXTURE_2D_ARRAY, Shadow_map_texture); + GL_state.Texture.Enable(5, GL_TEXTURE_2D_ARRAY, Shadow_map_texture); } // We need to use stable sorting here to make sure that the relative ordering of the same light types is the same as @@ -606,7 +611,7 @@ void gr_opengl_deferred_lighting_finish() else { // Transfer the resolved lighting back to the color texture // TODO: Maybe this could be improved so that it doesn't require the copy back operation? - glReadBuffer(GL_COLOR_ATTACHMENT5); + glReadBuffer(GL_COLOR_ATTACHMENT6); glBlitFramebuffer(0, 0, gr_screen.max_w, diff --git a/code/graphics/opengl/gropengldraw.cpp b/code/graphics/opengl/gropengldraw.cpp index 34183963b35..f9ae1384675 100644 --- a/code/graphics/opengl/gropengldraw.cpp +++ b/code/graphics/opengl/gropengldraw.cpp @@ -35,11 +35,13 @@ GLuint Scene_ldr_texture; GLuint Scene_color_texture; GLuint Scene_position_texture; GLuint Scene_normal_texture; +GLuint Scene_bent_texture; GLuint Scene_specular_texture; GLuint Scene_emissive_texture; GLuint Scene_color_texture_ms; GLuint Scene_position_texture_ms; GLuint Scene_normal_texture_ms; +GLuint Scene_bent_texture_ms; GLuint Scene_specular_texture_ms; GLuint Scene_emissive_texture_ms; GLuint Scene_composite_texture; @@ -215,6 +217,25 @@ void opengl_setup_scene_textures() glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, Scene_specular_texture, 0); + // setup bent render texture + glGenTextures(1, &Scene_bent_texture); + + GL_state.Texture.SetActiveUnit(0); + GL_state.Texture.SetTarget(GL_TEXTURE_2D); + GL_state.Texture.Enable(Scene_bent_texture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glGenerateMipmap(GL_TEXTURE_2D); + opengl_set_object_label(GL_TEXTURE, Scene_bent_texture, "Scene Bent texture"); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, Scene_bent_texture, 0); + // setup emissive render texture glGenTextures(1, &Scene_emissive_texture); @@ -228,11 +249,20 @@ void opengl_setup_scene_textures() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA16F, + Scene_texture_width, + Scene_texture_height, + 0, + GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, + NULL); glGenerateMipmap(GL_TEXTURE_2D); opengl_set_object_label(GL_TEXTURE, Scene_emissive_texture, "Scene Emissive texture"); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, Scene_emissive_texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, Scene_emissive_texture, 0); + // setup compositing render texture glGenTextures(1, &Scene_composite_texture); @@ -250,7 +280,7 @@ void opengl_setup_scene_textures() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); opengl_set_object_label(GL_TEXTURE, Scene_composite_texture, "Scene Composite texture"); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, Scene_composite_texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT6, GL_TEXTURE_2D, Scene_composite_texture, 0); //Set up luminance texture (used as input for FXAA) // also used as a light accumulation buffer during the deferred pass @@ -333,6 +363,9 @@ void opengl_setup_scene_textures() glDeleteTextures(1, &Scene_specular_texture); Scene_specular_texture = 0; + glDeleteTextures(1, &Scene_bent_texture); + Scene_bent_texture = 0; + glDeleteTextures(1, &Scene_emissive_texture); Scene_emissive_texture = 0; @@ -440,7 +473,6 @@ void opengl_setup_scene_textures() GL_TEXTURE_2D_MULTISAMPLE, Scene_normal_texture_ms, 0); - // setup specular render texture glGenTextures(1, &Scene_specular_texture_ms); @@ -462,6 +494,28 @@ void opengl_setup_scene_textures() Scene_specular_texture_ms, 0); + // setup bent render texture + glGenTextures(1, &Scene_bent_texture_ms); + + GL_state.Texture.SetActiveUnit(0); + GL_state.Texture.SetTarget(GL_TEXTURE_2D_MULTISAMPLE); + GL_state.Texture.Enable(Scene_bent_texture_ms); + + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, + Cmdline_msaa_enabled, + GL_RGBA16F, + Scene_texture_width, + Scene_texture_height, + GL_TRUE); + opengl_set_object_label(GL_TEXTURE, Scene_bent_texture_ms, "Scene Bent normal texture multisampling"); + + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT4, + GL_TEXTURE_2D_MULTISAMPLE, + Scene_bent_texture_ms, + 0); + + // setup emissive render texture glGenTextures(1, &Scene_emissive_texture_ms); @@ -477,7 +531,7 @@ void opengl_setup_scene_textures() GL_TRUE); opengl_set_object_label(GL_TEXTURE, Scene_emissive_texture_ms, "Scene Emissive texture multisample"); glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D_MULTISAMPLE, Scene_emissive_texture_ms, 0); @@ -639,6 +693,11 @@ void opengl_scene_texture_shutdown() Scene_specular_texture = 0; } + if (Scene_bent_texture) { + glDeleteTextures(1, &Scene_bent_texture); + Scene_bent_texture = 0; + } + if (Scene_emissive_texture) { glDeleteTextures(1, &Scene_emissive_texture); Scene_emissive_texture = 0; @@ -701,7 +760,7 @@ void gr_opengl_scene_texture_begin() glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 }; + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5, GL_COLOR_ATTACHMENT6 }; glDrawBuffers(6, buffers); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); @@ -806,7 +865,7 @@ void gr_opengl_copy_effect_texture() //Make sure we're reading from the up-to-date color texture glReadBuffer(GL_COLOR_ATTACHMENT0); - glDrawBuffer(GL_COLOR_ATTACHMENT5); + glDrawBuffer(GL_COLOR_ATTACHMENT6); glBlitFramebuffer(0, 0, gr_screen.max_w, gr_screen.max_h, 0, 0, gr_screen.max_w, gr_screen.max_h, GL_COLOR_BUFFER_BIT, GL_NEAREST); glDrawBuffer(GL_COLOR_ATTACHMENT0); } @@ -1163,8 +1222,9 @@ void gr_opengl_start_decal_pass() { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, }; - glDrawBuffers(3, buffers); + glDrawBuffers(4, buffers); } void gr_opengl_stop_decal_pass() { GLenum buffers2[] = { @@ -1174,8 +1234,9 @@ void gr_opengl_stop_decal_pass() { GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, }; - glDrawBuffers(6, buffers2); + glDrawBuffers(7, buffers2); } void gr_opengl_calculate_irrmap() diff --git a/code/graphics/opengl/gropengldraw.h b/code/graphics/opengl/gropengldraw.h index 17634cd7a37..50b5d13aa4f 100644 --- a/code/graphics/opengl/gropengldraw.h +++ b/code/graphics/opengl/gropengldraw.h @@ -23,11 +23,13 @@ extern GLuint Scene_ldr_texture; extern GLuint Scene_color_texture; extern GLuint Scene_position_texture; extern GLuint Scene_normal_texture; +extern GLuint Scene_bent_texture; extern GLuint Scene_specular_texture; extern GLuint Scene_emissive_texture; extern GLuint Scene_color_texture_ms; extern GLuint Scene_position_texture_ms; extern GLuint Scene_normal_texture_ms; +extern GLuint Scene_bent_texture_ms; extern GLuint Scene_specular_texture_ms; extern GLuint Scene_emissive_texture_ms; extern GLuint Scene_luminance_texture; diff --git a/code/graphics/opengl/gropenglshader.cpp b/code/graphics/opengl/gropenglshader.cpp index 85d6a3a366f..8357b3c5365 100644 --- a/code/graphics/opengl/gropenglshader.cpp +++ b/code/graphics/opengl/gropenglshader.cpp @@ -800,7 +800,8 @@ static void opengl_set_default_uniforms(const opengl_shader_t& sdr) { Current_shader->program->Uniforms.setTextureUniform("NormalBuffer", 1); Current_shader->program->Uniforms.setTextureUniform("PositionBuffer", 2); Current_shader->program->Uniforms.setTextureUniform("SpecBuffer", 3); - Current_shader->program->Uniforms.setTextureUniform("shadow_map", 4); + Current_shader->program->Uniforms.setTextureUniform("BentBuffer", 4); + Current_shader->program->Uniforms.setTextureUniform("shadow_map", 5); break; case SDR_TYPE_PASSTHROUGH_RENDER: @@ -875,6 +876,7 @@ void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_sha glBindFragDataLocation(program->getShaderHandle(), 2, "fragOut2"); glBindFragDataLocation(program->getShaderHandle(), 3, "fragOut3"); glBindFragDataLocation(program->getShaderHandle(), 4, "fragOut4"); + glBindFragDataLocation(program->getShaderHandle(), 5, "fragOut5"); if (do_shader_caching()) { // Enable shader caching diff --git a/code/graphics/opengl/gropengltnl.cpp b/code/graphics/opengl/gropengltnl.cpp index fe680cd189e..1320ab39d22 100644 --- a/code/graphics/opengl/gropengltnl.cpp +++ b/code/graphics/opengl/gropengltnl.cpp @@ -870,6 +870,8 @@ void opengl_tnl_set_model_material(model_material *material_info) Current_shader->program->Uniforms.setTextureUniform("sFramebuffer", 9); if (setAllUniforms || (flags & MODEL_SDR_FLAG_TRANSFORM)) Current_shader->program->Uniforms.setTextureUniform("transform_tex", 10); + if (setAllUniforms || (flags & MODEL_SDR_FLAG_BENT)) + Current_shader->program->Uniforms.setTextureUniform("sBentmap", 12); //No shader ever defines this, so don't push it. //Current_shader->program->Uniforms.setTextureUniform("sHeightmap", 5); @@ -953,6 +955,15 @@ void opengl_tnl_set_model_material(model_material *material_info) 7); } + if (material_info->get_texture_map(TM_BENT_NORMAL_TYPE) > 0) { + gr_opengl_tcache_set(material_info->get_texture_map(TM_BENT_NORMAL_TYPE), + TCACHE_TYPE_NORMAL, + &u_scale, + &v_scale, + &array_index, + 12); + } + if (material_info->is_shadow_receiving()) { GL_state.Texture.Enable(8, GL_TEXTURE_2D_ARRAY, Shadow_map_texture); } diff --git a/code/graphics/uniforms.cpp b/code/graphics/uniforms.cpp index fa7b27258c3..09ee3440afc 100644 --- a/code/graphics/uniforms.cpp +++ b/code/graphics/uniforms.cpp @@ -70,6 +70,7 @@ void convert_model_material(model_uniform_data* data_out, data_out->sMiscmapIndex = 0; data_out->sNormalmapIndex = 0; data_out->sSpecmapIndex = 0; + data_out->sBentmapIndex = 0; if (material.is_clipped()) { auto& clip_info = material.get_clip_plane(); @@ -174,6 +175,11 @@ void convert_model_material(model_uniform_data* data_out, data_out->sMiscmapIndex = bm_get_array_index(material.get_texture_map(TM_MISC_TYPE)); } + if (material.get_texture_map(TM_BENT_NORMAL_TYPE) > 0) { + data_out->sBentmapIndex = bm_get_array_index(material.get_texture_map(TM_BENT_NORMAL_TYPE)); + } + + if (material.is_shadow_receiving()) { data_out->shadow_mv_matrix = Shadow_view_matrix_light; diff --git a/code/graphics/util/uniform_structs.h b/code/graphics/util/uniform_structs.h index 4bf861d44ab..34ffeca56f4 100644 --- a/code/graphics/util/uniform_structs.h +++ b/code/graphics/util/uniform_structs.h @@ -139,7 +139,8 @@ struct model_uniform_data { int sMiscmapIndex; float alphaMult; int flags; - int pad[1]; + int sBentmapIndex; + int pad; }; const size_t model_uniform_data_size = sizeof(model_uniform_data); diff --git a/code/lab/dialogs/lab_ui.cpp b/code/lab/dialogs/lab_ui.cpp index 1860418118f..9b61c2c6a2e 100644 --- a/code/lab/dialogs/lab_ui.cpp +++ b/code/lab/dialogs/lab_ui.cpp @@ -363,6 +363,7 @@ void LabUi::show_render_options() Checkbox("Height map", &height_map); Checkbox("Misc map", &misc_map); Checkbox("AO map", &ao_map); + Checkbox("Bent normals map", &bent_map); build_texture_quality_combobox(); @@ -473,6 +474,7 @@ void LabUi::show_render_options() getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoGlowMap, !glow_map); getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoSpecularMap, !spec_map); getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoReflectMap, !reflect_map); + getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoBentMap, !bent_map); getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoEnvMap, !env_map); getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoNormalMap, !normal_map); getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoHeightMap, !height_map); diff --git a/code/lab/dialogs/lab_ui.h b/code/lab/dialogs/lab_ui.h index dfccf388d16..391f8140512 100644 --- a/code/lab/dialogs/lab_ui.h +++ b/code/lab/dialogs/lab_ui.h @@ -88,6 +88,7 @@ class LabUi { bool height_map = true; bool misc_map = true; bool ao_map = true; + bool bent_map = true; bool no_glowpoints = false; bool use_wireframe_rendering = false; bool no_lighting = false; diff --git a/code/lab/renderer/lab_renderer.cpp b/code/lab/renderer/lab_renderer.cpp index 0058f1405bb..f3909067b3b 100644 --- a/code/lab/renderer/lab_renderer.cpp +++ b/code/lab/renderer/lab_renderer.cpp @@ -96,6 +96,8 @@ void LabRenderer::renderModel(float frametime) { Ships[obj->instance].flags.set(Ship::Ship_Flags::Render_without_weapons, !renderFlags[LabRenderFlag::ShowWeapons]); Ships[obj->instance].flags.set(Ship::Ship_Flags::Render_without_ambientmap, renderFlags[LabRenderFlag::NoAOMap]); Ships[obj->instance].flags.set(Ship::Ship_Flags::No_insignias, !renderFlags[LabRenderFlag::ShowInsignia]); + Ships[obj->instance].flags.set(Ship::Ship_Flags::Render_without_bentmap, renderFlags[LabRenderFlag::NoBentMap]); + Ships[obj->instance].team_name = currentTeamColor; diff --git a/code/lab/renderer/lab_renderer.h b/code/lab/renderer/lab_renderer.h index 032f73cbb7e..59be724b5e9 100644 --- a/code/lab/renderer/lab_renderer.h +++ b/code/lab/renderer/lab_renderer.h @@ -29,6 +29,7 @@ FLAG_LIST(LabRenderFlag) { NoMiscMap, NoGlowpoints, NoLighting, + NoBentMap, ShowWireframe, ShowFullDetail, ShowThrusters, diff --git a/code/model/model.h b/code/model/model.h index fcefbc4c3be..72fd102719f 100644 --- a/code/model/model.h +++ b/code/model/model.h @@ -149,7 +149,8 @@ struct submodel_instance #define TM_MISC_TYPE 5 // optional utility map #define TM_SPEC_GLOSS_TYPE 6 // optional reflectance map (specular and gloss) #define TM_AMBIENT_TYPE 7 // optional ambient occlusion map with ambient occlusion and cavity occlusion factors for red and green channels. -#define TM_NUM_TYPES 8 //WMC - Number of texture_info objects in texture_map +#define TM_BENT_NORMAL_TYPE 8 // optional normal map with normals pointing in least occluded direction +#define TM_NUM_TYPES 9 //WMC - Number of texture_info objects in texture_map //Used by scripting - if you change this, do a search //to update switch() statement in lua.cpp @@ -1063,6 +1064,7 @@ constexpr uint64_t MR_NO_INSIGNIA = 2147483648; // Disable the insignias for ... #define MR_DEBUG_NO_AMBIENT (1<<11) #define MR_DEBUG_NO_MISC (1<<12) #define MR_DEBUG_NO_REFLECT (1<<13) +#define MR_DEBUG_NO_BENT (1<<14) //Defines for the render parameter of model_render, model_really_render and model_render_buffers #define MODEL_RENDER_OPAQUE 1 diff --git a/code/model/modelread.cpp b/code/model/modelread.cpp index d96bd05ede3..f6423aa33f1 100644 --- a/code/model/modelread.cpp +++ b/code/model/modelread.cpp @@ -3255,6 +3255,15 @@ void model_load_texture(polymodel *pm, int i, const char *file) tmisc->LoadTexture(tmp_name, pm->filename); + // bent normals + texture_info* tbent = &tmap->textures[TM_BENT_NORMAL_TYPE]; + + strcpy_s(tmp_name, file); + strcat_s(tmp_name, "-bent"); + strlwr(tmp_name); + + tbent->LoadTexture(tmp_name, pm->filename); + // ------------------------------------------------------------------------- // See if we need to compile a new shader for this material diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index 2b60a60b2b3..897a4dc4c45 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -771,6 +771,10 @@ bool model_draw_list::sort_draw_pair(const model_draw_list* target, const int a, return draw_call_a->render_material.get_texture_map(TM_MISC_TYPE) < draw_call_b->render_material.get_texture_map(TM_MISC_TYPE); } + if ( draw_call_a->render_material.get_texture_map(TM_BENT_NORMAL_TYPE) != draw_call_b->render_material.get_texture_map(TM_BENT_NORMAL_TYPE) ) { + return draw_call_a->render_material.get_texture_map(TM_BENT_NORMAL_TYPE) < draw_call_b->render_material.get_texture_map(TM_BENT_NORMAL_TYPE); + } + return draw_call_a->lights.index_start < draw_call_b->lights.index_start; } void model_draw_list::build_uniform_buffer() { @@ -1058,6 +1062,7 @@ void model_render_buffers(model_draw_list* scene, model_material *rendering_mate texture_maps[TM_MISC_TYPE] = -1; texture_maps[TM_SPEC_GLOSS_TYPE] = -1; texture_maps[TM_AMBIENT_TYPE] = -1; + texture_maps[TM_BENT_NORMAL_TYPE] = -1; if (forced_texture != -2) { texture_maps[TM_BASE_TYPE] = forced_texture; @@ -1125,6 +1130,7 @@ void model_render_buffers(model_draw_list* scene, model_material *rendering_mate auto height_map = &tmap->textures[TM_HEIGHT_TYPE]; auto ambient_map = &tmap->textures[TM_AMBIENT_TYPE]; auto misc_map = &tmap->textures[TM_MISC_TYPE]; + auto bent_map = &tmap->textures[TM_BENT_NORMAL_TYPE]; if (replacement_textures != nullptr) { const auto& replacement_textures_deref = *replacement_textures; @@ -1147,6 +1153,11 @@ void model_render_buffers(model_draw_list* scene, model_material *rendering_mate tex_replace[TM_MISC_TYPE] = texture_info(replacement_textures_deref[rt_begin_index + TM_MISC_TYPE]); misc_map = &tex_replace[TM_MISC_TYPE]; } + + if (replacement_textures_deref[rt_begin_index + TM_BENT_NORMAL_TYPE] >= 0) { + tex_replace[TM_MISC_TYPE] = texture_info(replacement_textures_deref[rt_begin_index + TM_BENT_NORMAL_TYPE]); + bent_map = &tex_replace[TM_BENT_NORMAL_TYPE]; + } } if (debug_flags & MR_DEBUG_NO_DIFFUSE) texture_maps[TM_BASE_TYPE] = -1; @@ -1157,6 +1168,7 @@ void model_render_buffers(model_draw_list* scene, model_material *rendering_mate if (!(debug_flags & MR_DEBUG_NO_NORMAL) && Detail.lighting > 0) texture_maps[TM_NORMAL_TYPE] = model_interp_get_texture(norm_map, elapsed_time); if (!(debug_flags & MR_DEBUG_NO_AMBIENT) && Detail.lighting > 0) texture_maps[TM_AMBIENT_TYPE] = model_interp_get_texture(ambient_map, elapsed_time); if (!(debug_flags & MR_DEBUG_NO_HEIGHT) && Detail.lighting > 1) texture_maps[TM_HEIGHT_TYPE] = model_interp_get_texture(height_map, elapsed_time); + if (!(debug_flags & MR_DEBUG_NO_BENT) && Detail.lighting > 0) texture_maps[TM_BENT_NORMAL_TYPE] = model_interp_get_texture(bent_map, elapsed_time); } } else { alpha = forced_alpha; @@ -1239,6 +1251,7 @@ void model_render_buffers(model_draw_list* scene, model_material *rendering_mate rendering_material->set_texture_map(TM_HEIGHT_TYPE, texture_maps[TM_HEIGHT_TYPE]); rendering_material->set_texture_map(TM_AMBIENT_TYPE, texture_maps[TM_AMBIENT_TYPE]); rendering_material->set_texture_map(TM_MISC_TYPE, texture_maps[TM_MISC_TYPE]); + rendering_material->set_texture_map(TM_BENT_NORMAL_TYPE, texture_maps[TM_BENT_NORMAL_TYPE]); } scene->add_buffer_draw(rendering_material, &pm->vert_source, buffer, i, tmap_flags); diff --git a/code/ship/ship.cpp b/code/ship/ship.cpp index d1914804c6e..c698ac2fb90 100644 --- a/code/ship/ship.cpp +++ b/code/ship/ship.cpp @@ -21045,6 +21045,10 @@ void ship_render(object* obj, model_draw_list* scene) debug_flags |= MR_DEBUG_NO_REFLECT; } + if (shipp->flags[Ship_Flags::Render_without_bentmap]) { + debug_flags |= MR_DEBUG_NO_BENT; + } + render_info.set_flags(render_flags); render_info.set_debug_flags(debug_flags); diff --git a/code/ship/ship_flags.h b/code/ship/ship_flags.h index e31121a567b..becd0194ab7 100644 --- a/code/ship/ship_flags.h +++ b/code/ship/ship_flags.h @@ -142,6 +142,7 @@ namespace Ship { Force_primary_unlinking, // plieblang - turned on when the ship is under good-primary-time No_scanned_cargo, //MjnMixael -- The cargo will never be revealed, instead always returning "Scanned" or "Not Scanned" No_insignias, // Cyborg do not render insignias, even when one is defined for them. + Render_without_bentmap, // render without using bent normals map NUM_VALUES