OSG Notes: AutoTransform implements fixed pixel size graphics

need

Draw a cube with a fixed size of 10 pixels at the (200,0,0) position

Method to realize

  1. For ease of observation, two straight lines are drawn in the example, intersecting at (200,0,0).

    //两根直线交于(200, 0, 0),用于辅助观察
    {
          
          
    	osg::Geometry* pLineGeom = new osg::Geometry();
    	osg::Vec3Array* pVertexArray = new osg::Vec3Array();
    	pVertexArray->push_back(osg::Vec3(-400, 0, 0));
    	pVertexArray->push_back(osg::Vec3(400, 0, 0));
    
    	pVertexArray->push_back(osg::Vec3(200, 0, 400));
    	pVertexArray->push_back(osg::Vec3(200, 0, -400));
    
    	pLineGeom->setVertexArray(pVertexArray);
    	pLineGeom->addPrimitiveSet(
    		new osg::DrawArrays(osg::DrawArrays::LINES, 0, pVertexArray->size()));
    	osg::Geode* pShapeGeode = new osg::Geode();
    	pShapeGeode->addDrawable(pLineGeom);
    	pRoot->addChild(pShapeGeode);
    }
    
  2. In the first implementation,
    the center point of osg::Box is directly set to (200,0,0). The test found that this is an incorrect implementation.

    {
          
          
    	osg::AutoTransform* pAt = new osg::AutoTransform();
    	pAt->setAutoScaleToScreen(true);
    	pRoot->addChild(pAt);
    
    	osg::ShapeDrawable* pShape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(200, 0, 0), 20));
    	pShape->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0));
    	osg::Geode* pShapeGeode = new osg::Geode();
    	pShapeGeode->addDrawable(pShape);
    	pAt->addChild(pShapeGeode);
    }
    

    Analysis of incorrect reasons:
    The principle of AutoTransform to achieve fixed pixel size is to calculate the scaling factor under the current view to keep the graphics at a fixed size.

    Refer to AutoTransform's function AutoTransform::computeMatrix() to calculate its own node matrix, and its
    function AutoTransform::computeLocalToWorldMatrix to calculate the world coordinate system. (Note: The source code is listed later). The formula for calculating the final coordinates of the Box center point is as follows:

    Box center point* (pivot matrix scaling matrix rotation matrix * position matrix * parent node matrix)

    In the current example, the pivot matrix and rotation matrix are both unit matrices, so the problem is simplified to

    Box center point* (scaling matrix* position matrix* parent node matrix)

    Because the scaling matrix is ​​applied first, for example, in the current view, the scaling factor is 2.0, then the coordinate point after the Box center point * the scaling matrix is ​​(400,0,0), which does not meet the requirements.

    void AutoTransform::computeMatrix() const
    {
          
          
        if (!_matrixDirty) return;
        
        _cachedMatrix.makeRotate(_rotation);
        _cachedMatrix.postMultTranslate(_position);
        _cachedMatrix.preMultScale(_scale);
        _cachedMatrix.preMultTranslate(-_pivotPoint);
        
        _matrixDirty = false;
    }
    
    bool AutoTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const
    {
          
          
        if (_matrixDirty) computeMatrix();
        
        if (_referenceFrame==RELATIVE_RF)
        {
          
          
            matrix.preMult(_cachedMatrix);
        }
        else // absolute
        {
          
          
            matrix = _cachedMatrix;
        }
        return true;
    }
    
  3. The second implementation of
    osg::AutoTransform node position coordinates is set to (200,0,0). The reason why this method is correct can be found in the analysis of the reasons for the first implementation.

    {
          
          
    	osg::AutoTransform* pAt = new osg::AutoTransform();
    	pAt->setAutoScaleToScreen(true);
    	pAt->setPosition(osg::Vec3(200, 0, 0));
    	pRoot->addChild(pAt);
    
    	osg::ShapeDrawable* pShape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), 20));
    	pShape->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0));
    	osg::Geode* pShapeGeode = new osg::Geode();
    	pShapeGeode->addDrawable(pShape);
    	pAt->addChild(pShapeGeode);
    }
    
  4. The third implementation
    adds a parent node (matrix node) to the osg::AutoTransform node, and then sets the position of the parent node to (200,0,0). The correct reason for this method can be found in the analysis of the reasons for the first implementation.

    {
          
          
    	osg::PositionAttitudeTransform* pParentNode = new osg::PositionAttitudeTransform();
    	pParentNode->setPosition(osg::Vec3(200, 0, 0));
    	pRoot->addChild(pParentNode);
    
    	osg::AutoTransform* pAt = new osg::AutoTransform();
    	pAt->setAutoScaleToScreen(true);
    	pParentNode->addChild(pAt);
    
    	osg::ShapeDrawable* pShape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), 20));
    	pShape->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0));
    	osg::Geode* pShapeGeode = new osg::Geode();
    	pShapeGeode->addDrawable(pShape);
    	pAt->addChild(pShapeGeode);
    }
    

Run screenshot

Insert image description here

Guess you like

Origin blog.csdn.net/s634772208/article/details/130532600