需求
在(200,0,0)位置绘制固定10像素大小的正方体
实现方式
-
为了便于观察,例子中绘制了两条直线,相交于(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); }
-
第一种实现
osg::Box的中心点直接设置为(200,0,0),测试发现,这是不正确的实现。{ 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); }
不正确的原因分析:
AutoTransform实现固定像素大小的原理,就是计算当前视图下的缩放因子让图形保持固定大小。参看AutoTransform计算自身节点矩阵的函数AutoTransform::computeMatrix(),以及
计算到世界坐标系的函数AutoTransform::computeLocalToWorldMatrix可知(注:源码在后文中有列出),计算Box中心点的最终坐标公式如下:Box中心点 * (pivot矩阵缩放矩阵旋转矩阵*位置矩阵 * 父节点矩阵)
当前例子下,pivot矩阵、旋转矩阵均为单位矩阵,所以问题简化为
Box中心点 * (缩放矩阵 * 位置矩阵 * 父节点矩阵)
因为最先应用的是缩放矩阵,如当前视图下,缩放因子为2.0,则Box中心点*缩放矩阵后的坐标点为(400,0,0),不满足需求。
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; }
-
第二种实现
osg::AutoTransform节点位置坐标设置为(200,0,0),此方法正确的原因可参看第一种实现原因分析{ 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); }
-
第三种实现
给osg::AutoTransform节点增加个父节点(矩阵节点),让后设置父节点的位置为(200,0,0),此方法正确的原因可参看第一种实现原因分析{ 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); }