From f9a7ce4203b9d72fd1de55631bdf559fcef26fae Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Thu, 23 Apr 2026 11:33:49 +0900 Subject: [PATCH 1/2] auto-scale indices display based on camera distance The indices text now maintains a constant screen-space size regardless of zoom level and scene dimensions, removing the need to manually adjust showIndicesScale per scene. - Compute per-vertex scale from the projection matrix and camera depth in GlText::textureDraw_Indices - Handle both perspective and orthographic projections - Add alpha blending for smoother text rendering - Update all callers to pass a dimensionless multiplier (default 1.0) instead of bbox-dependent world-space size --- .../PolynomialRestShapeSpringsForceField.inl | 4 +- .../statecontainer/MechanicalObject.inl | 6 +-- .../dynamic/PointSetGeometryAlgorithms.inl | 9 +---- .../component/visual/VisualPointCloud.inl | 5 +-- Sofa/GL/src/sofa/gl/glText.cpp | 39 +++++++++++++++++-- .../Common/src/sofa/gui/common/BaseViewer.cpp | 3 +- .../Common/src/sofa/gui/common/BaseViewer.h | 2 +- 7 files changed, 45 insertions(+), 23 deletions(-) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/PolynomialRestShapeSpringsForceField.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/PolynomialRestShapeSpringsForceField.inl index 2703c5d3690..a46099cc16f 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/PolynomialRestShapeSpringsForceField.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/PolynomialRestShapeSpringsForceField.inl @@ -40,7 +40,7 @@ PolynomialRestShapeSpringsForceField::PolynomialRestShapeSpringsForce , d_recomputeIndices(initData(&d_recomputeIndices, false, "recompute_indices", "Recompute indices (should be false for BBOX)")) , d_drawSpring(initData(&d_drawSpring,false,"drawSpring","draw Spring")) , d_springColor(initData(&d_springColor, sofa::type::RGBAColor(0.0f, 1.0f, 0.0f, 1.0f), "springColor","spring color")) - , d_showIndicesScale(initData(&d_showIndicesScale, (float)0.02, "showIndicesScale", "Scale for indices display. (default=0.02)")) + , d_showIndicesScale(initData(&d_showIndicesScale, (float)1.0, "showIndicesScale", "Multiplier for indices display size. Indices are auto-scaled to maintain a constant screen size.")) , d_zeroLength(initData(&d_zeroLength,"initialLength","initial virtual length of the spring")) , d_smoothShift(initData(&d_smoothShift,static_cast(0.0),"smoothShift","denominator correction adding shift value")) , d_smoothScale(initData(&d_smoothScale,static_cast(1.0),"smoothScale","denominator correction adding scale")) @@ -432,7 +432,7 @@ void PolynomialRestShapeSpringsForceField::draw(const core::visual::V // draw connected point indices - Real scale = (vparams->sceneBBox().maxBBox() - vparams->sceneBBox().minBBox()).norm() * d_showIndicesScale.getValue(); + Real scale = d_showIndicesScale.getValue(); type::vector positions; for (sofa::Index i = 0; i < indices.size(); i++) { diff --git a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl index 45f23586500..2cfc45c8378 100644 --- a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl +++ b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl @@ -151,7 +151,7 @@ MechanicalObject::MechanicalObject() , showObject(initData(&showObject, (bool) false, "showObject", "Show objects. (default=false)")) , showObjectScale(initData(&showObjectScale, 0.1f, "showObjectScale", "Scale for object display. (default=0.1)")) , showIndices(initData(&showIndices, (bool) false, "showIndices", "Show indices. (default=false)")) - , showIndicesScale(initData(&showIndicesScale, 0.02f, "showIndicesScale", "Scale for indices display. (default=0.02)")) + , showIndicesScale(initData(&showIndicesScale, 1.0f, "showIndicesScale", "Multiplier for indices display size. Indices are auto-scaled to maintain a constant screen size.")) , showVectors(initData(&showVectors, (bool) false, "showVectors", "Show velocity. (default=false)")) , showVectorsScale(initData(&showVectorsScale, 0.0001f, "showVectorsScale", "Scale for vectors display. (default=0.0001)")) , drawMode(initData(&drawMode,0,"drawMode","The way vectors will be drawn:\n- 0: Line\n- 1:Cylinder\n- 2: Arrow.\n\nThe DOFS will be drawn:\n- 0: point\n- >1: sphere. (default=0)")) @@ -2630,14 +2630,12 @@ SReal MechanicalObject::getConstraintJacobianTimesVecDeriv(unsigned i template inline void MechanicalObject::drawIndices(const core::visual::VisualParams* vparams) { - const float scale = (float)((vparams->sceneBBox().maxBBox() - vparams->sceneBBox().minBBox()).norm() * showIndicesScale.getValue()); - std::vector positions; positions.reserve(d_size.getValue()); for (int i = 0; i drawTool()->draw3DText_Indices(positions, scale, d_color.getValue()); + vparams->drawTool()->draw3DText_Indices(positions, showIndicesScale.getValue(), d_color.getValue()); } template diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/PointSetGeometryAlgorithms.inl b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/PointSetGeometryAlgorithms.inl index 5b51db3f59a..051d065c0f8 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/PointSetGeometryAlgorithms.inl +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/PointSetGeometryAlgorithms.inl @@ -34,7 +34,7 @@ using sofa::core::objectmodel::ComponentState; template PointSetGeometryAlgorithms< DataTypes >::PointSetGeometryAlgorithms() : GeometryAlgorithms() - , d_showIndicesScale (core::objectmodel::Base::initData(&d_showIndicesScale, (float) 0.02, "showIndicesScale", "Debug : scale for view topology indices")) + , d_showIndicesScale (core::objectmodel::Base::initData(&d_showIndicesScale, (float) 1.0, "showIndicesScale", "Debug : multiplier for view topology indices size. Indices are auto-scaled to maintain a constant screen size.")) , d_showPointIndices (core::objectmodel::Base::initData(&d_showPointIndices, (bool) false, "showPointIndices", "Debug : view Point indices")) , d_tagMechanics( initData(&d_tagMechanics,std::string(),"tagMechanics","Tag of the Mechanical Object")) , l_topology(initLink("topology", "link to the topology container")) @@ -85,12 +85,7 @@ void PointSetGeometryAlgorithms< DataTypes >::reinit() template float PointSetGeometryAlgorithms< DataTypes >::getIndicesScale() const { - const sofa::type::BoundingBox& bbox = this->getContext()->f_bbox.getValue(); - const float bbDiff = float((bbox.maxBBox() - bbox.minBBox()).norm()); - if (std::isinf(bbDiff)) - return d_showIndicesScale.getValue(); - else - return bbDiff * d_showIndicesScale.getValue(); + return d_showIndicesScale.getValue(); } diff --git a/Sofa/Component/Visual/src/sofa/component/visual/VisualPointCloud.inl b/Sofa/Component/Visual/src/sofa/component/visual/VisualPointCloud.inl index d3a508faba0..57fc964ff1f 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/VisualPointCloud.inl +++ b/Sofa/Component/Visual/src/sofa/component/visual/VisualPointCloud.inl @@ -158,10 +158,7 @@ void VisualPointCloud::doDrawVisual(const core::visual::VisualParams* template void VisualPointCloud::drawIndices(const core::visual::VisualParams* vparams) const { - const float scale = static_cast( - (vparams->sceneBBox().maxBBox() - vparams->sceneBBox().minBBox()).norm() * - d_indicesScale.getValue()); - vparams->drawTool()->draw3DText_Indices(convertCoord(), scale, d_indicesColor.getValue()); + vparams->drawTool()->draw3DText_Indices(convertCoord(), d_indicesScale.getValue(), d_indicesColor.getValue()); } template diff --git a/Sofa/GL/src/sofa/gl/glText.cpp b/Sofa/GL/src/sofa/gl/glText.cpp index 6fd0263b2a9..750bf13c94a 100644 --- a/Sofa/GL/src/sofa/gl/glText.cpp +++ b/Sofa/GL/src/sofa/gl/glText.cpp @@ -184,13 +184,32 @@ void GlText::textureDraw_Indices(const type::vector& positions, cons static const float worldHeight = 1.0; static const float worldWidth = 0.5; + // Auto-scaling: retrieve projection matrix and viewport to maintain + // a constant screen-space text size regardless of camera distance + GLfloat projMatrix[16]; + GLint viewport[4]; + glGetFloatv(GL_PROJECTION_MATRIX, projMatrix); + glGetIntegerv(GL_VIEWPORT, viewport); + + const float viewportHeight = static_cast(viewport[3]); + // Column-major P[1][1] = cot(fov_y/2) for perspective + const float p11 = projMatrix[5]; + // Column-major P[3][3]: 0 for perspective, ~1 for orthographic + const bool isPerspective = (projMatrix[15] < 0.5f); + // Base text height in pixels (before user multiplier) + static const float baseFontPixelHeight = 30.0f; + + if (p11 == 0.0f || viewportHeight == 0.0f) + return; + glPushAttrib(GL_TEXTURE_BIT); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // multiply tex color with glColor - //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // only tex color (no glColor) glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); s_asciiTexture->bind(); @@ -216,10 +235,23 @@ void GlText::textureDraw_Indices(const type::vector& positions, cons type::Vec3f temp(positions[i][0], positions[i][1], positions[i][2]); temp = modelviewM.transform(temp); + // Compute auto-scale: one pixel in world units = 2*depth / (p11 * viewportHeight) + float autoScale; + if (isPerspective) + { + float depth = -temp[2]; + if (depth < 1e-5f) depth = 1e-5f; + autoScale = baseFontPixelHeight * scale * 2.0f * depth / (p11 * viewportHeight); + } + else + { + autoScale = baseFontPixelHeight * scale * 2.0f / (p11 * viewportHeight); + } + glLoadIdentity(); //translate a little bit to center the text on the position (instead of starting from a top-left position) - glTranslatef(temp[0] - (worldWidth*length*scale)*0.5f, temp[1] + worldHeight*scale*0.5f, temp[2]); - glScalef(scale, scale, scale); + glTranslatef(temp[0] - (worldWidth*length*autoScale)*0.5f, temp[1] + worldHeight*autoScale*0.5f, temp[2]); + glScalef(autoScale, autoScale, autoScale); glRotatef(180.0, 1, 0, 0); for (std::size_t j = 0; j < length; j++) { @@ -262,6 +294,7 @@ void GlText::textureDraw_Indices(const type::vector& positions, cons s_asciiTexture->unbind(); glDisable(GL_ALPHA_TEST); + glDisable(GL_BLEND); glPopAttrib(); diff --git a/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.cpp b/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.cpp index 4ecdad8bbc3..22297b87293 100644 --- a/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.cpp +++ b/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.cpp @@ -472,8 +472,7 @@ void BaseViewer::drawSelection(sofa::core::visual::VisualParams* vparams) if(m_showSelectedObjectIndices && !positions.empty() && validBox) { - const float scale = (box.maxBBox() - box.minBBox()).norm() * m_visualScaling; - drawTool->draw3DText_Indices(positions, scale, m_selectionColor); + drawTool->draw3DText_Indices(positions, m_visualScaling, m_selectionColor); } continue; diff --git a/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.h b/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.h index 3a989cc27b4..2e14241df36 100644 --- a/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.h +++ b/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.h @@ -133,7 +133,7 @@ class SOFA_GUI_COMMON_API BaseViewer bool m_showSelectedObjectVolumes {false}; bool m_showSelectedObjectIndices {false}; type::RGBAColor m_selectionColor {type::RGBAColor::purple()}; - float m_visualScaling {0.2}; + float m_visualScaling {1.0}; protected: void drawIndices(const sofa::type::BoundingBox& bbox, const std::vector& positions); From 6cea26a908b2d64178d5ee2fbe55208007c68ea9 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Fri, 8 May 2026 10:50:07 +0900 Subject: [PATCH 2/2] Update Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl Co-authored-by: Paul Baksic <30337881+bakpaul@users.noreply.github.com> --- .../src/sofa/component/statecontainer/MechanicalObject.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl index 2cfc45c8378..278f489da96 100644 --- a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl +++ b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl @@ -151,7 +151,7 @@ MechanicalObject::MechanicalObject() , showObject(initData(&showObject, (bool) false, "showObject", "Show objects. (default=false)")) , showObjectScale(initData(&showObjectScale, 0.1f, "showObjectScale", "Scale for object display. (default=0.1)")) , showIndices(initData(&showIndices, (bool) false, "showIndices", "Show indices. (default=false)")) - , showIndicesScale(initData(&showIndicesScale, 1.0f, "showIndicesScale", "Multiplier for indices display size. Indices are auto-scaled to maintain a constant screen size.")) + , showIndicesScale(initData(&showIndicesScale, 1.0f, "showIndicesScale", "Scaling factor for indices display size. Indices are auto-scaled to maintain a constant screen size.")) , showVectors(initData(&showVectors, (bool) false, "showVectors", "Show velocity. (default=false)")) , showVectorsScale(initData(&showVectorsScale, 0.0001f, "showVectorsScale", "Scale for vectors display. (default=0.0001)")) , drawMode(initData(&drawMode,0,"drawMode","The way vectors will be drawn:\n- 0: Line\n- 1:Cylinder\n- 2: Arrow.\n\nThe DOFS will be drawn:\n- 0: point\n- >1: sphere. (default=0)"))