OSG笔记:AutoTransform实现固定像素大小的图形

文章详细探讨了在osg图形库中如何正确实现一个固定10像素大小的正方体,位于坐标(200,0,0)。通过三种不同的osg::AutoTransform和osg::Box组合方式,解释了错误和正确实现的原因,主要涉及到AutoTransform的缩放、旋转和位置矩阵的计算。
摘要由CSDN通过智能技术生成
需求
在(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);
}
复制代码

 

运行截图

 

————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/s634772208/article/details/130532600

posted @   unicornsir  阅读(48)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示