From df158a5090f657be51f01d7d0fa7da786263529e Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 13 Mar 2026 07:05:45 +0100 Subject: [PATCH 1/2] Viewer: Improve near/far clipping plane calculation Iterate per-model bounding boxes and skip models outside the camera frustum to prevent distant off-screen objects from inflating the far plane. This improves depth buffer precision and reduces z-fighting. Enforce a maximum far/near ratio of 3000.0 by pushing the near plane forward if necessary. Additionally, refine the near plane adjustment when zooming into a point of interest to prevent geometry clipping. --- Fwk/AppFwk/cafViewer/cafViewer.cpp | 73 ++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 3ba95957d4a..096772ff414 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -509,32 +509,56 @@ bool caf::Viewer::calculateNearFarPlanes( const cvf::Rendering* rendering, double* farPlaneDist, double* nearPlaneDist ) { - cvf::BoundingBox bb = rendering->boundingBox(); - - if ( !bb.isValid() ) return false; + if ( !rendering->boundingBox().isValid() ) return false; cvf::Vec3d eye = rendering->camera()->position(); cvf::Vec3d viewdir = rendering->camera()->direction(); - cvf::Vec3d bboxCorners[8]; - bb.cornerVertices( bboxCorners ); - - // Find the distance to the bbox corners most behind and most in front of camera + // Iterate per-model bounding boxes and skip models that are entirely outside the + // camera frustum. This avoids distant off-screen objects inflating the far plane, + // which would degrade depth buffer precision and cause z-fighting. + // Fall back to the scene-wide bounding box if no model contributes. double maxDistEyeToCornerAlongViewDir = -HUGE_VAL; double minDistEyeToCornerAlongViewDir = HUGE_VAL; - for ( int bcIdx = 0; bcIdx < 8; ++bcIdx ) - { - double distEyeBoxCornerAlongViewDir = ( bboxCorners[bcIdx] - eye ) * viewdir; - if ( distEyeBoxCornerAlongViewDir > maxDistEyeToCornerAlongViewDir ) + cvf::Frustum viewFrustum = rendering->camera()->frustum(); + const cvf::Scene* scene = rendering->scene(); + bool anyModelContributed = false; + + if ( scene ) + { + for ( cvf::uint mIdx = 0; mIdx < scene->modelCount(); ++mIdx ) { - maxDistEyeToCornerAlongViewDir = distEyeBoxCornerAlongViewDir; + const cvf::Model* model = scene->model( mIdx ); + cvf::BoundingBox modelBB = model->boundingBox(); + + if ( !modelBB.isValid() ) continue; + if ( viewFrustum.isOutside( modelBB ) ) continue; + + cvf::Vec3d corners[8]; + modelBB.cornerVertices( corners ); + for ( int cIdx = 0; cIdx < 8; ++cIdx ) + { + double dist = ( corners[cIdx] - eye ) * viewdir; + maxDistEyeToCornerAlongViewDir = CVF_MAX( maxDistEyeToCornerAlongViewDir, dist ); + minDistEyeToCornerAlongViewDir = CVF_MIN( minDistEyeToCornerAlongViewDir, dist ); + } + anyModelContributed = true; } + } - if ( distEyeBoxCornerAlongViewDir < minDistEyeToCornerAlongViewDir ) + if ( !anyModelContributed ) + { + // Fallback: use the scene-wide bounding box (original behaviour) + cvf::BoundingBox bb = rendering->boundingBox(); + cvf::Vec3d bboxCorners[8]; + bb.cornerVertices( bboxCorners ); + for ( int bcIdx = 0; bcIdx < 8; ++bcIdx ) { - minDistEyeToCornerAlongViewDir = distEyeBoxCornerAlongViewDir; // Sometimes negative-> behind camera + double dist = ( bboxCorners[bcIdx] - eye ) * viewdir; + maxDistEyeToCornerAlongViewDir = CVF_MAX( maxDistEyeToCornerAlongViewDir, dist ); + minDistEyeToCornerAlongViewDir = CVF_MIN( minDistEyeToCornerAlongViewDir, dist ); } } @@ -548,16 +572,16 @@ bool caf::Viewer::calculateNearFarPlanes( const cvf::Rendering* rendering, if ( rendering->camera()->projection() == cvf::Camera::PERSPECTIVE || isOrthoNearPlaneFollowingCamera ) { - // Choose the one furthest from the camera of: 0.8*bbox distance, m_minPerspectiveNearPlaneDistance. + // Choose the one furthest from the camera of: 0.8*bbox distance, m_defaultPerspectiveNearPlaneDistance. ( *nearPlaneDist ) = CVF_MAX( m_defaultPerspectiveNearPlaneDistance, 0.8 * minDistEyeToCornerAlongViewDir ); - // If we are zooming into a detail, allow the near-plane to move towards camera beyond the - // m_minPerspectiveNearPlaneDistance - if ( ( *nearPlaneDist ) == m_defaultPerspectiveNearPlaneDistance // We are inside the bounding box - && m_navigationPolicy.notNull() && m_navigationPolicyEnabled ) + // If the camera is inside (or past) the bounding box, allow the near plane to move + // closer to the camera based on the point of interest distance, so zooming into details + // does not clip geometry. + if ( minDistEyeToCornerAlongViewDir <= 0 && m_navigationPolicy.notNull() && m_navigationPolicyEnabled ) { double pointOfInterestDist = ( eye - navPointOfinterest ).length(); - ( *nearPlaneDist ) = CVF_MIN( ( *nearPlaneDist ), pointOfInterestDist * 0.2 ); + ( *nearPlaneDist ) = CVF_MAX( m_defaultPerspectiveNearPlaneDistance, pointOfInterestDist * 0.1 ); } // Guard against the zero nearplane possibility @@ -577,6 +601,15 @@ bool caf::Viewer::calculateNearFarPlanes( const cvf::Rendering* rendering, if ( ( *farPlaneDist ) <= ( *nearPlaneDist ) ) ( *farPlaneDist ) = ( *nearPlaneDist ) + 1.0; + // Enforce a maximum far/near ratio to preserve depth buffer precision. + // A 24-bit depth buffer loses effective precision rapidly as far/near grows. + // Pushing the near plane forward is preferable to allowing z-fighting. + const double maxFarNearRatio = 3000.0; + if ( ( *nearPlaneDist ) > 0 && ( ( *farPlaneDist ) / ( *nearPlaneDist ) ) > maxFarNearRatio ) + { + ( *nearPlaneDist ) = ( *farPlaneDist ) / maxFarNearRatio; + } + return true; } From f943519245b8c16766786d82c27523b75cc1a559 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 13 Mar 2026 16:26:52 +0100 Subject: [PATCH 2/2] Viewer: Add logarithmic depth buffer to eliminate z-fighting Implements the Outerra logarithmic depth buffer method to fix z-fighting caused by poor depth precision when the far/near plane ratio is large. - Add vs_logDepth.glsl / fs_logDepth.glsl components; ShaderProgramGenerator auto-injects them into all 3D shader programs (screen-space programs opt out via setInjectLogDepth(false)) - All 3D vertex shaders call calcLogDepth(gl_Position) to store v_logz; all 3D fragment shaders call applyLogDepth() to write gl_FragDepth - In orthographic mode u_useLogDepth=0 causes applyLogDepth() to fall back to gl_FragCoord.z so depth works correctly without perspective w_clip - glPolygonOffset is bypassed when gl_FragDepth is written explicitly; replace with manual GLSL implementation using dFdx/dFdy slope derivatives and u_polygonOffsetFactor/Units uniforms mirroring the GL state - GlobalViewerDynUniformSet provides u_logDepthFC and u_useLogDepth as per-frame globals; shader programs get zero polygon offset defaults so the uniforms are always satisfied even without explicit polygon offset - Fix vs_CellFace.glsl and vs_2dTextureCellFace.glsl which were missing the calcLogDepth hook, causing undefined v_logz and incorrect depth writes that hid side faces and broke mesh line visibility --- .../Resources/vs_2dTextureCellFace.glsl | 3 + ApplicationExeCode/Resources/vs_CellFace.glsl | 3 + .../RivExtrudedCurveIntersectionPartMgr.cpp | 18 ++- .../RivCellEdgeEffectGenerator.cpp | 9 +- .../RivTernaryScalarMapperEffectGenerator.cpp | 6 +- .../Seismic/RivSeismicSectionPartMgr.cpp | 10 +- Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp | 52 +++++-- Fwk/AppFwk/CommonCode/cafEffectGenerator.h | 4 + Fwk/AppFwk/cafViewer/cafViewer.cpp | 28 +++- .../cafTransparentWBRenderConfiguration.cpp | 7 +- .../LibRender/cvfShaderProgramGenerator.cpp | 49 ++++++- .../LibRender/cvfShaderProgramGenerator.h | 2 + .../LibRender/cvfShaderSourceRepository.cpp | 8 ++ .../LibRender/cvfShaderSourceRepository.h | 4 + Fwk/VizFwk/LibRender/cvfShaderSourceStrings.h | 129 ++++++++++++++++++ .../glsl/fs_CenterLitSpherePoints.glsl | 4 + .../LibRender/glsl/fs_FixedColorMagenta.glsl | 4 + .../glsl/fs_HighlightStencilDraw.glsl | 4 + .../glsl/fs_ParticleTraceComets.glsl | 4 + Fwk/VizFwk/LibRender/glsl/fs_Standard.glsl | 4 + Fwk/VizFwk/LibRender/glsl/fs_Text.glsl | 4 + Fwk/VizFwk/LibRender/glsl/fs_Unlit.glsl | 4 + .../LibRender/glsl/fs_VectorDrawer.glsl | 4 + Fwk/VizFwk/LibRender/glsl/fs_logDepth.glsl | 43 ++++++ .../glsl/vs_DistanceScaledPoints.glsl | 4 + .../LibRender/glsl/vs_EnvironmentMapping.glsl | 4 + Fwk/VizFwk/LibRender/glsl/vs_Minimal.glsl | 4 + .../LibRender/glsl/vs_MinimalTexture.glsl | 4 + .../glsl/vs_ParticleTraceComets.glsl | 4 + Fwk/VizFwk/LibRender/glsl/vs_Standard.glsl | 4 + .../LibRender/glsl/vs_VectorDrawer.glsl | 4 + Fwk/VizFwk/LibRender/glsl/vs_logDepth.glsl | 14 ++ .../cvfSingleQuadRenderingGenerator.cpp | 3 +- 33 files changed, 405 insertions(+), 47 deletions(-) create mode 100644 Fwk/VizFwk/LibRender/glsl/fs_logDepth.glsl create mode 100644 Fwk/VizFwk/LibRender/glsl/vs_logDepth.glsl diff --git a/ApplicationExeCode/Resources/vs_2dTextureCellFace.glsl b/ApplicationExeCode/Resources/vs_2dTextureCellFace.glsl index a42ba28a432..59a80e7a48d 100644 --- a/ApplicationExeCode/Resources/vs_2dTextureCellFace.glsl +++ b/ApplicationExeCode/Resources/vs_2dTextureCellFace.glsl @@ -126,5 +126,8 @@ void main() v_ecNormal = cvfu_normalMatrix * cvfa_normal; gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; +#ifdef CVF_LOG_DEPTH_IMPL + calcLogDepth(gl_Position); +#endif } diff --git a/ApplicationExeCode/Resources/vs_CellFace.glsl b/ApplicationExeCode/Resources/vs_CellFace.glsl index c638cc038b4..4e3f021fdc9 100644 --- a/ApplicationExeCode/Resources/vs_CellFace.glsl +++ b/ApplicationExeCode/Resources/vs_CellFace.glsl @@ -177,5 +177,8 @@ void main() v_ecNormal = cvfu_normalMatrix * cvfa_normal; gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; +#ifdef CVF_LOG_DEPTH_IMPL + calcLogDepth(gl_Position); +#endif } diff --git a/ApplicationLibCode/ModelVisualization/Intersections/RivExtrudedCurveIntersectionPartMgr.cpp b/ApplicationLibCode/ModelVisualization/Intersections/RivExtrudedCurveIntersectionPartMgr.cpp index 233cd7b7243..fe2b9d3586f 100644 --- a/ApplicationLibCode/ModelVisualization/Intersections/RivExtrudedCurveIntersectionPartMgr.cpp +++ b/ApplicationLibCode/ModelVisualization/Intersections/RivExtrudedCurveIntersectionPartMgr.cpp @@ -82,6 +82,7 @@ #include "cvfRenderState_FF.h" #include "cvfStructGridGeometryGenerator.h" #include "cvfTransform.h" +#include "cvfUniform.h" #include "cvfqtUtils.h" #include @@ -711,12 +712,14 @@ void RivExtrudedCurveIntersectionPartMgr::createAnnotationSurfaceParts( bool use // The factor value is defined by enums in // EffectGenerator::createAndConfigurePolygonOffsetRenderState() Use a factor that is more negative // than the existing enums - const double offsetFactor = -5; + const float offsetFactor = -5.0f; + const float offsetUnits = static_cast( band->polygonOffsetUnit() ); polyOffset->setFactor( offsetFactor ); - - polyOffset->setUnits( band->polygonOffsetUnit() ); + polyOffset->setUnits( offsetUnits ); geometryOnlyEffect->setRenderState( polyOffset.p() ); + geometryOnlyEffect->setUniform( new cvf::UniformFloat( "u_polygonOffsetFactor", offsetFactor ) ); + geometryOnlyEffect->setUniform( new cvf::UniformFloat( "u_polygonOffsetUnits", offsetUnits ) ); } part->setEffect( geometryOnlyEffect.p() ); @@ -759,11 +762,14 @@ cvf::ref RivExtrudedCurveIntersectionPartMgr::createCurvePart( const cvf::ref polyOffset = new cvf::RenderStatePolygonOffset; polyOffset->enableFillMode( true ); - polyOffset->setFactor( -5 ); - const double maxOffsetFactor = -1000; - polyOffset->setUnits( maxOffsetFactor ); + const float lineFactor = -5.0f; + const float lineUnits = -1000.0f; + polyOffset->setFactor( lineFactor ); + polyOffset->setUnits( lineUnits ); eff->setRenderState( polyOffset.p() ); + eff->setUniform( new cvf::UniformFloat( "u_polygonOffsetFactor", lineFactor ) ); + eff->setUniform( new cvf::UniformFloat( "u_polygonOffsetUnits", lineUnits ) ); part->setEffect( eff.p() ); diff --git a/ApplicationLibCode/ModelVisualization/RivCellEdgeEffectGenerator.cpp b/ApplicationLibCode/ModelVisualization/RivCellEdgeEffectGenerator.cpp index 5e3fcad7fba..3cc73e3cb91 100644 --- a/ApplicationLibCode/ModelVisualization/RivCellEdgeEffectGenerator.cpp +++ b/ApplicationLibCode/ModelVisualization/RivCellEdgeEffectGenerator.cpp @@ -273,13 +273,8 @@ void CellEdgeEffectGenerator::updateForShaderBasedRendering( cvf::Effect* effect texBind->addBinding( cellTexture.p(), sampler.p(), "u_cellTexture2D" ); eff->setRenderState( texBind.p() ); - // Polygon offset - - { - cvf::ref polyOffset = new cvf::RenderStatePolygonOffset; - polyOffset->configurePolygonPositiveOffset(); - eff->setRenderState( polyOffset.p() ); - } + // Polygon offset (render state + shader uniforms for log-depth compatibility) + EffectGenerator::applyPolygonOffset( eff.p(), caf::PO_1 ); // Simple transparency if ( m_opacityLevel < 1.0f ) diff --git a/ApplicationLibCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.cpp b/ApplicationLibCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.cpp index 8e013a8830e..c0feb4771f9 100644 --- a/ApplicationLibCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.cpp +++ b/ApplicationLibCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.cpp @@ -185,11 +185,7 @@ void RivTernaryScalarMapperEffectGenerator::updateCommonEffect( cvf::Effect* eff { CVF_ASSERT( effect ); - if ( m_polygonOffset != caf::PO_NONE ) - { - cvf::ref polyOffset = EffectGenerator::createAndConfigurePolygonOffsetRenderState( m_polygonOffset ); - effect->setRenderState( polyOffset.p() ); - } + EffectGenerator::applyPolygonOffset( effect, m_polygonOffset ); // Simple transparency if ( m_opacityLevel < 1.0f ) diff --git a/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.cpp b/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.cpp index 29372586333..301e875d3ed 100644 --- a/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.cpp +++ b/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.cpp @@ -49,6 +49,7 @@ #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfScalarMapper.h" +#include "cvfUniform.h" #include @@ -243,11 +244,14 @@ void RivSeismicSectionPartMgr::appendSurfaceIntersectionLines( cvf::ModelBasicLi cvf::ref polyOffset = new cvf::RenderStatePolygonOffset; polyOffset->enableFillMode( true ); - polyOffset->setFactor( -5 ); - const double maxOffsetFactor = -1000; - polyOffset->setUnits( maxOffsetFactor ); + const float lineFactor = -5.0f; + const float lineUnits = -1000.0f; + polyOffset->setFactor( lineFactor ); + polyOffset->setUnits( lineUnits ); eff->setRenderState( polyOffset.p() ); + eff->setUniform( new cvf::UniformFloat( "u_polygonOffsetFactor", lineFactor ) ); + eff->setUniform( new cvf::UniformFloat( "u_polygonOffsetUnits", lineUnits ) ); part->setEffect( eff.p() ); part->setPriority( RivPartPriority::PartType::MeshLines ); diff --git a/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp b/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp index a48f31936af..811a0503ad0 100644 --- a/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp +++ b/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp @@ -154,6 +154,44 @@ cvf::ref return rs; } +//-------------------------------------------------------------------------------------------------- +/// Sets both the GL polygon offset render state and the equivalent shader uniforms. +/// glPolygonOffset has no effect when gl_FragDepth is written explicitly (as in log-depth +/// rendering), so the uniforms are required for correct depth ordering in that mode. +//-------------------------------------------------------------------------------------------------- +void EffectGenerator::applyPolygonOffset( cvf::Effect* effect, PolygonOffset polygonOffset ) +{ + if ( polygonOffset == PO_NONE ) return; + + effect->setRenderState( createAndConfigurePolygonOffsetRenderState( polygonOffset ).p() ); + + float factor = 0.0f, units = 0.0f; + switch ( polygonOffset ) + { + case PO_1: + factor = 1.0f; + units = 1.0f; + break; + case PO_2: + factor = 2.0f; + units = 2.0f; + break; + case PO_POS_LARGE: + factor = 3.0f; + units = 50.0f; + break; + case PO_NEG_LARGE: + factor = -1.0f; + units = -30.0f; + break; + default: + CVF_FAIL_MSG( "Unhandled polygon offset enum" ); + return; + } + effect->setUniform( new cvf::UniformFloat( "u_polygonOffsetFactor", factor ) ); + effect->setUniform( new cvf::UniformFloat( "u_polygonOffsetUnits", units ) ); +} + //================================================================================================== // // EffectGenerator Base class @@ -347,12 +385,7 @@ void SurfaceEffectGenerator::updateForFixedFunctionRendering( cvf::Effect* effec //-------------------------------------------------------------------------------------------------- void SurfaceEffectGenerator::updateCommonEffect( cvf::Effect* effect ) const { - if ( m_polygonOffset != PO_NONE ) - { - cvf::ref polyOffset = - EffectGenerator::createAndConfigurePolygonOffsetRenderState( m_polygonOffset ); - effect->setRenderState( polyOffset.p() ); - } + EffectGenerator::applyPolygonOffset( effect, m_polygonOffset ); // Simple transparency if ( m_color.a() < 1.0f ) @@ -553,12 +586,7 @@ void ScalarMapperEffectGenerator::updateCommonEffect( cvf::Effect* effect ) cons { CVF_ASSERT( effect ); - if ( m_polygonOffset != PO_NONE ) - { - cvf::ref polyOffset = - EffectGenerator::createAndConfigurePolygonOffsetRenderState( m_polygonOffset ); - effect->setRenderState( polyOffset.p() ); - } + EffectGenerator::applyPolygonOffset( effect, m_polygonOffset ); // Simple transparency if ( m_opacityLevel < 1.0f ) diff --git a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h index ab8bff38e4f..ad6f2524338 100644 --- a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h +++ b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h @@ -107,6 +107,10 @@ class EffectGenerator static cvf::ref createAndConfigurePolygonOffsetRenderState( caf::PolygonOffset polygonOffset ); + // Sets both the GL polygon offset render state and the shader uniforms needed for log-depth + // rendering (glPolygonOffset is ignored when gl_FragDepth is written explicitly). + static void applyPolygonOffset( cvf::Effect* effect, caf::PolygonOffset polygonOffset ); + protected: // Interface that must be implemented in base classes virtual bool isEqual( const EffectGenerator* other ) const = 0; diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 096772ff414..bcb0841bde7 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -86,8 +86,12 @@ class GlobalViewerDynUniformSet : public cvf::DynamicUniformSet GlobalViewerDynUniformSet() { m_headlightPosition = new cvf::UniformFloat( "u_ecLightPosition", cvf::Vec3f( 0.5, 5.0, 7.0 ) ); + m_logDepthFC = new cvf::UniformFloat( "u_logDepthFC", 1.0f ); + m_useLogDepth = new cvf::UniformFloat( "u_useLogDepth", 1.0f ); m_uniformSet = new cvf::UniformSet(); m_uniformSet->setUniform( m_headlightPosition.p() ); + m_uniformSet->setUniform( m_logDepthFC.p() ); + m_uniformSet->setUniform( m_useLogDepth.p() ); } ~GlobalViewerDynUniformSet() override {} @@ -97,12 +101,20 @@ class GlobalViewerDynUniformSet : public cvf::DynamicUniformSet m_headlightPosition->set( posRelativeToCamera ); } + // FC = 2.0 / log2(farPlane + 1.0) — update each frame after clip plane calculation + void setLogDepthFarConstant( float fc ) { m_logDepthFC->set( fc ); } + + // Enable (1.0) for perspective projection, disable (0.0) for orthographic + void setUseLogDepth( float use ) { m_useLogDepth->set( use ); } + cvf::UniformSet* uniformSet() override { return m_uniformSet.p(); } void update( cvf::Rendering* rendering ) override {}; private: cvf::ref m_uniformSet; cvf::ref m_headlightPosition; + cvf::ref m_logDepthFC; + cvf::ref m_useLogDepth; }; } // namespace caf @@ -468,6 +480,14 @@ void caf::Viewer::optimizeClippingPlanes() { m_mainCamera->setProjectionAsOrtho( m_mainCamera->frontPlaneFrustumHeight(), nearPlaneDist, farPlaneDist ); } + + // Update the logarithmic depth buffer constant: FC = 2 / log2(far + 1). + // Shaders use this to compute gl_FragDepth = log2(v_logz) * FC * 0.5. + // Log depth only works for perspective; orthographic uses linear depth. + const bool isPerspective = ( m_mainCamera->projection() == cvf::Camera::PERSPECTIVE ); + float logDepthFC = static_cast( 2.0 / std::log2( farPlaneDist + 1.0 ) ); + m_globalUniformSet->setLogDepthFarConstant( logDepthFC ); + m_globalUniformSet->setUseLogDepth( isPerspective ? 1.0f : 0.0f ); } copyCameraView( m_mainCamera.p(), m_comparisonMainCamera.p() ); @@ -522,9 +542,9 @@ bool caf::Viewer::calculateNearFarPlanes( const cvf::Rendering* rendering, double maxDistEyeToCornerAlongViewDir = -HUGE_VAL; double minDistEyeToCornerAlongViewDir = HUGE_VAL; - cvf::Frustum viewFrustum = rendering->camera()->frustum(); - const cvf::Scene* scene = rendering->scene(); - bool anyModelContributed = false; + cvf::Frustum viewFrustum = rendering->camera()->frustum(); + const cvf::Scene* scene = rendering->scene(); + bool anyModelContributed = false; if ( scene ) { @@ -540,7 +560,7 @@ bool caf::Viewer::calculateNearFarPlanes( const cvf::Rendering* rendering, modelBB.cornerVertices( corners ); for ( int cIdx = 0; cIdx < 8; ++cIdx ) { - double dist = ( corners[cIdx] - eye ) * viewdir; + double dist = ( corners[cIdx] - eye ) * viewdir; maxDistEyeToCornerAlongViewDir = CVF_MAX( maxDistEyeToCornerAlongViewDir, dist ); minDistEyeToCornerAlongViewDir = CVF_MIN( minDistEyeToCornerAlongViewDir, dist ); } diff --git a/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.cpp b/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.cpp index cd7788728f0..3769e945bf8 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.cpp +++ b/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.cpp @@ -542,12 +542,7 @@ void WBTransparencySurfaceEffectGenerator::updateForFixedFunctionRendering( cvf: //-------------------------------------------------------------------------------------------------- void WBTransparencySurfaceEffectGenerator::updateCommonEffect( cvf::Effect* effect ) const { - if ( m_polygonOffset != PO_NONE ) - { - cvf::ref polyOffset = - EffectGenerator::createAndConfigurePolygonOffsetRenderState( m_polygonOffset ); - effect->setRenderState( polyOffset.p() ); - } + EffectGenerator::applyPolygonOffset( effect, m_polygonOffset ); if ( m_color.a() < 1.0f ) { diff --git a/Fwk/VizFwk/LibRender/cvfShaderProgramGenerator.cpp b/Fwk/VizFwk/LibRender/cvfShaderProgramGenerator.cpp index 5cd7c8b51e6..d61b0c963df 100644 --- a/Fwk/VizFwk/LibRender/cvfShaderProgramGenerator.cpp +++ b/Fwk/VizFwk/LibRender/cvfShaderProgramGenerator.cpp @@ -39,6 +39,7 @@ #include "cvfShaderProgramGenerator.h" #include "cvfShaderProgram.h" #include "cvfShaderSourceProvider.h" +#include "cvfUniform.h" #include "cvfMath.h" namespace cvf { @@ -61,6 +62,7 @@ ShaderProgramGenerator::ShaderProgramGenerator(String shaderProgramName, ShaderS CVF_ASSERT(sourceProvider); m_sourceProvider = sourceProvider; m_shaderProgramName = shaderProgramName; + m_injectLogDepth = true; } @@ -140,7 +142,16 @@ void ShaderProgramGenerator::addFragmentCodeFromFile(String shaderName) //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void ShaderProgramGenerator::setInjectLogDepth(bool inject) +{ + m_injectLogDepth = inject; +} + + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void ShaderProgramGenerator::configureStandardHeadlightColor() { @@ -170,8 +181,29 @@ ref ShaderProgramGenerator::generate() { CVF_ASSERT((!m_vertexCodes.empty()) && (!m_fragmentCodes.empty())); - ShaderSourceCombiner vertexCombiner(m_vertexCodes, m_vertexNames); - ShaderSourceCombiner fragmentCombiner(m_fragmentCodes, m_fragmentNames); + std::vector vertexCodes; + std::vector vertexNames; + std::vector fragmentCodes; + std::vector fragmentNames; + + if (m_injectLogDepth) + { + // Prepend the log-depth components so that the CVF_LOG_DEPTH_IMPL #define + // is visible to all vertex/fragment shaders that have the corresponding hooks. + // Screen-space shaders should call setInjectLogDepth(false) to skip this. + vertexCodes.push_back(m_sourceProvider->getSourceFromRepository(ShaderSourceRepository::vs_logDepth)); + vertexNames.push_back("vs_logDepth"); + fragmentCodes.push_back(m_sourceProvider->getSourceFromRepository(ShaderSourceRepository::fs_logDepth)); + fragmentNames.push_back("fs_logDepth"); + } + + vertexCodes.insert(vertexCodes.end(), m_vertexCodes.begin(), m_vertexCodes.end()); + vertexNames.insert(vertexNames.end(), m_vertexNames.begin(), m_vertexNames.end()); + fragmentCodes.insert(fragmentCodes.end(), m_fragmentCodes.begin(), m_fragmentCodes.end()); + fragmentNames.insert(fragmentNames.end(), m_fragmentNames.begin(), m_fragmentNames.end()); + + ShaderSourceCombiner vertexCombiner(vertexCodes, vertexNames); + ShaderSourceCombiner fragmentCombiner(fragmentCodes, fragmentNames); String vertexSource = vertexCombiner.combinedSource(); String fragmentSource = fragmentCombiner.combinedSource(); @@ -185,6 +217,17 @@ ref ShaderProgramGenerator::generate() prog->addShader(vertexShader.p()); prog->addShader(fragmentShader.p()); + if (m_injectLogDepth) + { + // Provide defaults so uniforms are always "set" even when the caller does not + // configure polygon offset or has not yet received the per-frame global uniforms. + // The GlobalViewerDynUniformSet overrides u_logDepthFC and u_useLogDepth each frame. + // Explicit applyPolygonOffset() calls on the effect override the offset defaults. + prog->setDefaultUniform(new UniformFloat("u_useLogDepth", 1.0f)); + prog->setDefaultUniform(new UniformFloat("u_polygonOffsetFactor", 0.0f)); + prog->setDefaultUniform(new UniformFloat("u_polygonOffsetUnits", 0.0f)); + } + if (!m_geometryCodes.empty()) { ShaderSourceCombiner geometryCombiner(m_geometryCodes, m_geometryNames); diff --git a/Fwk/VizFwk/LibRender/cvfShaderProgramGenerator.h b/Fwk/VizFwk/LibRender/cvfShaderProgramGenerator.h index de5ae931e78..e3a422b8e10 100644 --- a/Fwk/VizFwk/LibRender/cvfShaderProgramGenerator.h +++ b/Fwk/VizFwk/LibRender/cvfShaderProgramGenerator.h @@ -68,11 +68,13 @@ class ShaderProgramGenerator void configureStandardHeadlightColor(); void configureStandardHeadlightTexture(); + void setInjectLogDepth(bool inject); ref generate(); private: ShaderSourceProvider* m_sourceProvider; String m_shaderProgramName; + bool m_injectLogDepth; std::vector m_vertexCodes; std::vector m_fragmentCodes; diff --git a/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.cpp b/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.cpp index 2decf3369aa..22023583562 100644 --- a/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.cpp +++ b/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.cpp @@ -123,6 +123,8 @@ const char* ShaderSourceRepository::shaderIdentString(ShaderIdent shaderIdent) CVF_IDENT_HANDLE_CASE(checkDiscard_ClipDistances); + CVF_IDENT_HANDLE_CASE(vs_logDepth); + CVF_IDENT_HANDLE_CASE(vs_Standard); CVF_IDENT_HANDLE_CASE(vs_EnvironmentMapping); CVF_IDENT_HANDLE_CASE(vs_FullScreenQuad); @@ -132,6 +134,8 @@ const char* ShaderSourceRepository::shaderIdentString(ShaderIdent shaderIdent) CVF_IDENT_HANDLE_CASE(vs_DistanceScaledPoints); CVF_IDENT_HANDLE_CASE(vs_ParticleTraceComets); + CVF_IDENT_HANDLE_CASE(fs_logDepth); + CVF_IDENT_HANDLE_CASE(fs_Standard); CVF_IDENT_HANDLE_CASE(fs_Shadow_v33); CVF_IDENT_HANDLE_CASE(fs_Unlit); @@ -184,6 +188,8 @@ bool ShaderSourceRepository::rawShaderSource(ShaderIdent shaderIdent, CharArray* CVF_SOURCE_HANDLE_CASE(checkDiscard_ClipDistances); + CVF_SOURCE_HANDLE_CASE(vs_logDepth); + CVF_SOURCE_HANDLE_CASE(vs_Standard); CVF_SOURCE_HANDLE_CASE(vs_EnvironmentMapping); CVF_SOURCE_HANDLE_CASE(vs_FullScreenQuad); @@ -193,6 +199,8 @@ bool ShaderSourceRepository::rawShaderSource(ShaderIdent shaderIdent, CharArray* CVF_SOURCE_HANDLE_CASE(vs_DistanceScaledPoints); CVF_SOURCE_HANDLE_CASE(vs_ParticleTraceComets); + CVF_SOURCE_HANDLE_CASE(fs_logDepth); + CVF_SOURCE_HANDLE_CASE(fs_Standard); CVF_SOURCE_HANDLE_CASE(fs_Shadow_v33); CVF_SOURCE_HANDLE_CASE(fs_Unlit); diff --git a/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.h b/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.h index bacf13cb42a..fd072b703d4 100644 --- a/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.h +++ b/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.h @@ -73,6 +73,8 @@ class ShaderSourceRepository : public Object checkDiscard_ClipDistances, + vs_logDepth, + vs_Standard, vs_EnvironmentMapping, vs_FullScreenQuad, @@ -82,6 +84,8 @@ class ShaderSourceRepository : public Object vs_DistanceScaledPoints, vs_ParticleTraceComets, + fs_logDepth, + fs_Standard, fs_Shadow_v33, fs_Unlit, diff --git a/Fwk/VizFwk/LibRender/cvfShaderSourceStrings.h b/Fwk/VizFwk/LibRender/cvfShaderSourceStrings.h index 32eb38d77e8..704b6481f26 100644 --- a/Fwk/VizFwk/LibRender/cvfShaderSourceStrings.h +++ b/Fwk/VizFwk/LibRender/cvfShaderSourceStrings.h @@ -122,6 +122,10 @@ static const char fs_CenterLitSpherePoints_inl[] = " gl_FragColor = vec4(color.rgb*diffuse, color.a); \n" " \n" " //gl_FragDepth = gl_FragCoord.z - 15.0*(1.0-mag); \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" applyLogDepth(); \n" +"#endif \n" "} \n"; @@ -136,6 +140,10 @@ static const char fs_FixedColorMagenta_inl[] = "void main() \n" "{ \n" " gl_FragColor = vec4(1,0,1,1); \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" applyLogDepth(); \n" +"#endif \n" "} \n"; @@ -406,6 +414,10 @@ static const char fs_HighlightStencilDraw_inl[] = "void main() \n" "{ \n" " gl_FragData[0] = u_color; \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" applyLogDepth(); \n" +"#endif \n" "} \n"; @@ -435,6 +447,55 @@ static const char fs_HighlightStencilMix_v33_inl[] = +//############################################################################################################################# +//############################################################################################################################# +static const char fs_logDepth_inl[] = +" \n" +"varying float v_logz; \n" +" \n" +"uniform float u_logDepthFC; // = 2.0 / log2(farPlane + 1.0), updated each frame \n" +"uniform float u_useLogDepth; // 1.0 = perspective (log depth), 0.0 = orthographic (linear depth) \n" +"uniform float u_polygonOffsetFactor; // mirrors glPolygonOffset factor (default 0) \n" +"uniform float u_polygonOffsetUnits; // mirrors glPolygonOffset units (default 0) \n" +" \n" +"#define CVF_LOG_DEPTH_IMPL \n" +" \n" +"//-------------------------------------------------------------------------------------------------- \n" +"/// Fragment component - logarithmic depth buffer \n" +"/// Writes a log-distributed depth to gl_FragDepth, replacing the default linear depth. \n" +"/// Requires v_logz to be set by calcLogDepth() in the vertex shader. \n" +"/// \n" +"/// For orthographic projection (u_useLogDepth == 0), falls back to the standard linear \n" +"/// gl_FragCoord.z, since w_clip == 1 in orthographic and log depth gives no benefit. \n" +"/// \n" +"/// Also implements polygon offset manually, because glPolygonOffset has no effect when \n" +"/// gl_FragDepth is written explicitly. Set u_polygonOffsetFactor/Units to mirror the \n" +"/// glPolygonOffset parameters used on the effect. \n" +"/// \n" +"/// Reference: http://outerra.blogspot.com/2013/07/logarithmic-depth-buffer-optimizations.html \n" +"//-------------------------------------------------------------------------------------------------- \n" +"void applyLogDepth() \n" +"{ \n" +" float depth; \n" +" if (u_useLogDepth > 0.5) \n" +" { \n" +" depth = log2(max(1.0e-6, v_logz)) * u_logDepthFC * 0.5; \n" +" } \n" +" else \n" +" { \n" +" depth = gl_FragCoord.z; \n" +" } \n" +" \n" +" // Manual polygon offset: factor * max_slope + units * depth_resolution \n" +" // Resolution constant = 1/2^24 for a 24-bit depth buffer. \n" +" float slope = max(abs(dFdx(depth)), abs(dFdy(depth))); \n" +" depth += u_polygonOffsetFactor * slope + u_polygonOffsetUnits * (1.0 / 16777216.0); \n" +" \n" +" gl_FragDepth = depth; \n" +"} \n"; + + + //############################################################################################################################# //############################################################################################################################# static const char fs_ParticleTraceComets_inl[] = @@ -462,6 +523,10 @@ static const char fs_ParticleTraceComets_inl[] = " \n" " vec3 color = srcFragment().rgb; \n" " gl_FragColor = vec4(color*diffuse, v_alpha); \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" applyLogDepth(); \n" +"#endif \n" "} \n"; @@ -538,6 +603,10 @@ static const char fs_Standard_inl[] = " color = lightFragment(color, 1.0); \n" " \n" " gl_FragColor = color; \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" applyLogDepth(); \n" +"#endif \n" "} \n"; @@ -558,6 +627,10 @@ static const char fs_Text_inl[] = "{ \n" " float alpha = texture2D(u_texture2D, v_texCoord).a; \n" " gl_FragColor = vec4(u_color, alpha); \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" applyLogDepth(); \n" +"#endif \n" "} \n"; @@ -580,6 +653,10 @@ static const char fs_Unlit_inl[] = " vec4 color = srcFragment(); \n" " \n" " gl_FragColor = color; \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" applyLogDepth(); \n" +"#endif \n" "} \n"; @@ -601,6 +678,10 @@ static const char fs_VectorDrawer_inl[] = "#endif \n" " \n" " gl_FragColor = vec4(u_color*v_diffuse, 1.0); \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" applyLogDepth(); \n" +"#endif \n" "} \n"; @@ -957,6 +1038,10 @@ static const char vs_DistanceScaledPoints_inl[] = " \n" " gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; \n" " \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" calcLogDepth(gl_Position); \n" +"#endif \n" +" \n" " // Compute the point diameter in window coords (pixels) \n" " // Scale with distance for perspective correction of the size \n" " float dist = length(v_ecPosition); \n" @@ -1001,6 +1086,10 @@ static const char vs_EnvironmentMapping_inl[] = " \n" " gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; \n" " \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" calcLogDepth(gl_Position); \n" +"#endif \n" +" \n" " // Compute the texture coordinate for the environment map texture lookup \n" " vec3 u = normalize(v_ecPosition); \n" " vec3 n = normalize(v_ecNormal); \n" @@ -1039,6 +1128,26 @@ static const char vs_FullScreenQuad_inl[] = +//############################################################################################################################# +//############################################################################################################################# +static const char vs_logDepth_inl[] = +" \n" +"varying float v_logz; \n" +" \n" +"#define CVF_LOG_DEPTH_IMPL \n" +" \n" +"//-------------------------------------------------------------------------------------------------- \n" +"/// Vertex component - logarithmic depth buffer (Outerra method) \n" +"/// Store (1 + w_clip) in v_logz for use in the fragment shader. \n" +"/// Call calcLogDepth(gl_Position) at the end of the vertex main() to activate. \n" +"//-------------------------------------------------------------------------------------------------- \n" +"void calcLogDepth(vec4 clipPos) \n" +"{ \n" +" v_logz = 1.0 + clipPos.w; \n" +"} \n"; + + + //############################################################################################################################# //############################################################################################################################# static const char vs_Minimal_inl[] = @@ -1058,6 +1167,10 @@ static const char vs_Minimal_inl[] = "{ \n" " gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; \n" " \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" calcLogDepth(gl_Position); \n" +"#endif \n" +" \n" "#ifdef CVF_CALC_CLIP_DISTANCES_IMPL \n" " vec3 ecPosition = (cvfu_modelViewMatrix * cvfa_vertex).xyz; \n" " calcClipDistances(vec4(ecPosition, 1)); \n" @@ -1088,6 +1201,10 @@ static const char vs_MinimalTexture_inl[] = " v_texCoord = cvfa_texCoord; \n" " gl_Position = cvfu_modelViewProjectionMatrix * cvfa_vertex; \n" " \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" calcLogDepth(gl_Position); \n" +"#endif \n" +" \n" "#ifdef CVF_CALC_CLIP_DISTANCES_IMPL \n" " vec3 ecPosition = (cvfu_modelViewMatrix * cvfa_vertex).xyz; \n" " calcClipDistances(vec4(ecPosition, 1)); \n" @@ -1138,6 +1255,10 @@ static const char vs_ParticleTraceComets_inl[] = " v_alpha = a_alpha; \n" " \n" " gl_Position = cvfu_projectionMatrix * ecVertex; \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" calcLogDepth(gl_Position); \n" +"#endif \n" "} \n"; @@ -1180,6 +1301,10 @@ static const char vs_Standard_inl[] = "#endif \n" " \n" " gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" calcLogDepth(gl_Position); \n" +"#endif \n" "} \n"; @@ -1213,6 +1338,10 @@ static const char vs_VectorDrawer_inl[] = " \n" " gl_Position = cvfu_modelViewProjectionMatrix*u_transformationMatrix*cvfa_vertex; \n" " v_diffuse = abs(normalize(cvfu_normalMatrix*mat3_transMatr*cvfa_normal).z); \n" +" \n" +"#ifdef CVF_LOG_DEPTH_IMPL \n" +" calcLogDepth(gl_Position); \n" +"#endif \n" "} \n"; diff --git a/Fwk/VizFwk/LibRender/glsl/fs_CenterLitSpherePoints.glsl b/Fwk/VizFwk/LibRender/glsl/fs_CenterLitSpherePoints.glsl index b9f9c8362b8..55043e76904 100644 --- a/Fwk/VizFwk/LibRender/glsl/fs_CenterLitSpherePoints.glsl +++ b/Fwk/VizFwk/LibRender/glsl/fs_CenterLitSpherePoints.glsl @@ -29,6 +29,10 @@ void main() gl_FragColor = vec4(color.rgb*diffuse, color.a); //gl_FragDepth = gl_FragCoord.z - 15.0*(1.0-mag); + +#ifdef CVF_LOG_DEPTH_IMPL + applyLogDepth(); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/fs_FixedColorMagenta.glsl b/Fwk/VizFwk/LibRender/glsl/fs_FixedColorMagenta.glsl index eb582e381e6..ad80ba383f5 100644 --- a/Fwk/VizFwk/LibRender/glsl/fs_FixedColorMagenta.glsl +++ b/Fwk/VizFwk/LibRender/glsl/fs_FixedColorMagenta.glsl @@ -5,4 +5,8 @@ void main() { gl_FragColor = vec4(1,0,1,1); + +#ifdef CVF_LOG_DEPTH_IMPL + applyLogDepth(); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/fs_HighlightStencilDraw.glsl b/Fwk/VizFwk/LibRender/glsl/fs_HighlightStencilDraw.glsl index d1836d66749..86af9d84878 100644 --- a/Fwk/VizFwk/LibRender/glsl/fs_HighlightStencilDraw.glsl +++ b/Fwk/VizFwk/LibRender/glsl/fs_HighlightStencilDraw.glsl @@ -7,5 +7,9 @@ uniform vec4 u_color; void main() { gl_FragData[0] = u_color; + +#ifdef CVF_LOG_DEPTH_IMPL + applyLogDepth(); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/fs_ParticleTraceComets.glsl b/Fwk/VizFwk/LibRender/glsl/fs_ParticleTraceComets.glsl index 8a76ddf6568..8f7356edcc6 100644 --- a/Fwk/VizFwk/LibRender/glsl/fs_ParticleTraceComets.glsl +++ b/Fwk/VizFwk/LibRender/glsl/fs_ParticleTraceComets.glsl @@ -22,5 +22,9 @@ void main() vec3 color = srcFragment().rgb; gl_FragColor = vec4(color*diffuse, v_alpha); + +#ifdef CVF_LOG_DEPTH_IMPL + applyLogDepth(); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/fs_Standard.glsl b/Fwk/VizFwk/LibRender/glsl/fs_Standard.glsl index 8e8addb74e9..3932d1d73f3 100644 --- a/Fwk/VizFwk/LibRender/glsl/fs_Standard.glsl +++ b/Fwk/VizFwk/LibRender/glsl/fs_Standard.glsl @@ -16,4 +16,8 @@ void main() color = lightFragment(color, 1.0); gl_FragColor = color; + +#ifdef CVF_LOG_DEPTH_IMPL + applyLogDepth(); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/fs_Text.glsl b/Fwk/VizFwk/LibRender/glsl/fs_Text.glsl index c8425a55b0d..37e5fc4d705 100644 --- a/Fwk/VizFwk/LibRender/glsl/fs_Text.glsl +++ b/Fwk/VizFwk/LibRender/glsl/fs_Text.glsl @@ -11,4 +11,8 @@ void main() { float alpha = texture2D(u_texture2D, v_texCoord).a; gl_FragColor = vec4(u_color, alpha); + +#ifdef CVF_LOG_DEPTH_IMPL + applyLogDepth(); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/fs_Unlit.glsl b/Fwk/VizFwk/LibRender/glsl/fs_Unlit.glsl index cb1747e114f..10f145dc22a 100644 --- a/Fwk/VizFwk/LibRender/glsl/fs_Unlit.glsl +++ b/Fwk/VizFwk/LibRender/glsl/fs_Unlit.glsl @@ -13,4 +13,8 @@ void main() vec4 color = srcFragment(); gl_FragColor = color; + +#ifdef CVF_LOG_DEPTH_IMPL + applyLogDepth(); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/fs_VectorDrawer.glsl b/Fwk/VizFwk/LibRender/glsl/fs_VectorDrawer.glsl index 150cb224e09..e16294a56b8 100644 --- a/Fwk/VizFwk/LibRender/glsl/fs_VectorDrawer.glsl +++ b/Fwk/VizFwk/LibRender/glsl/fs_VectorDrawer.glsl @@ -12,4 +12,8 @@ void main() #endif gl_FragColor = vec4(u_color*v_diffuse, 1.0); + +#ifdef CVF_LOG_DEPTH_IMPL + applyLogDepth(); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/fs_logDepth.glsl b/Fwk/VizFwk/LibRender/glsl/fs_logDepth.glsl new file mode 100644 index 00000000000..9e53151c3e9 --- /dev/null +++ b/Fwk/VizFwk/LibRender/glsl/fs_logDepth.glsl @@ -0,0 +1,43 @@ + +varying float v_logz; + +uniform float u_logDepthFC; // = 2.0 / log2(farPlane + 1.0), updated each frame +uniform float u_useLogDepth; // 1.0 = perspective (log depth), 0.0 = orthographic (linear depth) +uniform float u_polygonOffsetFactor; // mirrors glPolygonOffset factor (default 0) +uniform float u_polygonOffsetUnits; // mirrors glPolygonOffset units (default 0) + +#define CVF_LOG_DEPTH_IMPL + +//-------------------------------------------------------------------------------------------------- +/// Fragment component - logarithmic depth buffer +/// Writes a log-distributed depth to gl_FragDepth, replacing the default linear depth. +/// Requires v_logz to be set by calcLogDepth() in the vertex shader. +/// +/// For orthographic projection (u_useLogDepth == 0), falls back to the standard linear +/// gl_FragCoord.z, since w_clip == 1 in orthographic and log depth gives no benefit. +/// +/// Also implements polygon offset manually, because glPolygonOffset has no effect when +/// gl_FragDepth is written explicitly. Set u_polygonOffsetFactor/Units to mirror the +/// glPolygonOffset parameters used on the effect. +/// +/// Reference: http://outerra.blogspot.com/2013/07/logarithmic-depth-buffer-optimizations.html +//-------------------------------------------------------------------------------------------------- +void applyLogDepth() +{ + float depth; + if (u_useLogDepth > 0.5) + { + depth = log2(max(1.0e-6, v_logz)) * u_logDepthFC * 0.5; + } + else + { + depth = gl_FragCoord.z; + } + + // Manual polygon offset: factor * max_slope + units * depth_resolution + // Resolution constant = 1/2^24 for a 24-bit depth buffer. + float slope = max(abs(dFdx(depth)), abs(dFdy(depth))); + depth += u_polygonOffsetFactor * slope + u_polygonOffsetUnits * (1.0 / 16777216.0); + + gl_FragDepth = depth; +} diff --git a/Fwk/VizFwk/LibRender/glsl/vs_DistanceScaledPoints.glsl b/Fwk/VizFwk/LibRender/glsl/vs_DistanceScaledPoints.glsl index 7d88eda974b..e7b695a5dc6 100644 --- a/Fwk/VizFwk/LibRender/glsl/vs_DistanceScaledPoints.glsl +++ b/Fwk/VizFwk/LibRender/glsl/vs_DistanceScaledPoints.glsl @@ -24,6 +24,10 @@ void main () gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; +#ifdef CVF_LOG_DEPTH_IMPL + calcLogDepth(gl_Position); +#endif + // Compute the point diameter in window coords (pixels) // Scale with distance for perspective correction of the size float dist = length(v_ecPosition); diff --git a/Fwk/VizFwk/LibRender/glsl/vs_EnvironmentMapping.glsl b/Fwk/VizFwk/LibRender/glsl/vs_EnvironmentMapping.glsl index 35463293070..7171e3a0c96 100644 --- a/Fwk/VizFwk/LibRender/glsl/vs_EnvironmentMapping.glsl +++ b/Fwk/VizFwk/LibRender/glsl/vs_EnvironmentMapping.glsl @@ -31,6 +31,10 @@ void main () gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; +#ifdef CVF_LOG_DEPTH_IMPL + calcLogDepth(gl_Position); +#endif + // Compute the texture coordinate for the environment map texture lookup vec3 u = normalize(v_ecPosition); vec3 n = normalize(v_ecNormal); diff --git a/Fwk/VizFwk/LibRender/glsl/vs_Minimal.glsl b/Fwk/VizFwk/LibRender/glsl/vs_Minimal.glsl index 38e28f1c6c5..be933720bc5 100644 --- a/Fwk/VizFwk/LibRender/glsl/vs_Minimal.glsl +++ b/Fwk/VizFwk/LibRender/glsl/vs_Minimal.glsl @@ -14,6 +14,10 @@ void main () { gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; +#ifdef CVF_LOG_DEPTH_IMPL + calcLogDepth(gl_Position); +#endif + #ifdef CVF_CALC_CLIP_DISTANCES_IMPL vec3 ecPosition = (cvfu_modelViewMatrix * cvfa_vertex).xyz; calcClipDistances(vec4(ecPosition, 1)); diff --git a/Fwk/VizFwk/LibRender/glsl/vs_MinimalTexture.glsl b/Fwk/VizFwk/LibRender/glsl/vs_MinimalTexture.glsl index d570c465e3e..238f0f667a1 100644 --- a/Fwk/VizFwk/LibRender/glsl/vs_MinimalTexture.glsl +++ b/Fwk/VizFwk/LibRender/glsl/vs_MinimalTexture.glsl @@ -17,6 +17,10 @@ void main () v_texCoord = cvfa_texCoord; gl_Position = cvfu_modelViewProjectionMatrix * cvfa_vertex; +#ifdef CVF_LOG_DEPTH_IMPL + calcLogDepth(gl_Position); +#endif + #ifdef CVF_CALC_CLIP_DISTANCES_IMPL vec3 ecPosition = (cvfu_modelViewMatrix * cvfa_vertex).xyz; calcClipDistances(vec4(ecPosition, 1)); diff --git a/Fwk/VizFwk/LibRender/glsl/vs_ParticleTraceComets.glsl b/Fwk/VizFwk/LibRender/glsl/vs_ParticleTraceComets.glsl index 791eb7b495f..1134e007a35 100644 --- a/Fwk/VizFwk/LibRender/glsl/vs_ParticleTraceComets.glsl +++ b/Fwk/VizFwk/LibRender/glsl/vs_ParticleTraceComets.glsl @@ -37,4 +37,8 @@ void main() v_alpha = a_alpha; gl_Position = cvfu_projectionMatrix * ecVertex; + +#ifdef CVF_LOG_DEPTH_IMPL + calcLogDepth(gl_Position); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/vs_Standard.glsl b/Fwk/VizFwk/LibRender/glsl/vs_Standard.glsl index 0463877e69b..ab3ddccb35e 100644 --- a/Fwk/VizFwk/LibRender/glsl/vs_Standard.glsl +++ b/Fwk/VizFwk/LibRender/glsl/vs_Standard.glsl @@ -33,4 +33,8 @@ void main () #endif gl_Position = cvfu_modelViewProjectionMatrix*cvfa_vertex; + +#ifdef CVF_LOG_DEPTH_IMPL + calcLogDepth(gl_Position); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/vs_VectorDrawer.glsl b/Fwk/VizFwk/LibRender/glsl/vs_VectorDrawer.glsl index 77ffd3a9769..78f2cc066d5 100644 --- a/Fwk/VizFwk/LibRender/glsl/vs_VectorDrawer.glsl +++ b/Fwk/VizFwk/LibRender/glsl/vs_VectorDrawer.glsl @@ -24,4 +24,8 @@ void main () gl_Position = cvfu_modelViewProjectionMatrix*u_transformationMatrix*cvfa_vertex; v_diffuse = abs(normalize(cvfu_normalMatrix*mat3_transMatr*cvfa_normal).z); + +#ifdef CVF_LOG_DEPTH_IMPL + calcLogDepth(gl_Position); +#endif } diff --git a/Fwk/VizFwk/LibRender/glsl/vs_logDepth.glsl b/Fwk/VizFwk/LibRender/glsl/vs_logDepth.glsl new file mode 100644 index 00000000000..b56b825cfbe --- /dev/null +++ b/Fwk/VizFwk/LibRender/glsl/vs_logDepth.glsl @@ -0,0 +1,14 @@ + +varying float v_logz; + +#define CVF_LOG_DEPTH_IMPL + +//-------------------------------------------------------------------------------------------------- +/// Vertex component - logarithmic depth buffer (Outerra method) +/// Store (1 + w_clip) in v_logz for use in the fragment shader. +/// Call calcLogDepth(gl_Position) at the end of the vertex main() to activate. +//-------------------------------------------------------------------------------------------------- +void calcLogDepth(vec4 clipPos) +{ + v_logz = 1.0 + clipPos.w; +} diff --git a/Fwk/VizFwk/LibViewing/cvfSingleQuadRenderingGenerator.cpp b/Fwk/VizFwk/LibViewing/cvfSingleQuadRenderingGenerator.cpp index 6d9d14c17d2..a0e1e06dd45 100644 --- a/Fwk/VizFwk/LibViewing/cvfSingleQuadRenderingGenerator.cpp +++ b/Fwk/VizFwk/LibViewing/cvfSingleQuadRenderingGenerator.cpp @@ -172,8 +172,9 @@ ref SingleQuadRenderingGenerator::generate() } } - // Shader program + // Shader program — screen-space quad, no 3D depth needed cvf::ShaderProgramGenerator gen(m_renderingName + "ShaderProg", cvf::ShaderSourceProvider::instance()); + gen.setInjectLogDepth(false); gen.addVertexCode(cvf::ShaderSourceRepository::vs_FullScreenQuad);