需求
在(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);
}
运行截图