From 40c3fe3bd63a456341ac017efe28e51b72df0ead Mon Sep 17 00:00:00 2001 From: slipher Date: Mon, 2 Sep 2024 23:04:30 -0500 Subject: [PATCH 1/4] Don't omit light factor when using depth fade The overbright correction shouldn't be skipped here. Currently all depth fade assets also use vertex sprite so the USE_DEPTH_FADE variant of the depth fade code is never run, only the USE_VERTEX_SPRITE one. --- src/engine/renderer/glsl_source/generic_fp.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/renderer/glsl_source/generic_fp.glsl b/src/engine/renderer/glsl_source/generic_fp.glsl index e9f04ef1df..c923d6a35c 100644 --- a/src/engine/renderer/glsl_source/generic_fp.glsl +++ b/src/engine/renderer/glsl_source/generic_fp.glsl @@ -61,7 +61,7 @@ void main() color *= var_Color; -#if !defined(GENERIC_2D) && !defined(USE_DEPTH_FADE) +#if !defined(GENERIC_2D) color.rgb *= u_InverseLightFactor; #endif From 3ade40a1e8f0f2eb01b7e7934d6f311e19138d1c Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 4 Sep 2024 23:37:36 -0500 Subject: [PATCH 2/4] Tess_SurfacePolychain: don't skip tangents randomly I needed this to test depth fade with /testshader --- src/engine/renderer/tr_surface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/renderer/tr_surface.cpp b/src/engine/renderer/tr_surface.cpp index f433aaf861..43868ac361 100644 --- a/src/engine/renderer/tr_surface.cpp +++ b/src/engine/renderer/tr_surface.cpp @@ -683,7 +683,7 @@ static void Tess_SurfacePolychain( srfPoly_t *p ) Tess_CheckOverflow( numVertexes, numIndexes ); - if (!tess.surfaceShader->interactLight || tess.skipTangents) + if ( tess.skipTangents ) { // fan triangles into the tess array From 0dad856f33b0a1dfa0f879d9b65366f852b8ab6a Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 6 Sep 2024 21:43:58 -0500 Subject: [PATCH 3/4] Do autosprite calcs with CPU, not GLSL Get rid of vertexSprite_vp.glsl/USE_VERTEX_SPRITE and return to doing deformvertexes autosprite/autosprite2 vertex calculations on the CPU (like it was until 2015). This fixes various bugs with autosprite[2] BSP surfaces. Also it fixes some particle systems which were broken for unknown reasons. One problem with the vertex sprite GLSL is that it always applied depth fade, regardless of whether it was requested. Depth fade means the alpha will be reduced if there is something close behind the particle within a certain depth (judging by the z buffer). With autosprite1, this depth parameter was set equal to the size of the sprite. So it is like a cube-shaped cloud (which matters when part of the cloud is inside a wall). The shader-specified fade depth, if any, was ignored. With autosprite2, the shader used a negative depth parameter, which just breaks everything. By removing unwanted depth fade for BSP surfaces, this fixes #997 (non-opaque autosprite2 BSP surfaces do not show up, as seen with the various flames on KOsAD's metro map). Also depth fade will no longer be automatically applied to all particles. I believe we have just 3 Unvanquished shaders configured with depth fade: acid tube acid, booster effect, and grenade smoke. Any other particles could potentially look different due to removing depth fade. So we may need some asset changes to adjust to this change. Another issue is that USE_VERTEX_SPRITE was not available for lightmap shaders. This meant that vertex positions were out of sync between the generic and lightmap shaders, and the lightmap shader failed to render anything. So this commit fixes #1246 (wrong lighting for autosprite[2] BSP surfaces with lightmaps, as seen on map "defenxe") by calculating the final vertex positions before uploading them, which ensures they are the same for all GLSL shaders used. With this commit, some particles that were previously not visible are now rendered, for example: - ones with the gfx/players/alien_base/green_acid shader which are emitted upon evolving, or damaging or destroying an alien buildable - orange glowing "mark" (which is actually a particle) added at impact point of several weapons (rifle, shotgun...) I believe the problem must have been that Tess_AddSprite oriented the triangles backward (CW instead of CCW or vice versa). And unlike most particle shaders, the acid one fails to specify double-sided culling, so it would disappear if oriented backward. To implement CPU-side autosprite/autosprite2 transformations, I took the code from an old (~2015) version of the file. But I ended up completely writing the autosprite2 one. When autosprites were first implemented in GLSL, there was also a change in how the polygon is positioned: in the GLSL implementation it faces towards the viewer, rather than Tremulous' behavior to face opposite the view direction. I decided that the GLSL behavior is superior for autosprite2 and reimplemented the CPU version that way (but you can get the old behavior by setting the r_autosprite2Style cvar). For autosprite the old behavior seems good enough so it once again faces opposing the view direction. This commit makes autosprite2 surfaces work with material system enabled for the first time, by virtue of rendering them without using the material system. --- src.cmake | 1 - src/engine/renderer/Material.cpp | 47 ++- src/engine/renderer/Material.h | 3 +- src/engine/renderer/gl_shader.cpp | 52 +-- src/engine/renderer/gl_shader.h | 46 +-- .../renderer/glsl_source/generic_fp.glsl | 4 +- .../renderer/glsl_source/generic_vp.glsl | 10 +- .../renderer/glsl_source/heatHaze_vp.glsl | 1 - .../renderer/glsl_source/lightMapping_vp.glsl | 1 - .../renderer/glsl_source/material_fp.glsl | 4 +- .../renderer/glsl_source/vertexSimple_vp.glsl | 2 +- .../renderer/glsl_source/vertexSprite_vp.glsl | 82 ----- src/engine/renderer/shaders.cpp | 2 - src/engine/renderer/tr_backend.cpp | 12 - src/engine/renderer/tr_bsp.cpp | 19 +- src/engine/renderer/tr_local.h | 15 +- src/engine/renderer/tr_main.cpp | 8 +- src/engine/renderer/tr_shade.cpp | 55 +-- src/engine/renderer/tr_shade_calc.cpp | 335 +++++++++--------- src/engine/renderer/tr_shader.cpp | 4 - src/engine/renderer/tr_surface.cpp | 56 +-- src/engine/renderer/tr_vbo.cpp | 11 +- 22 files changed, 258 insertions(+), 512 deletions(-) delete mode 100644 src/engine/renderer/glsl_source/vertexSprite_vp.glsl diff --git a/src.cmake b/src.cmake index 4662c5cb14..79bb2f04ba 100644 --- a/src.cmake +++ b/src.cmake @@ -157,7 +157,6 @@ set(GLSLSOURCELIST ${ENGINE_DIR}/renderer/glsl_source/vertexAnimation_vp.glsl ${ENGINE_DIR}/renderer/glsl_source/vertexSimple_vp.glsl ${ENGINE_DIR}/renderer/glsl_source/vertexSkinning_vp.glsl - ${ENGINE_DIR}/renderer/glsl_source/vertexSprite_vp.glsl ${ENGINE_DIR}/renderer/glsl_source/blurX_fp.glsl ${ENGINE_DIR}/renderer/glsl_source/blurX_vp.glsl ${ENGINE_DIR}/renderer/glsl_source/blurY_fp.glsl diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index 5d65f7dada..b067732ab6 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -247,12 +247,12 @@ void UpdateSurfaceDataGeneric3D( uint32_t* materials, Material& material, drawSu gl_genericShaderMaterial->SetUniform_ColorMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); } - bool needDepthMap = pStage->hasDepthFade || shader->autoSpriteMode; + bool needDepthMap = pStage->hasDepthFade; if ( needDepthMap ) { gl_genericShaderMaterial->SetUniform_DepthMapBindless( GL_BindToTMU( 1, tr.currentDepthImage ) ); } - bool hasDepthFade = pStage->hasDepthFade && !shader->autoSpriteMode; + bool hasDepthFade = pStage->hasDepthFade; if ( hasDepthFade ) { gl_genericShaderMaterial->SetUniform_DepthScale( pStage->depthFadeValue ); } @@ -959,7 +959,7 @@ void MaterialSystem::GenerateWorldCommandBuffer() { } shader = shader->remappedShader ? shader->remappedShader : shader; - if ( shader->isSky || shader->isPortal ) { + if ( shader->isSky || shader->isPortal || shader->autoSpriteMode ) { continue; } @@ -1067,13 +1067,12 @@ void BindShaderGeneric3D( Material* material ) { gl_genericShaderMaterial->SetTCGenEnvironment( material->tcGenEnvironment ); gl_genericShaderMaterial->SetTCGenLightmap( material->tcGen_Lightmap ); gl_genericShaderMaterial->SetDepthFade( material->hasDepthFade ); - gl_genericShaderMaterial->SetVertexSprite( material->vertexSprite ); // Bind shader program. gl_genericShaderMaterial->BindProgram( material->deformIndex ); // Set shader uniforms. - if ( material->tcGenEnvironment || material->vertexSprite ) { + if ( material->tcGenEnvironment ) { gl_genericShaderMaterial->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); gl_genericShaderMaterial->SetUniform_ViewUp( backEnd.orientation.axis[2] ); } @@ -1146,17 +1145,11 @@ void BindShaderScreen( Material* material ) { void BindShaderHeatHaze( Material* material ) { // Select shader permutation. gl_heatHazeShaderMaterial->SetVertexAnimation( material->vertexAnimation ); - gl_heatHazeShaderMaterial->SetVertexSprite( material->vertexSprite ); // Bind shader program. gl_heatHazeShaderMaterial->BindProgram( material->deformIndex ); // Set shader uniforms. - if ( material->vertexSprite ) { - gl_heatHazeShaderMaterial->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); - gl_heatHazeShaderMaterial->SetUniform_ViewUp( backEnd.orientation.axis[2] ); - } - gl_heatHazeShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_heatHazeShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); } @@ -1184,15 +1177,12 @@ void ProcessMaterialNOP( Material*, shaderStage_t*, drawSurf_t* ) { // ProcessMaterial*() are essentially same as BindShader*(), but only set the GL program id to the material, // without actually binding it -void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ) { - shader_t* shader = drawSurf->shader; - +void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, drawSurf_t* ) { material->shader = gl_genericShaderMaterial; material->vertexAnimation = false; material->tcGenEnvironment = pStage->tcGen_Environment; material->tcGen_Lightmap = pStage->tcGen_Lightmap; - material->vertexSprite = shader->autoSpriteMode != 0; material->deformIndex = pStage->deformIndex; gl_genericShaderMaterial->SetVertexAnimation( false ); @@ -1200,10 +1190,9 @@ void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, drawSu gl_genericShaderMaterial->SetTCGenEnvironment( pStage->tcGen_Environment ); gl_genericShaderMaterial->SetTCGenLightmap( pStage->tcGen_Lightmap ); - bool hasDepthFade = pStage->hasDepthFade && !shader->autoSpriteMode; + bool hasDepthFade = pStage->hasDepthFade; material->hasDepthFade = hasDepthFade; gl_genericShaderMaterial->SetDepthFade( hasDepthFade ); - gl_genericShaderMaterial->SetVertexSprite( shader->autoSpriteMode != 0 ); material->program = gl_genericShaderMaterial->GetProgram( pStage->deformIndex ); } @@ -1286,21 +1275,13 @@ void ProcessMaterialScreen( Material* material, shaderStage_t* pStage, drawSurf_ material->program = gl_screenShaderMaterial->GetProgram( pStage->deformIndex ); } -void ProcessMaterialHeatHaze( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ) { - shader_t* shader = drawSurf->shader; - +void ProcessMaterialHeatHaze( Material* material, shaderStage_t* pStage, drawSurf_t* ) { material->shader = gl_heatHazeShaderMaterial; material->vertexAnimation = false; material->deformIndex = pStage->deformIndex; gl_heatHazeShaderMaterial->SetVertexAnimation( false ); - if ( shader->autoSpriteMode ) { - gl_heatHazeShaderMaterial->SetVertexSprite( true ); - } else { - gl_heatHazeShaderMaterial->SetVertexSprite( false ); - } - material->program = gl_heatHazeShaderMaterial->GetProgram( pStage->deformIndex ); } @@ -1447,7 +1428,7 @@ void MaterialSystem::GenerateWorldMaterials() { } shader = shader->remappedShader ? shader->remappedShader : shader; - if ( shader->isSky || shader->isPortal ) { + if ( shader->isSky || shader->isPortal || shader->autoSpriteMode ) { continue; } @@ -1807,6 +1788,7 @@ void MaterialSystem::Free() { generatedWorldCommandBuffer = false; dynamicDrawSurfs.clear(); + autospriteSurfaces.clear(); portalSurfaces.clear(); portalSurfacesTmp.clear(); portalBounds.clear(); @@ -1948,6 +1930,17 @@ void MaterialSystem::AddPortalSurfaces() { portalSurfacesSSBO.AreaIncr(); } +// autosprite[2] is not implemented in material system, draw them old-fashionedly +void MaterialSystem::AddAutospriteSurfaces() { + tr.currentEntity = &tr.worldEntity; + + for ( const drawSurf_t &drawSurf : autospriteSurfaces ) + { + R_AddDrawSurf( drawSurf.surface, drawSurf.shader, + drawSurf.lightmapNum(), drawSurf.fogNum(), drawSurf.bspSurface ); + } +} + void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderSort_t toSort, const uint32_t viewID ) { if ( !r_drawworld->integer ) { return; diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h index fe398d9ee1..f154575440 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -98,7 +98,6 @@ struct Material { bool tcGenEnvironment; bool tcGen_Lightmap; bool hasDepthFade; - bool vertexSprite; bool alphaTest; bool bspSurface; @@ -217,6 +216,7 @@ class MaterialSystem { std::vector portalSurfacesTmp; std::vector portalSurfaces; + std::vector autospriteSurfaces; std::vector portalBounds; uint32_t totalPortals; std::vector skyShaders; @@ -250,6 +250,7 @@ class MaterialSystem { const GLuint count, const GLuint firstIndex ); void AddPortalSurfaces(); + void AddAutospriteSurfaces(); void RenderMaterials( const shaderSort_t fromSort, const shaderSort_t toSort, const uint32_t viewID ); void UpdateDynamicSurfaces(); diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 6fd4b05e67..0a84b98e26 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -1583,7 +1583,7 @@ bool GLCompileMacro_USE_REFLECTIVE_SPECULAR::HasConflictingMacros( size_t permut { for (const GLCompileMacro* macro : macros) { - if ( ( permutation & macro->GetBit() ) != 0 && (macro->GetType() == USE_PHYSICAL_MAPPING || macro->GetType() == USE_VERTEX_SPRITE) ) + if ( ( permutation & macro->GetBit() ) != 0 && macro->GetType() == USE_PHYSICAL_MAPPING ) { //Log::Notice("conflicting macro! canceling '%s' vs. '%s'", GetName(), macro->GetName()); return true; @@ -1598,7 +1598,7 @@ bool GLCompileMacro_USE_VERTEX_SKINNING::HasConflictingMacros( size_t permutatio for (const GLCompileMacro* macro : macros) { //if(GLCompileMacro_USE_VERTEX_ANIMATION* m = dynamic_cast(macro)) - if ( ( permutation & macro->GetBit() ) != 0 && (macro->GetType() == USE_VERTEX_ANIMATION || macro->GetType() == USE_VERTEX_SPRITE) ) + if ( ( permutation & macro->GetBit() ) != 0 && macro->GetType() == USE_VERTEX_ANIMATION ) { //Log::Notice("conflicting macro! canceling '%s' vs. '%s'", GetName(), macro->GetName()); return true; @@ -1617,7 +1617,7 @@ bool GLCompileMacro_USE_VERTEX_ANIMATION::HasConflictingMacros( size_t permutati { for (const GLCompileMacro* macro : macros) { - if ( ( permutation & macro->GetBit() ) != 0 && (macro->GetType() == USE_VERTEX_SKINNING || macro->GetType() == USE_VERTEX_SPRITE) ) + if ( ( permutation & macro->GetBit() ) != 0 && macro->GetType() == USE_VERTEX_SKINNING ) { //Log::Notice("conflicting macro! canceling '%s' vs. '%s'", GetName(), macro->GetName()); return true; @@ -1634,20 +1634,6 @@ uint32_t GLCompileMacro_USE_VERTEX_ANIMATION::GetRequiredVertexAttributes() cons return attribs; } -bool GLCompileMacro_USE_VERTEX_SPRITE::HasConflictingMacros( size_t permutation, const std::vector< GLCompileMacro * > ¯os ) const -{ - for (const GLCompileMacro* macro : macros) - { - if ( ( permutation & macro->GetBit() ) != 0 && (macro->GetType() == USE_VERTEX_SKINNING || macro->GetType() == USE_VERTEX_ANIMATION || macro->GetType() == USE_DEPTH_FADE)) - { - //Log::Notice("conflicting macro! canceling '%s' vs. '%s'", GetName(), macro->GetName()); - return true; - } - } - - return false; -} - bool GLCompileMacro_USE_TCGEN_ENVIRONMENT::HasConflictingMacros( size_t permutation, const std::vector ¯os) const { for (const GLCompileMacro* macro : macros) @@ -1676,20 +1662,6 @@ bool GLCompileMacro_USE_TCGEN_LIGHTMAP::HasConflictingMacros(size_t permutation, return false; } -bool GLCompileMacro_USE_DEPTH_FADE::HasConflictingMacros(size_t permutation, const std::vector ¯os) const -{ - for (const GLCompileMacro* macro : macros) - { - if ((permutation & macro->GetBit()) != 0 && (macro->GetType() == USE_VERTEX_SPRITE)) - { - //Log::Notice("conflicting macro! canceling '%s' vs. '%s'", GetName(), macro->GetName()); - return true; - } - } - - return false; -} - bool GLCompileMacro_USE_DELUXE_MAPPING::HasConflictingMacros(size_t permutation, const std::vector ¯os) const { for (const GLCompileMacro* macro : macros) @@ -1953,7 +1925,7 @@ void GLShader::DispatchComputeIndirect( const GLintptr indirectBuffer ) { glDispatchComputeIndirect( indirectBuffer ); } -void GLShader::SetRequiredVertexPointers( bool vertexSprite ) +void GLShader::SetRequiredVertexPointers() { uint32_t macroVertexAttribs = 0; @@ -1966,13 +1938,6 @@ void GLShader::SetRequiredVertexPointers( bool vertexSprite ) } uint32_t attribs = _vertexAttribsRequired | _vertexAttribs | macroVertexAttribs; // & ~_vertexAttribsUnsupported); - - if ( vertexSprite ) - { - attribs &= ~ATTR_QTANGENT; - attribs |= ATTR_ORIENTATION; - } - GL_VertexAttribsState( attribs ); } @@ -2031,7 +1996,6 @@ GLShader_generic::GLShader_generic( GLShaderManager *manager ) : GLDeformStage( this ), GLCompileMacro_USE_VERTEX_SKINNING( this ), GLCompileMacro_USE_VERTEX_ANIMATION( this ), - GLCompileMacro_USE_VERTEX_SPRITE( this ), GLCompileMacro_USE_TCGEN_ENVIRONMENT( this ), GLCompileMacro_USE_TCGEN_LIGHTMAP( this ), GLCompileMacro_USE_DEPTH_FADE( this ) @@ -2063,7 +2027,6 @@ GLShader_genericMaterial::GLShader_genericMaterial( GLShaderManager* manager ) : GLDeformStage( this ), // GLCompileMacro_USE_VERTEX_SKINNING( this ), GLCompileMacro_USE_VERTEX_ANIMATION( this ), - GLCompileMacro_USE_VERTEX_SPRITE( this ), GLCompileMacro_USE_TCGEN_ENVIRONMENT( this ), GLCompileMacro_USE_TCGEN_LIGHTMAP( this ), GLCompileMacro_USE_DEPTH_FADE( this ) { @@ -2604,8 +2567,7 @@ GLShader_heatHaze::GLShader_heatHaze( GLShaderManager *manager ) : u_VertexInterpolation( this ), GLDeformStage( this ), GLCompileMacro_USE_VERTEX_SKINNING( this ), - GLCompileMacro_USE_VERTEX_ANIMATION( this ), - GLCompileMacro_USE_VERTEX_SPRITE( this ) + GLCompileMacro_USE_VERTEX_ANIMATION( this ) { } @@ -2636,8 +2598,8 @@ GLShader_heatHazeMaterial::GLShader_heatHazeMaterial( GLShaderManager* manager ) u_VertexInterpolation( this ), GLDeformStage( this ), // GLCompileMacro_USE_VERTEX_SKINNING( this ), - GLCompileMacro_USE_VERTEX_ANIMATION( this ), - GLCompileMacro_USE_VERTEX_SPRITE( this ) { + GLCompileMacro_USE_VERTEX_ANIMATION( this ) +{ } void GLShader_heatHazeMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index ae168f3568..c860398994 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -277,7 +277,7 @@ class GLShader void BindProgram( int deformIndex ); void DispatchCompute( const GLuint globalWorkgroupX, const GLuint globalWorkgroupY, const GLuint globalWorkgroupZ ); void DispatchComputeIndirect( const GLintptr indirectBuffer ); - void SetRequiredVertexPointers( bool vertexSprite = false ); + void SetRequiredVertexPointers(); bool IsMacroSet( int bit ) { @@ -1666,7 +1666,6 @@ class GLCompileMacro USE_BSP_SURFACE, USE_VERTEX_SKINNING, USE_VERTEX_ANIMATION, - USE_VERTEX_SPRITE, USE_TCGEN_ENVIRONMENT, USE_TCGEN_LIGHTMAP, USE_DELUXE_MAPPING, @@ -1812,37 +1811,6 @@ class GLCompileMacro_USE_VERTEX_ANIMATION : } }; -class GLCompileMacro_USE_VERTEX_SPRITE : - GLCompileMacro -{ -public: - GLCompileMacro_USE_VERTEX_SPRITE( GLShader *shader ) : - GLCompileMacro( shader ) - { - } - - const char *GetName() const override - { - return "USE_VERTEX_SPRITE"; - } - - EGLCompileMacro GetType() const override - { - return EGLCompileMacro::USE_VERTEX_SPRITE; - } - - bool HasConflictingMacros( size_t permutation, const std::vector< GLCompileMacro * > ¯os ) const override; - uint32_t GetRequiredVertexAttributes() const override - { - return ATTR_QTANGENT; - } - - void SetVertexSprite( bool enable ) - { - SetMacro( enable ); - } -}; - class GLCompileMacro_USE_TCGEN_ENVIRONMENT : GLCompileMacro { @@ -2122,7 +2090,6 @@ class GLCompileMacro_USE_DEPTH_FADE : return "USE_DEPTH_FADE"; } - bool HasConflictingMacros(size_t permutation, const std::vector ¯os) const override; EGLCompileMacro GetType() const override { return EGLCompileMacro::USE_DEPTH_FADE; @@ -3945,7 +3912,6 @@ class GLShader_generic : public GLDeformStage, public GLCompileMacro_USE_VERTEX_SKINNING, public GLCompileMacro_USE_VERTEX_ANIMATION, - public GLCompileMacro_USE_VERTEX_SPRITE, public GLCompileMacro_USE_TCGEN_ENVIRONMENT, public GLCompileMacro_USE_TCGEN_LIGHTMAP, public GLCompileMacro_USE_DEPTH_FADE @@ -3974,7 +3940,6 @@ class GLShader_genericMaterial : public GLDeformStage, // public GLCompileMacro_USE_VERTEX_SKINNING, public GLCompileMacro_USE_VERTEX_ANIMATION, - public GLCompileMacro_USE_VERTEX_SPRITE, public GLCompileMacro_USE_TCGEN_ENVIRONMENT, public GLCompileMacro_USE_TCGEN_LIGHTMAP, public GLCompileMacro_USE_DEPTH_FADE { @@ -4416,8 +4381,7 @@ class GLShader_heatHaze : public u_VertexInterpolation, public GLDeformStage, public GLCompileMacro_USE_VERTEX_SKINNING, - public GLCompileMacro_USE_VERTEX_ANIMATION, - public GLCompileMacro_USE_VERTEX_SPRITE + public GLCompileMacro_USE_VERTEX_ANIMATION { public: GLShader_heatHaze( GLShaderManager *manager ); @@ -4444,9 +4408,9 @@ class GLShader_heatHazeMaterial : public u_VertexInterpolation, public GLDeformStage, // public GLCompileMacro_USE_VERTEX_SKINNING, - public GLCompileMacro_USE_VERTEX_ANIMATION, - public GLCompileMacro_USE_VERTEX_SPRITE { - public: + public GLCompileMacro_USE_VERTEX_ANIMATION +{ +public: GLShader_heatHazeMaterial( GLShaderManager* manager ); void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; }; diff --git a/src/engine/renderer/glsl_source/generic_fp.glsl b/src/engine/renderer/glsl_source/generic_fp.glsl index c923d6a35c..42301f1998 100644 --- a/src/engine/renderer/glsl_source/generic_fp.glsl +++ b/src/engine/renderer/glsl_source/generic_fp.glsl @@ -34,7 +34,7 @@ uniform float u_InverseLightFactor; IN(smooth) vec2 var_TexCoords; IN(smooth) vec4 var_Color; -#if defined(USE_DEPTH_FADE) || defined(USE_VERTEX_SPRITE) +#if defined(USE_DEPTH_FADE) IN(smooth) vec2 var_FadeDepth; uniform sampler2D u_DepthMap; #endif @@ -53,7 +53,7 @@ void main() return; } -#if defined(USE_DEPTH_FADE) || defined(USE_VERTEX_SPRITE) +#if defined(USE_DEPTH_FADE) float depth = texture2D(u_DepthMap, gl_FragCoord.xy / r_FBufSize).x; float fadeDepth = 0.5 * var_FadeDepth.x / var_FadeDepth.y + 0.5; color.a *= smoothstep(gl_FragCoord.z, fadeDepth, depth); diff --git a/src/engine/renderer/glsl_source/generic_vp.glsl b/src/engine/renderer/glsl_source/generic_vp.glsl index 3765151031..8de2de9e6f 100644 --- a/src/engine/renderer/glsl_source/generic_vp.glsl +++ b/src/engine/renderer/glsl_source/generic_vp.glsl @@ -25,12 +25,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #insert vertexSimple_vp #insert vertexSkinning_vp #insert vertexAnimation_vp -#insert vertexSprite_vp uniform mat4 u_TextureMatrix; -#if !defined(USE_VERTEX_SPRITE) uniform vec3 u_ViewOrigin; -#endif uniform float u_Time; @@ -41,9 +38,7 @@ uniform mat4 u_ModelMatrix; #endif uniform mat4 u_ModelViewProjectionMatrix; -#if defined(USE_VERTEX_SPRITE) -OUT(smooth) vec2 var_FadeDepth; -#elif defined(USE_DEPTH_FADE) +#if defined(USE_DEPTH_FADE) uniform float u_DepthScale; OUT(smooth) vec2 var_FadeDepth; #endif @@ -102,9 +97,6 @@ void main() // compute z of end of fading effect vec4 fadeDepth = u_ModelViewProjectionMatrix * (position - u_DepthScale * vec4(LB.normal, 0.0)); var_FadeDepth = fadeDepth.zw; -#elif defined(USE_VERTEX_SPRITE) - vec4 fadeDepth = u_ModelViewProjectionMatrix * (position - depthScale * vec4(LB.normal, 0.0)); - var_FadeDepth = fadeDepth.zw; #endif var_Color = color; diff --git a/src/engine/renderer/glsl_source/heatHaze_vp.glsl b/src/engine/renderer/glsl_source/heatHaze_vp.glsl index a9b4cd6544..29fd607409 100644 --- a/src/engine/renderer/glsl_source/heatHaze_vp.glsl +++ b/src/engine/renderer/glsl_source/heatHaze_vp.glsl @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #insert vertexSimple_vp #insert vertexSkinning_vp #insert vertexAnimation_vp -#insert vertexSprite_vp uniform float u_Time; diff --git a/src/engine/renderer/glsl_source/lightMapping_vp.glsl b/src/engine/renderer/glsl_source/lightMapping_vp.glsl index 5a2ab6574d..32978b7b76 100644 --- a/src/engine/renderer/glsl_source/lightMapping_vp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_vp.glsl @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #insert vertexSimple_vp #insert vertexSkinning_vp #insert vertexAnimation_vp -#insert vertexSprite_vp #if !defined(USE_BSP_SURFACE) #define USE_MODEL_SURFACE diff --git a/src/engine/renderer/glsl_source/material_fp.glsl b/src/engine/renderer/glsl_source/material_fp.glsl index bf72a5cf6f..57abe21a73 100644 --- a/src/engine/renderer/glsl_source/material_fp.glsl +++ b/src/engine/renderer/glsl_source/material_fp.glsl @@ -66,9 +66,9 @@ sampler2D u_ColorMap = sampler2D( u_ColorMap_initial ); #if defined(GENERIC_GLSL) sampler2D u_ColorMap = sampler2D( u_ColorMap_initial ); -#if defined(USE_DEPTH_FADE) || defined(USE_VERTEX_SPRITE) +#if defined(USE_DEPTH_FADE) sampler2D u_DepthMap = sampler2D( u_DepthMap_initial ); -#endif // !(USE_DEPTH_FADE || USE_VERTEX_SPRITE) +#endif #endif // !GENERIC_GLSL #if defined(HEATHAZE_GLSL) diff --git a/src/engine/renderer/glsl_source/vertexSimple_vp.glsl b/src/engine/renderer/glsl_source/vertexSimple_vp.glsl index b316351950..58eebaf142 100644 --- a/src/engine/renderer/glsl_source/vertexSimple_vp.glsl +++ b/src/engine/renderer/glsl_source/vertexSimple_vp.glsl @@ -38,7 +38,7 @@ void QTangentToLocalBasis( in vec4 qtangent, out localBasis LB ) { LB.binormal = QuatTransVec( qtangent, vec3( 0.0, 1.0, 0.0 ) ); } -#if !defined(USE_VERTEX_ANIMATION) && !defined(USE_VERTEX_SKINNING) && !defined(USE_VERTEX_SPRITE) +#if !defined(USE_VERTEX_ANIMATION) && !defined(USE_VERTEX_SKINNING) IN vec3 attr_Position; IN vec4 attr_Color; diff --git a/src/engine/renderer/glsl_source/vertexSprite_vp.glsl b/src/engine/renderer/glsl_source/vertexSprite_vp.glsl deleted file mode 100644 index 8b914c4307..0000000000 --- a/src/engine/renderer/glsl_source/vertexSprite_vp.glsl +++ /dev/null @@ -1,82 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 Robert Beckebans - -This file is part of XreaL source code. - -XreaL source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -XreaL source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with XreaL source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// vertexSprite_vp.glsl - sprite vertex fetch - -#if defined(USE_VERTEX_SPRITE) - -IN vec3 attr_Position; -IN vec4 attr_Color; -IN vec4 attr_TexCoord0; -IN vec4 attr_Orientation; - -uniform vec3 u_ViewOrigin; -uniform vec3 u_ViewUp; - -float depthScale; - -void VertexFetch(out vec4 position, - out localBasis normalBasis, - out vec4 color, - out vec2 texCoord, - out vec2 lmCoord) -{ - vec2 corner; - float radius = attr_Orientation.w; - vec3 normal = normalize( u_ViewOrigin - attr_Position ), up, left; - float s, c; // sin & cos of rotation factor - - corner = sign( attr_TexCoord0.zw ); - - if( radius <= 0.0 ) { - // autosprite2 mode, attr_Orientation.xyz contains the up-vector - up = attr_Orientation.xyz; - left = radius * normalize( cross( up, normal ) ); - position = vec4( attr_Position + corner.y * left, 1.0 ); - } else { - // autosprite mode, attr_Orientation.x contains the rotation angle - left = normalize( cross( u_ViewUp, normal ) ); - up = cross( left, normal ); - - s = radius * sin( radians( attr_Orientation.x ) ); - c = radius * cos( radians( attr_Orientation.x ) ); - - // rotate left and up vectors - vec3 leftOrig = left; - left = c * left + s * up; - up = c * up - s * leftOrig; - - left *= corner.x; - up *= corner.y; - - position = vec4( attr_Position + left + up, 1.0 ); - } - normalBasis.normal = normal; - normalBasis.tangent = normalize( up ); - normalBasis.binormal = normalize( left ); - - texCoord = 0.5 * corner + 0.5; //attr_TexCoord0.xy; - lmCoord = abs( attr_TexCoord0.zw ); - color = attr_Color; - - depthScale = 2.0 * radius; -} -#endif diff --git a/src/engine/renderer/shaders.cpp b/src/engine/renderer/shaders.cpp index 2953c09dc6..a41f284a9d 100644 --- a/src/engine/renderer/shaders.cpp +++ b/src/engine/renderer/shaders.cpp @@ -6,7 +6,6 @@ #include "vertexAnimation_vp.glsl.h" #include "vertexSimple_vp.glsl.h" #include "vertexSkinning_vp.glsl.h" -#include "vertexSprite_vp.glsl.h" #include "blurX_fp.glsl.h" #include "blurX_vp.glsl.h" #include "blurY_fp.glsl.h" @@ -131,5 +130,4 @@ std::unordered_map shadermap({ { "vertexAnimation_vp.glsl", std::string(reinterpret_cast(vertexAnimation_vp_glsl), sizeof(vertexAnimation_vp_glsl)) }, { "vertexSimple_vp.glsl", std::string(reinterpret_cast(vertexSimple_vp_glsl), sizeof(vertexSimple_vp_glsl)) }, { "vertexSkinning_vp.glsl", std::string(reinterpret_cast(vertexSkinning_vp_glsl), sizeof(vertexSkinning_vp_glsl)) }, - { "vertexSprite_vp.glsl", std::string(reinterpret_cast(vertexSprite_vp_glsl), sizeof(vertexSprite_vp_glsl)) }, }); diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 34c1784e75..6c779abf89 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1913,7 +1913,6 @@ static void RB_SetupLightForLighting( trRefLight_t *light ) gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); gl_genericShader->SetTCGenEnvironment( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); gl_genericShader->BindProgram( 0 ); @@ -2783,7 +2782,6 @@ void RB_RunVisTests( ) gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -3418,7 +3416,6 @@ static void RB_RenderDebugUtils() gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -3579,7 +3576,6 @@ static void RB_RenderDebugUtils() gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -3696,7 +3692,6 @@ static void RB_RenderDebugUtils() gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -3764,7 +3759,6 @@ static void RB_RenderDebugUtils() gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -3979,7 +3973,6 @@ static void RB_RenderDebugUtils() gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -4093,7 +4086,6 @@ static void RB_RenderDebugUtils() gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -4161,7 +4153,6 @@ static void RB_RenderDebugUtils() gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -4254,7 +4245,6 @@ static void RB_RenderDebugUtils() gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -4549,7 +4539,6 @@ void DebugDrawBegin( debugDrawMode_t mode, float size ) { gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -5692,7 +5681,6 @@ void RB_ShowImages() gl_genericShader->SetVertexSkinning( false ); gl_genericShader->SetVertexAnimation( false ); - gl_genericShader->SetVertexSprite( false ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index 1240ee761d..200d83b78f 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -2974,7 +2974,7 @@ static void R_CreateWorldVBO() { surface = &s_worldData.surfaces[ k ]; - if ( surface->shader->isPortal ) + if ( surface->shader->isPortal || surface->shader->autoSpriteMode != 0 ) { continue; } @@ -3049,7 +3049,7 @@ static void R_CreateWorldVBO() shader1 = surf1->shader; - if ( shader1->isPortal ) + if ( shader1->isPortal || shader1->autoSpriteMode != 0 ) { continue; } @@ -3117,6 +3117,12 @@ static void R_CreateWorldVBO() continue; } + if ( surface->shader->autoSpriteMode != 0 ) + { + // don't use VBO because verts are rewritten each time based on view origin + continue; + } + if ( *surface->data == surfaceType_t::SF_FACE || *surface->data == surfaceType_t::SF_GRID || *surface->data == surfaceType_t::SF_TRIANGLES ) { surfaces[ numSurfaces++ ] = surface; @@ -3183,8 +3189,6 @@ static void R_CreateWorldVBO() } rb_surfaceTable[Util::ordinal(surfaceType_t::SF_FACE)](srf ); - Tess_AutospriteDeform( surface->shader->autoSpriteMode, srf->firstVert, srf->numVerts, - 3 * srf->firstTriangle, 3 * srf->numTriangles ); } else if ( *surface->data == surfaceType_t::SF_GRID ) { @@ -3219,8 +3223,6 @@ static void R_CreateWorldVBO() } rb_surfaceTable[Util::ordinal(surfaceType_t::SF_GRID)](srf ); - Tess_AutospriteDeform( surface->shader->autoSpriteMode, srf->firstVert, srf->numVerts, - 3 * srf->firstTriangle, 3 * srf->numTriangles ); } else if ( *surface->data == surfaceType_t::SF_TRIANGLES ) { @@ -3255,15 +3257,12 @@ static void R_CreateWorldVBO() } rb_surfaceTable[Util::ordinal(surfaceType_t::SF_TRIANGLES)](srf ); - Tess_AutospriteDeform( surface->shader->autoSpriteMode, srf->firstVert, srf->numVerts, - 3 * srf->firstTriangle, 3 * srf->numTriangles ); } } - // autosprite/autosprite2 surfaces have ATTR_ORIENTATION and everything else ATTR_QTANGENT. s_worldData.vbo = R_CreateStaticVBO2( "staticWorld_VBO %i", numVerts, vboVerts, - ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_ORIENTATION | ATTR_COLOR ); + ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_COLOR ); s_worldData.ibo = R_CreateStaticIBO2( va( "staticWorld_IBO %i", 0 ), numTriangles, vboIdxs ); Tess_Clear(); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index f1685cde4c..99e1b1c030 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -658,9 +658,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; ATTR_INDEX_QTANGENT, ATTR_INDEX_COLOR, - // Sprites - ATTR_INDEX_ORIENTATION, - // GPU vertex skinning ATTR_INDEX_BONE_FACTORS, @@ -677,7 +674,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; "attr_TexCoord0", "attr_QTangent", "attr_Color", - "attr_Orientation", "attr_BoneFactors", "attr_Position2", "attr_QTangent2" @@ -690,7 +686,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; ATTR_QTANGENT = BIT( ATTR_INDEX_QTANGENT ), ATTR_COLOR = BIT( ATTR_INDEX_COLOR ), - ATTR_ORIENTATION = BIT( ATTR_INDEX_ORIENTATION ), ATTR_BONE_FACTORS = BIT( ATTR_INDEX_BONE_FACTORS ), // for .md3 interpolation @@ -1298,8 +1293,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; bool interactLight; // this shader can interact with light shaders - // mode 1 can be used in BSP surfaces or with RT_SPRITE - // mode 2 can be used only in BSP surfaces int autoSpriteMode; uint8_t numDeforms; @@ -3278,10 +3271,7 @@ inline bool checkGLErrors() struct shaderVertex_t { vec3_t xyz; Color::Color32Bit color; - union { - i16vec4_t qtangents; - f16vec4_t spriteOrientation; - }; + i16vec4_t qtangents; f16vec4_t texCoords; }; @@ -3680,8 +3670,7 @@ inline bool checkGLErrors() void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ); float R_ProjectRadius( float r, vec3_t location ); - void Tess_AutospriteDeform( int mode, int firstVertex, int numVertexes, - int firstIndex, int numIndexes ); + void Tess_AutospriteDeform( int mode ); float RB_EvalWaveForm( const waveForm_t *wf ); float RB_EvalWaveFormClamped( const waveForm_t *wf ); diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 83fdd30a6e..a3fbe46bfe 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -1908,7 +1908,7 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, i tr.refdef.numDrawSurfs++; // Portal and sky surfaces are not handled by the material system at all - if ( materialSystem.generatingWorldCommandBuffer && ( shader->isPortal || shader->isSky ) ) { + if ( materialSystem.generatingWorldCommandBuffer && ( shader->isPortal || shader->isSky || shader->autoSpriteMode ) ) { if ( shader->isSky && std::find( materialSystem.skyShaders.begin(), materialSystem.skyShaders.end(), shader ) == materialSystem.skyShaders.end() ) { materialSystem.skyShaders.emplace_back( shader ); @@ -1922,6 +1922,11 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, i materialSystem.portalSurfacesTmp.end() ); materialSystem.portalSurfacesTmp.emplace_back( drawSurf ); } + + if ( shader->autoSpriteMode ) { + materialSystem.autospriteSurfaces.push_back( *drawSurf ); + } + return; } @@ -2792,6 +2797,7 @@ void R_RenderView( viewParms_t *parms ) if ( glConfig2.materialSystemAvailable ) { tr.viewParms.viewID = tr.viewCount; materialSystem.QueueSurfaceCull( tr.viewCount, tr.viewParms.pvsOrigin, (frustum_t*) tr.viewParms.frustums[0] ); + materialSystem.AddAutospriteSurfaces(); } else { R_AddWorldSurfaces(); } diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 8b5a5387db..afc80392fc 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -612,11 +612,8 @@ static void DrawTris() GLimp_LogComment( "--- DrawTris ---\n" ); - bool vertexSprite = tess.surfaceShader->autoSpriteMode != 0; - gl_genericShader->SetVertexSkinning( glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning ); gl_genericShader->SetVertexAnimation( tess.vboVertexAnimation ); - gl_genericShader->SetVertexSprite( vertexSprite ); gl_genericShader->SetTCGenEnvironment( false ); gl_genericShader->SetTCGenLightmap( false ); gl_genericShader->SetDepthFade( false ); @@ -667,7 +664,7 @@ static void DrawTris() GL_BindToTMU( 0, tr.whiteImage ) ); gl_genericShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); - gl_genericShader->SetRequiredVertexPointers( vertexSprite ); + gl_genericShader->SetRequiredVertexPointers(); glDepthRange( 0, 0 ); @@ -735,7 +732,7 @@ void Tess_Begin( void ( *stageIteratorFunc )(), tess.surfaceLastStage = nullptr; } - Tess_MapVBOs( false ); + Tess_MapVBOs( tess.surfaceShader && tess.surfaceShader->autoSpriteMode != 0 ); if ( !tess.stageIteratorFunc ) { @@ -783,9 +780,8 @@ static void Render_generic2D( shaderStage_t *pStage ) GL_State( pStage->stateBits ); - bool hasDepthFade = pStage->hasDepthFade && !tess.surfaceShader->autoSpriteMode; - bool needDepthMap = pStage->hasDepthFade || tess.surfaceShader->autoSpriteMode; - bool vertexSprite = tess.surfaceShader->autoSpriteMode != 0; + bool hasDepthFade = pStage->hasDepthFade; + bool needDepthMap = pStage->hasDepthFade; // choose right shader program ---------------------------------- gl_generic2DShader->SetDepthFade( hasDepthFade ); @@ -832,7 +828,7 @@ static void Render_generic2D( shaderStage_t *pStage ) ); } - gl_generic2DShader->SetRequiredVertexPointers( vertexSprite ); + gl_generic2DShader->SetRequiredVertexPointers(); Tess_DrawElements(); GL_CheckErrors(); @@ -856,9 +852,8 @@ void Render_generic3D( shaderStage_t *pStage ) GL_State( pStage->stateBits ); - bool hasDepthFade = pStage->hasDepthFade && !tess.surfaceShader->autoSpriteMode; - bool needDepthMap = pStage->hasDepthFade || tess.surfaceShader->autoSpriteMode; - bool vertexSprite = tess.surfaceShader->autoSpriteMode != 0; + bool hasDepthFade = pStage->hasDepthFade; + bool needDepthMap = pStage->hasDepthFade; // choose right shader program ---------------------------------- gl_genericShader->SetVertexSkinning( glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning ); @@ -866,12 +861,11 @@ void Render_generic3D( shaderStage_t *pStage ) gl_genericShader->SetTCGenEnvironment( pStage->tcGen_Environment ); gl_genericShader->SetTCGenLightmap( pStage->tcGen_Lightmap ); gl_genericShader->SetDepthFade( hasDepthFade ); - gl_genericShader->SetVertexSprite( vertexSprite ); gl_genericShader->BindProgram( pStage->deformIndex ); // end choose right shader program ------------------------------ // set uniforms - if ( pStage->tcGen_Environment || vertexSprite ) + if ( pStage->tcGen_Environment ) { // calculate the environment texcoords in object space gl_genericShader->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); @@ -938,7 +932,7 @@ void Render_generic3D( shaderStage_t *pStage ) ); } - gl_genericShader->SetRequiredVertexPointers( vertexSprite ); + gl_genericShader->SetRequiredVertexPointers(); Tess_DrawElements(); @@ -2150,20 +2144,11 @@ void Render_heatHaze( shaderStage_t *pStage ) // choose right shader program ---------------------------------- gl_heatHazeShader->SetVertexSkinning( glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning ); gl_heatHazeShader->SetVertexAnimation( glState.vertexAttribsInterpolation > 0 ); - bool vertexSprite = tess.surfaceShader->autoSpriteMode != 0; - gl_heatHazeShader->SetVertexSprite( vertexSprite ); gl_heatHazeShader->BindProgram( pStage->deformIndex ); // end choose right shader program ------------------------------ // set uniforms - if ( vertexSprite ) - { - // calculate the environment texcoords in object space - gl_heatHazeShader->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); - gl_heatHazeShader->SetUniform_ViewUp( backEnd.orientation.axis[ 2 ] ); - } - deformMagnitude = RB_EvalExpression( &pStage->deformMagnitudeExp, 1.0 ); gl_heatHazeShader->SetUniform_DeformMagnitude( deformMagnitude ); @@ -2214,7 +2199,7 @@ void Render_heatHaze( shaderStage_t *pStage ) GL_BindToTMU( 1, tr.currentRenderImage[backEnd.currentMainFBO] ) ); - gl_heatHazeShader->SetRequiredVertexPointers( vertexSprite ); + gl_heatHazeShader->SetRequiredVertexPointers(); Tess_DrawElements(); @@ -2753,6 +2738,11 @@ void Tess_StageIteratorColor() GL_CheckErrors(); + if ( tess.surfaceShader->autoSpriteMode != 0 ) + { + Tess_AutospriteDeform( tess.surfaceShader->autoSpriteMode ); + } + if ( !glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo ) { Tess_UpdateVBOs( ); @@ -2818,6 +2808,11 @@ void Tess_StageIteratorPortal() { GL_CheckErrors(); + if ( tess.surfaceShader->autoSpriteMode != 0 ) + { + Tess_AutospriteDeform( tess.surfaceShader->autoSpriteMode ); + } + if ( !glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo ) { Tess_UpdateVBOs(); } @@ -2853,6 +2848,11 @@ void Tess_StageIteratorShadowFill() GL_CheckErrors(); + if ( tess.surfaceShader->autoSpriteMode != 0 ) + { + Tess_AutospriteDeform( tess.surfaceShader->autoSpriteMode ); + } + if ( !glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo ) { Tess_UpdateVBOs( ); @@ -2909,6 +2909,11 @@ void Tess_StageIteratorLighting() light = backEnd.currentLight; + if ( tess.surfaceShader->autoSpriteMode != 0 ) + { + Tess_AutospriteDeform( tess.surfaceShader->autoSpriteMode ); + } + if ( !glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo ) { Tess_UpdateVBOs( ); diff --git a/src/engine/renderer/tr_shade_calc.cpp b/src/engine/renderer/tr_shade_calc.cpp index adf3531f8e..05e936c39e 100644 --- a/src/engine/renderer/tr_shade_calc.cpp +++ b/src/engine/renderer/tr_shade_calc.cpp @@ -463,87 +463,75 @@ DEFORMATIONS ==================================================================== */ +static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) +{ + out[ 0 ] = DotProduct( in, backEnd.orientation.axis[ 0 ] ); + out[ 1 ] = DotProduct( in, backEnd.orientation.axis[ 1 ] ); + out[ 2 ] = DotProduct( in, backEnd.orientation.axis[ 2 ] ); +} + /* ===================== AutospriteDeform Assuming all the triangles for this shader are independent quads, rebuild them as forward facing sprites +They face toward the *view direction* like autosprite2 style 0. We could implement style +1 (toward viewer) here as well, but the difference seems less noticeable. ===================== */ -static void ComputeCorner( int firstVertex, int numVertexes ) +static void AutospriteDeform( uint32_t numVertexes ) { - int i, j; - shaderVertex_t *v; - vec4_t tc, midtc; + vec3_t leftDir, upDir; - for ( i = 0; i < numVertexes; i += 4 ) { - // find the midpoint - v = &tess.verts[ firstVertex + i ]; + if ( backEnd.currentEntity != &tr.worldEntity ) + { + GlobalVectorToLocal( backEnd.viewParms.orientation.axis[ 1 ], leftDir ); + GlobalVectorToLocal( backEnd.viewParms.orientation.axis[ 2 ], upDir ); + } + else + { + VectorCopy( backEnd.viewParms.orientation.axis[ 1 ], leftDir ); + VectorCopy( backEnd.viewParms.orientation.axis[ 2 ], upDir ); + } - Vector4Set( midtc, 0.0f, 0.0f, 0.0f, 0.0f ); - for( j = 0; j < 4; j++ ) { - halfToFloat( v[ j ].texCoords, tc ); - VectorAdd( tc, midtc, midtc ); - midtc[ 3 ] += tc[ 3 ]; - } + float scale = 1.0 / M_SQRT2; - midtc[ 0 ] = 0.25f * midtc[ 0 ]; - midtc[ 1 ] = 0.25f * midtc[ 1 ]; + if ( backEnd.currentEntity->e.nonNormalizedAxes ) + { + float axisLength = VectorLength( backEnd.currentEntity->e.axis[ 0 ] ); - for ( j = 0; j < 4; j++ ) { - halfToFloat( v[ j ].texCoords, tc ); - if( tc[ 0 ] < midtc[ 0 ] ) { - tc[ 2 ] = -tc[ 2 ]; - } - if( tc[ 1 ] < midtc[ 1 ] ) { - tc[ 3 ] = -tc[ 3 ]; - } - floatToHalf( tc, v[ j ].texCoords ); + if ( axisLength ) + { + scale /= axisLength; } } -} - -static void AutospriteDeform( int firstVertex, int numVertexes, int numIndexes ) -{ - int i, j; - shaderVertex_t *v; - vec3_t mid, delta; - float radius; - if ( numVertexes & 3 ) + for ( uint32_t i = 0; i < numVertexes; i += 4 ) { - Log::Warn("Autosprite shader %s had odd vertex count", tess.surfaceShader->name ); - } + const shaderVertex_t *v = tess.vertsBuffer + i; - if ( numIndexes != ( numVertexes >> 2 ) * 6 ) - { - Log::Warn("Autosprite shader %s had odd index count", tess.surfaceShader->name ); - } + // find the midpoint + vec3_t center; + VectorAdd( v[ 0 ].xyz, v[ 1 ].xyz, center ); + VectorAdd( center, v[ 2 ].xyz, center ); + VectorAdd( center, v[ 3 ].xyz, center ); + VectorScale( center, 0.25f, center ); - ComputeCorner( firstVertex, numVertexes ); + vec3_t delta; + VectorSubtract( v[ 0 ].xyz, center, delta ); + float radius = VectorLength( delta ) * scale; - for ( i = 0; i < numVertexes; i += 4 ) - { - // find the midpoint - v = &tess.verts[ firstVertex + i ]; - - mid[ 0 ] = 0.25f * ( v[ 0 ].xyz[ 0 ] + v[ 1 ].xyz[ 0 ] + v[ 2 ].xyz[ 0 ] + v[ 3 ].xyz[ 0 ] ); - mid[ 1 ] = 0.25f * ( v[ 0 ].xyz[ 1 ] + v[ 1 ].xyz[ 1 ] + v[ 2 ].xyz[ 1 ] + v[ 3 ].xyz[ 1 ] ); - mid[ 2 ] = 0.25f * ( v[ 0 ].xyz[ 2 ] + v[ 1 ].xyz[ 2 ] + v[ 2 ].xyz[ 2 ] + v[ 3 ].xyz[ 2 ] ); - - VectorSubtract( v[ 0 ].xyz, mid, delta ); - radius = VectorLength( delta ) * 0.5f * M_SQRT2; - - // add 4 identical vertices - for ( j = 0; j < 4; j++ ) { - VectorCopy( mid, v[ j ].xyz ); - Vector4Set( v[ j ].spriteOrientation, - floatToHalf( 0 ), - floatToHalf( 0 ), - floatToHalf( 0 ), - floatToHalf( radius ) ); + vec3_t left, up; + VectorScale( leftDir, radius, left ); + VectorScale( upDir, radius, up ); + + if ( backEnd.viewParms.mirrorLevel & 1 ) + { + VectorNegate( left, left ); } + + Tess_AddQuadStamp( center, left, up, v->color ); } } @@ -554,125 +542,106 @@ Autosprite2Deform Autosprite2 will pivot a rectangular quad along the center of its long axis ===================== */ -static const int edgeVerts[ 6 ][ 2 ] = -{ - { 0, 1 }, - { 0, 2 }, - { 0, 3 }, - { 1, 2 }, - { 1, 3 }, - { 2, 3 } -}; - -static void Autosprite2Deform( int firstVertex, int numVertexes, int numIndexes ) +// Style 0 is what Tremulous did but style 1 generally looks better, even with Tremulous assets. +// Style 0 looks stupid because you can see the sprite rotating if you stand still and move the +// mouse. Style 1 does a better job for making something look cylindrical, like the "pillar of flame" +// suggested in the Q3 manual. Either one will look bad beyond the ends of the long axis. +static Cvar::Range> r_autosprite2Style( + "r_autosprite2Style", "display autosprite2 surfaces facing (0) in view direction or (1) toward viewer", + Cvar::NONE, 1, 0, 1); +static void Autosprite2Deform( uint32_t numVertexes ) { - shaderVertex_t *v = &tess.verts[ firstVertex ]; - int i, j, k; - vec3_t oldPos[4]; - - if ( numVertexes & 3 ) - { - Log::Warn("Autosprite2 shader %s had odd vertex count", tess.surfaceShader->name ); - } - - if ( numIndexes != ( numVertexes >> 2 ) * 6 ) - { - Log::Warn("Autosprite2 shader %s had odd index count", tess.surfaceShader->name ); - } - - ComputeCorner( firstVertex, numVertexes ); + tess.numVertexes = numVertexes; + tess.numIndexes = ( numVertexes >> 2 ) * 6; + std::copy_n( tess.indexesBuffer, tess.numIndexes, tess.indexes ); // this is a lot of work for two triangles... // we could precalculate a lot of it is an issue, but it would mess up // the shader abstraction - for ( i = 0; i < numVertexes; i += 4, v += 4 ) + for ( uint32_t i = 0, indexes = 0; i < tess.numVertexes; i += 4, indexes += 6 ) { - float lengths[ 2 ]; - int nums[ 2 ]; - vec3_t mid[ 2 ]; - vec3_t normal, cross; - vec3_t major, minor; - shaderVertex_t *v1, *v2; - - VectorCopy( v[0].xyz, oldPos[0] ); - VectorCopy( v[1].xyz, oldPos[1] ); - VectorCopy( v[2].xyz, oldPos[2] ); - VectorCopy( v[3].xyz, oldPos[3] ); - - R_QtangentsToNormal( v->qtangents, normal ); - - // find the midpoint - - // identify the two shortest edges - nums[ 0 ] = nums[ 1 ] = 0; - lengths[ 0 ] = lengths[ 1 ] = 999999; - - for ( j = 0; j < 6; j++ ) + struct TriSide { + vec3_t firstVert; + float lengthSq; + vec3_t vector; // second point minus first point + }; + + TriSide sides[ 3 ]; + VectorCopy( tess.vertsBuffer[ tess.indexesBuffer[ indexes + 0 ] ].xyz, sides[ 0 ].firstVert ); + VectorCopy( tess.vertsBuffer[ tess.indexesBuffer[ indexes + 1 ] ].xyz, sides[ 1 ].firstVert ); + VectorCopy( tess.vertsBuffer[ tess.indexesBuffer[ indexes + 2 ] ].xyz, sides[ 2 ].firstVert ); + + for ( int j = 0; j < 3; j++ ) { - float l; - vec3_t temp; - - v1 = v + edgeVerts[ j ][ 0 ]; - v2 = v + edgeVerts[ j ][ 1 ]; - - VectorSubtract( v1->xyz, v2->xyz, temp ); + VectorSubtract( sides[ (j + 1) % 3 ].firstVert, sides[ j ].firstVert, sides[ j ].vector ); + sides[ j ].lengthSq = VectorLengthSquared( sides[ j ].vector ); + } - l = DotProduct( temp, temp ); + std::sort( std::begin( sides ), std::end( sides ), + []( TriSide &a, TriSide &b ) { return a.lengthSq < b.lengthSq; } ); + // Now sides[ 0 ] should be a short side of the rectangle, sides[ 1 ] a long side, + // and sides[ 2 ] a diagonal - if ( l < lengths[ 0 ] ) - { - nums[ 1 ] = nums[ 0 ]; - lengths[ 1 ] = lengths[ 0 ]; - nums[ 0 ] = j; - lengths[ 0 ] = l; - } - else if ( l < lengths[ 1 ] ) - { - nums[ 1 ] = j; - lengths[ 1 ] = l; - } + vec3_t forward; + if ( backEnd.currentEntity != &tr.worldEntity ) + { + // FIXME: implement style 1 here + GlobalVectorToLocal( backEnd.viewParms.orientation.axis[ 0 ], forward ); } - - for ( j = 0; j < 2; j++ ) + else if ( r_autosprite2Style.Get() == 0 ) { - v1 = v + edgeVerts[ nums[ j ] ][ 0 ]; - v2 = v + edgeVerts[ nums[ j ] ][ 1 ]; - - mid[ j ][ 0 ] = 0.5f * ( v1->xyz[ 0 ] + v2->xyz[ 0 ] ); - mid[ j ][ 1 ] = 0.5f * ( v1->xyz[ 1 ] + v2->xyz[ 1 ] ); - mid[ j ][ 2 ] = 0.5f * ( v1->xyz[ 2 ] + v2->xyz[ 2 ] ); + VectorCopy( backEnd.viewParms.orientation.axis[ 0 ], forward ); } - - // find the vector of the major axis - VectorSubtract( mid[ 1 ], mid[ 0 ], major ); - CrossProduct( major, normal, cross ); - - // update the vertices - for ( j = 0; j < 4; j++ ) + else { - vec4_t orientation; - - v1 = v + j; - lengths[ 0 ] = Distance( mid[ 0 ], v1->xyz ); - lengths[ 1 ] = Distance( mid[ 1 ], v1->xyz ); + vec3_t quadCenter; + VectorMA( sides[ 2 ].firstVert, 0.5f, sides[ 2 ].vector, quadCenter ); + VectorSubtract( quadCenter, backEnd.viewParms.orientation.origin, forward ); + VectorNormalize( forward ); + } - // pick the closer midpoint - if ( lengths[ 0 ] <= lengths[ 1 ] ) - k = 0; - else - k = 1; - - VectorSubtract( v1->xyz, mid[ k ], minor ); - // I guess this works, since the sign bit is the MSB for both floating point and integers - if ( ( DotProduct( cross, minor ) * static_cast(v1->texCoords[ 3 ].bits) ) < 0 ) { - VectorNegate( major, orientation ); - } else { - VectorCopy( major, orientation ); + vec3_t newMinorAxis; + CrossProduct( sides[ 1 ].vector, forward, newMinorAxis); + VectorNormalize( newMinorAxis ); + plane_t projection; + VectorNormalize2( sides[ 0 ].vector, projection.normal ); + projection.dist = DotProduct( sides[ 0 ].firstVert, projection.normal ) + + 0.5f * sqrtf( sides[ 0 ].lengthSq ); + vec3_t minorAxisReplace; + VectorSubtract( newMinorAxis, projection.normal, minorAxisReplace ); + + if ( tess.skipTangents ) + { + for ( uint32_t j = i; j <= i + 4; j++ ) + { + shaderVertex_t v = tess.vertsBuffer[ j ]; + float d = DotProduct( projection.normal, v.xyz ) - projection.dist; + VectorMA( v.xyz, d, minorAxisReplace, v.xyz ); + tess.verts[ j ] = v; + } + } + else + { + i16vec4_t qtangents; + vec3_t normal; + CrossProduct( newMinorAxis, sides[ 1 ].vector, normal ); + if ( DotProduct( normal, forward ) > 0 ) + { + VectorNegate( normal, normal ); } - orientation[ 3 ] = -lengths[ k ]; + VectorNormalize( normal ); + // What the fuck are tangent and binormal even for? + // I'll just put in zeroes and let R_TBNtoQtangents make some up for me. + R_TBNtoQtangents( vec3_origin, vec3_origin, normal, qtangents ); - floatToHalf( orientation, v1->spriteOrientation ); - VectorCopy( mid[ k ], v1->xyz ); + for ( uint32_t j = i; j <= i + 4; j++ ) + { + shaderVertex_t v = tess.vertsBuffer[ j ]; + float d = DotProduct( projection.normal, v.xyz ) - projection.dist; + VectorMA( v.xyz, d, minorAxisReplace, v.xyz ); + Vector4Copy( qtangents, v.qtangents ); + tess.verts[ j ] = v; + } } } } @@ -681,24 +650,46 @@ static void Autosprite2Deform( int firstVertex, int numVertexes, int numIndexes ===================== Tess_AutospriteDeform -Set up vertices to be decoded by the vertexSprite_vp shader. -The ComputeCorner function used in here encodes information in the sign of the lightmap -coordinates, so it only works if there are positive lightmap tc's. Thus it does -not work on anything besides BSP surfaces. ===================== */ -void Tess_AutospriteDeform( int mode, int firstVertex, int numVertexes, - int firstIndex, int numIndexes ) +void Tess_AutospriteDeform( int mode ) { - (void)firstIndex; + if ( tess.verts != tess.vertsBuffer ) + { + Log::Warn( "Tess_AutospriteDeform: CPU vertex buffer not active" ); + return; + } + + uint32_t numVertexes = tess.numVertexes; + uint32_t numIndexes = tess.numIndexes; + + // Tess_MapVBOs( true ) should have been called previously. Now we take the original verts from + // the CPU-only buffer and write the rotated verts to the shared GPU buffer. (If the GPU buffer + // is not supported, the source and dest buffers are the same.) + Tess_Clear(); + Tess_MapVBOs( false ); + + if ( numVertexes & 3 ) + { + Log::Warn( "Autosprite shader %s had odd vertex count", tess.surfaceShader->name ); + return; // drop vertexes + } + + if ( numIndexes != ( numVertexes >> 2 ) * 6 ) + { + Log::Warn( "Autosprite shader %s had odd index count", tess.surfaceShader->name ); + return; // drop vertexes + } switch( mode ) { case 1: - AutospriteDeform( firstVertex, numVertexes, numIndexes ); + AutospriteDeform( numVertexes ); break; case 2: - Autosprite2Deform( firstVertex, numVertexes, numIndexes ); + Autosprite2Deform( numVertexes ); break; + default: + ASSERT_UNREACHABLE(); } } diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 1e81cddcfa..4b2bc1efee 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -6305,10 +6305,6 @@ shader_t *R_FindShader( const char *name, shaderType_t type, implicitCullType = CT_FRONT_SIDED; } - if( flags & RSF_SPRITE ) { - shader.autoSpriteMode = 1; - } - // attempt to define shader from an explicit parameter file shaderText = FindShaderInShaderText( strippedName ); diff --git a/src/engine/renderer/tr_surface.cpp b/src/engine/renderer/tr_surface.cpp index 43868ac361..2a4c061419 100644 --- a/src/engine/renderer/tr_surface.cpp +++ b/src/engine/renderer/tr_surface.cpp @@ -410,46 +410,6 @@ void Tess_AddQuadStamp2WithNormals( vec4_t quadVerts[ 4 ], const Color::Color& c Tess_AddQuadStampExt2( quadVerts, color, 0, 0, 1, 1 ); } -// Defines ATTR_POSITION, ATTR_COLOR, ATTR_TEXCOORD, ATTR_ORIENTATION -void Tess_AddSprite( const vec3_t center, const Color::Color32Bit color, float radius, float rotation ) -{ - int i; - int ndx; - - GLimp_LogComment( "--- Tess_AddSprite ---\n" ); - - Tess_CheckOverflow( 4, 6 ); - - ndx = tess.numVertexes; - - // triangle indexes for a simple quad - tess.indexes[ tess.numIndexes ] = ndx; - tess.indexes[ tess.numIndexes + 1 ] = ndx + 1; - tess.indexes[ tess.numIndexes + 2 ] = ndx + 3; - - tess.indexes[ tess.numIndexes + 3 ] = ndx + 3; - tess.indexes[ tess.numIndexes + 4 ] = ndx + 1; - tess.indexes[ tess.numIndexes + 5 ] = ndx + 2; - - for ( i = 0; i < 4; i++ ) - { - vec4_t texCoord; - vec4_t orientation; - - Vector4Set( texCoord, 0.5f * (i & 2), 0.5f * ( (i + 1) & 2 ), - (i & 2) - 1.0f, ( (i + 1) & 2 ) - 1.0f ); - - VectorCopy( center, tess.verts[ ndx + i ].xyz ); - tess.verts[ ndx + i ].color = color; - floatToHalf( texCoord, tess.verts[ ndx + i ].texCoords ); - Vector4Set( orientation, rotation, 0.0f, 0.0f, radius ); - floatToHalf( orientation, tess.verts[ ndx + i ].spriteOrientation ); - } - - tess.numVertexes += 4; - tess.numIndexes += 6; -} - // Defines ATTR_POSITION, ATTR_COLOR void Tess_AddTetrahedron( vec4_t tetraVerts[ 4 ], const Color::Color& colorf ) { @@ -628,16 +588,12 @@ static void Tess_SurfaceSprite() radius = backEnd.currentEntity->e.radius; - if( tess.surfaceShader->autoSpriteMode == 1 ) { - // the calculations are done in GLSL shader - // FIXME why does this need a different codepath (other than to cope with USE_VERTEX_SPRITE - // shader variants being selected?) Aren't the semantics of deformvertexes autosprite the - // same as those of RT_SPRITE? - - Tess_AddSprite( backEnd.currentEntity->e.origin, - backEnd.currentEntity->e.shaderRGBA, - radius, backEnd.currentEntity->e.rotation ); - return; + if ( tess.surfaceShader->autoSpriteMode != 0 ) + { + // This function does similarly to autosprite mode 1. Autospriting it again would be a + // waste and would probably lose the rotation angle + Log::Warn( "RT_SPRITE entity should NOT configure its shader (%s) as autosprite", + tess.surfaceShader->name ); } VectorSubtract( backEnd.currentEntity->e.origin, backEnd.viewParms.pvsOrigin, delta ); diff --git a/src/engine/renderer/tr_vbo.cpp b/src/engine/renderer/tr_vbo.cpp index 74940b7550..60abb87f59 100644 --- a/src/engine/renderer/tr_vbo.cpp +++ b/src/engine/renderer/tr_vbo.cpp @@ -210,13 +210,6 @@ static void R_SetAttributeLayoutsStatic( VBO_t *vbo ) vbo->attribs[ ATTR_INDEX_TEXCOORD ].stride = sizeShaderVertex; vbo->attribs[ ATTR_INDEX_TEXCOORD ].frameOffset = 0; - vbo->attribs[ ATTR_INDEX_ORIENTATION ].numComponents = 4; - vbo->attribs[ ATTR_INDEX_ORIENTATION ].componentType = GL_HALF_FLOAT; - vbo->attribs[ ATTR_INDEX_ORIENTATION ].normalize = GL_FALSE; - vbo->attribs[ ATTR_INDEX_ORIENTATION ].ofs = offsetof( shaderVertex_t, spriteOrientation ); - vbo->attribs[ ATTR_INDEX_ORIENTATION ].stride = sizeShaderVertex; - vbo->attribs[ ATTR_INDEX_ORIENTATION ].frameOffset = 0; - // total size vbo->vertexesSize = sizeShaderVertex * vbo->vertexesNum; } @@ -1007,9 +1000,7 @@ R_InitVBOs */ void R_InitVBOs() { - // ATTR_QTANGENT and ATTR_ORIENTATION are mutually exclusive, but we don't know in advance - // which attributes will be used as this buffer is used for many purposes. - uint32_t attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_ORIENTATION | ATTR_COLOR; + uint32_t attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_COLOR; Log::Debug("------- R_InitVBOs -------" ); From d440b4fdce7deef4bdecef9b8ff8858aefa7ecc1 Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 6 Sep 2024 20:56:32 -0500 Subject: [PATCH 4/4] Make particles face in view direction (not toward viewer) Make RT_SPRITE entities whose shaders were registered with RSF_SPRITE face opposite the view direction, instead of toward the viewer. This prevents pathological cases where the normal of a closeby sprite is oriented nearly orthogonally to the view direction, making its 2-D nature obvious and ugly. I found that to happen with the alien evolve acid particle system if I walked backward right after evolving from Dretch to Mantis. RT_SPRITE entities without the RSF_SPRITE shader flag continue to face toward the viewer. Light flares go in this category. --- src/engine/renderer/tr_local.h | 3 +++ src/engine/renderer/tr_shader.cpp | 5 +++++ src/engine/renderer/tr_surface.cpp | 23 +++++++++++++++++++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 99e1b1c030..bc85d49bc8 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1293,6 +1293,9 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; bool interactLight; // this shader can interact with light shaders + // For RT_SPRITE, face opposing the view direction rather than the viewer + bool entitySpriteFaceViewDirection; + int autoSpriteMode; uint8_t numDeforms; diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 4b2bc1efee..32c802565d 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -6305,6 +6305,11 @@ shader_t *R_FindShader( const char *name, shaderType_t type, implicitCullType = CT_FRONT_SIDED; } + if ( flags & RSF_SPRITE ) + { + shader.entitySpriteFaceViewDirection = true; + } + // attempt to define shader from an explicit parameter file shaderText = FindShaderInShaderText( strippedName ); diff --git a/src/engine/renderer/tr_surface.cpp b/src/engine/renderer/tr_surface.cpp index 2a4c061419..e4fb229114 100644 --- a/src/engine/renderer/tr_surface.cpp +++ b/src/engine/renderer/tr_surface.cpp @@ -596,20 +596,35 @@ static void Tess_SurfaceSprite() tess.surfaceShader->name ); } - VectorSubtract( backEnd.currentEntity->e.origin, backEnd.viewParms.pvsOrigin, delta ); + VectorSubtract( backEnd.currentEntity->e.origin, backEnd.viewParms.orientation.origin, delta ); if( VectorNormalize( delta ) < NORMAL_EPSILON ) return; - CrossProduct( backEnd.viewParms.orientation.axis[ 2 ], delta, left ); + vec3_t forward; + if ( tess.surfaceShader->entitySpriteFaceViewDirection ) + { + // Face opposite to view direction, triggered by RSF_SPRITE. + // Good for particles that may appear very close to the viewer and thus have extreme + // difference between the view direction and the direction to the viewer, so + // as to avoid cases where they appear obviously planar + VectorCopy( backEnd.viewParms.orientation.axis[ 0 ], forward ); + } + else + { + // Face toward viewer. Used by light flares + VectorCopy( delta, forward ); + } + + CrossProduct( backEnd.viewParms.orientation.axis[ 2 ], forward, left ); if( VectorNormalize( left ) < NORMAL_EPSILON ) VectorSet( left, 1, 0, 0 ); if( backEnd.currentEntity->e.rotation != 0 ) - RotatePointAroundVector( left, delta, left, backEnd.currentEntity->e.rotation ); + RotatePointAroundVector( left, forward, left, backEnd.currentEntity->e.rotation ); - CrossProduct( delta, left, up ); + CrossProduct( forward, left, up ); VectorScale( left, radius, left ); VectorScale( up, radius, up );