​若该文为原创文章,未经允许不得转载
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/144609131
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

OSG开发专栏(点击传送门)

上一篇:《OSG开发笔记(三十九):OSG中模型的透明度实现、球体透明度Demo
下一篇:持续补充中…


前言

  OSG内置的几何图形并没有球面,那么绘制球面先要绘制球面的组成顶点,本篇解说绘制球面组成顶点的详细过程。


Demo

  在这里插入图片描述

  组成面的时候,为了看到是否正确,取中间的几个圆环:
  在这里插入图片描述

  在这里插入图片描述

  


回顾OSG坐标系理解

  OSG的坐标系类似于Qt场景坐标系,场景有场景的坐标系,图元有图元的坐标系,视图有视图的坐标系。与此类似,OSG坐标系也相似,差别在于视图坐标系在OSG是相机坐标系。

世界坐标系

  世界坐标系描述的是整个场景中所有的对象,可以理解为绝对坐标系,所有对象的位置都是绝对坐标。从整体上考虑,它为所有对象的位置提供一个绝对的参考标准,从而避免了物体之间由于独立的物体坐标系而导致的坐标系混乱。

物体坐标系

  每一个物体都有自己的坐标系,当物体发生交换时,实际上是它本身的坐标系相对于世界坐标系发生变换的过程。
物体坐标系通常描述的问题是特定物体的内部对象,主要包括物体的顶点,物体的法向量和物体的方向。

摄像机坐标系

  摄像机坐标系与屏幕坐标系类似,只不过摄像机坐标系位于3D空间,而屏幕坐标系位于2D空间。
  坐标系三轴正方向

  • opengl坐标系,即z轴正向朝外,y轴正向朝上,x轴正向朝右(符合软件研发标准坐标);
  • osg坐标系,即z轴正向朝上,y轴正向朝内,x轴正向朝右(笛卡尔坐标系);
  • Directx坐标系,即z轴正向朝里,y轴正向朝上,x轴正向朝右.(左手坐标系);

笛卡尔坐标系-右手法则

  在这里插入图片描述


球面顶点计算原理

  平行面计算平行角度θ,其一周的x和y计算:
  在这里插入图片描述

  得到了最大横截面的时候圆圈点的求解公式。
  垂直平面计算垂直的z坐标系:
  在这里插入图片描述

  以上两个绘制出来就是圆柱了:
  在这里插入图片描述

  纵轴的角度也要参与到之前圆圈的计算中,得到上下走的时候圆圈缩小:
  在这里插入图片描述

  在这里插入图片描述

  那么x和y都需要额外乘以垂直角度来缩小,按照代码的计算方式,是从y从0°开始,所以是cos,不是sin,绘制出来如下图:
  在这里插入图片描述


绘制球面顶点过程

步骤一:创建几何节点和几何信息节点

  在这里插入图片描述

// 步骤一:创建一个用户保存集合信息的对象osg::Geode
osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;

步骤二:计算顶点,设置顶点颜色

  在这里插入图片描述

    // 步骤二:计算顶点,颜色
    osg::ref_ptr<osg::Vec3Array> pVec3ArrayVertex = new osg::Vec3Array;
    osg::ref_ptr<osg::Vec4Array> pVec4ArrayColor = new osg::Vec4Array;
    // 计算步长数量
    int xyStepTotal = qCeil(360.0f / xyCircleStepAngle);
    // 纵轴,因为只提供了z坐标,走180°即可
    int xzStepTotal = qCeil(180.0f / xzCircleStepAngle);
    {
        // 计算步长角度
        double xyStepAngle = 360.0f / xyStepTotal;
        double xzStepAngle = 180.0f / xzStepTotal;
#if 1
        // 计算顶点,颜色
        for(int xzStepIndex = 0; xzStepIndex < xzStepTotal; xzStepIndex++)
        {
            for(int xyStepIndex = 0; xyStepIndex < xyStepTotal; xyStepIndex++)
            {
//                LOG << xyStepIndex << xyStepIndex * xyStepAngle
//                    << xzStepIndex << xzStepIndex * xzStepAngle;
                LOG << radius * cos(qDegreesToRadians(xyStepIndex * xyStepAngle))
                    << radius * sin(qDegreesToRadians(xyStepIndex * xyStepAngle))
                    << radius * cos(qDegreesToRadians(xzStepIndex * xzStepAngle));
                // 绘制点
                pVec3ArrayVertex->push_back(osg::Vec3f(radius * cos(qDegreesToRadians(xyStepIndex * xyStepAngle)) * sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),
                                                       radius * sin(qDegreesToRadians(xyStepIndex * xyStepAngle)) * sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),
                                                       radius * cos(qDegreesToRadians(xzStepIndex * xzStepAngle))));
                // 绘制颜色
                pVec4ArrayColor->push_back(osg::Vec4f(1.0, 0.0, 0.0, 1.0));
            }
        }
#endif
    }
pGeometry->setVertexArray(pVec3ArrayVertex.get());

步骤三:设置顶点颜色

  在这里插入图片描述

// 步骤三:设置顶点颜色
    pGeometry->setColorArray(pVec4ArrayColor.get());
pGeometry->setColorBinding(osg::Geometry::BIND_OVERALL);

步骤四:设置顶点法向量

  在这里插入图片描述

// 步骤四:添加法线、设置法线
osg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;
pVec3ArrayNormal->push_back(osg::Vec3f(0, 1, 0));
pGeometry->setNormalArray(pVec3ArrayNormal);

步骤五:设置几何图形绘制方式

  在这里插入图片描述

// 步骤五:设置顶点几何绘制方式
//LOG << pVec3ArrayVertex->size() << pVec4ArrayColor->size();
pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::POINTS, 0, pVec3ArrayVertex->size()));

步骤六:绘制几何图形

  在这里插入图片描述

// 步骤六:绘制几何图形
pGeode->addDrawable(pGeometry.get());

步骤七:设置顶点绘制大小

  在这里插入图片描述

#if 1
    // 步骤七:设置顶点大小
    osg::ref_ptr<osg::Point> pPoint = new osg::Point();
    pPoint->setSize(1);
    pGeometry->getOrCreateStateSet()->setAttributeAndModes(pPoint, osg::StateAttribute::ON);
#endif

Demo源码

节点完整绘制函数

osg::ref_ptr<osg::Node> OsgWidget::getSpherialSurface()
{
    // 其他demo的控件
    updateControlVisible(false);

    osg::ref_ptr<osg::Group> pGroup = new osg::Group();

    {
        // 创建球面
        osg::ref_ptr<osg::Geode> pGeode = OsgManager::createSpherialSurface(Point3F(0, 0, 0), 50, 10, 10);
        // 关闭光照
        OsgManager::setLighting(pGeode.get(), false);

        pGroup->addChild(pGeode.get());
    }

    return pGroup.get();
}

绘制球面点函数

osg::ref_ptr<osg::Geode> OsgManager::createSpherialSurface(Point3F center, double radius, double xyCircleStepAngle, double xzCircleStepAngle)
{
    // 绘制球面
    // 步骤一:创建一个用户保存集合信息的对象osg::Geode
    osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
    osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;
    // 步骤二:计算顶点,颜色
    osg::ref_ptr<osg::Vec3Array> pVec3ArrayVertex = new osg::Vec3Array;
    osg::ref_ptr<osg::Vec4Array> pVec4ArrayColor = new osg::Vec4Array;
    // 计算步长数量
    int xyStepTotal = qCeil(360.0f / xyCircleStepAngle);
    // 纵轴,因为只提供了z坐标,走180°即可
    int xzStepTotal = qCeil(180.0f / xzCircleStepAngle);
    {
        // 计算步长角度
        double xyStepAngle = 360.0f / xyStepTotal;
        double xzStepAngle = 180.0f / xzStepTotal;
#if 1
        // 计算顶点,颜色
        for(int xzStepIndex = 0; xzStepIndex < xzStepTotal; xzStepIndex++)
        {
            for(int xyStepIndex = 0; xyStepIndex < xyStepTotal; xyStepIndex++)
            {
//                LOG << xyStepIndex << xyStepIndex * xyStepAngle
//                    << xzStepIndex << xzStepIndex * xzStepAngle;
                LOG << radius * cos(qDegreesToRadians(xyStepIndex * xyStepAngle))
                    << radius * sin(qDegreesToRadians(xyStepIndex * xyStepAngle))
                    << radius * cos(qDegreesToRadians(xzStepIndex * xzStepAngle));
                // 绘制点
                pVec3ArrayVertex->push_back(osg::Vec3f(radius * cos(qDegreesToRadians(xyStepIndex * xyStepAngle)) * sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),
                                                       radius * sin(qDegreesToRadians(xyStepIndex * xyStepAngle)) * sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),
                                                       radius * cos(qDegreesToRadians(xzStepIndex * xzStepAngle))));
                // 绘制颜色
                pVec4ArrayColor->push_back(osg::Vec4f(1.0, 0.0, 0.0, 1.0));
            }
        }
#endif
    }
    pGeometry->setVertexArray(pVec3ArrayVertex.get());
    // 步骤三:设置顶点颜色
    pGeometry->setColorArray(pVec4ArrayColor.get());
    pGeometry->setColorBinding(osg::Geometry::BIND_OVERALL);
    // 步骤四:添加法线、设置法线
    osg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;
    pVec3ArrayNormal->push_back(osg::Vec3f(0, 1, 0));
    pGeometry->setNormalArray(pVec3ArrayNormal);
    // 步骤五:设置顶点几何绘制方式
//    LOG << pVec3ArrayVertex->size() << pVec4ArrayColor->size();
    pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::POINTS, 0, pVec3ArrayVertex->size()));
    // 步骤六:绘制几何图形
    pGeode->addDrawable(pGeometry.get());
#if 0
    // 步骤七:设置顶点大小
    osg::ref_ptr<osg::Point> pPoint = new osg::Point();
    pPoint->setSize(1);
    pGeometry->getOrCreateStateSet()->setAttributeAndModes(pPoint, osg::StateAttribute::ON);
#endif
    return pGeode.get();
}

关闭光照函数

void OsgManager::setLighting(osg::Node *pNode, bool open)
{
    // 步骤一:获取状态集
    osg::ref_ptr<osg::StateSet> pStateSet = pNode->getOrCreateStateSet();
    // 步骤二:状态集 设置深度测试开启,确保透明的物体深度测试开启
    pStateSet->setMode(GL_LIGHTING, open ? osg::StateAttribute::ON : osg::StateAttribute::OFF);
}

工程模板v1.40.0

  在这里插入图片描述


入坑

入坑一:测试绘制顶点的时候,绘制顶点不显示

问题

  顶点不显示
  在这里插入图片描述

  结点代码:
  在这里插入图片描述

尝试

  改成直线后也不现实,然后拽托下变换视角,发现可以显示
  在这里插入图片描述

  在这里插入图片描述

  所以绘制时出来了,只是看不到,关闭光照就好:
  在这里插入图片描述

  改回点即可。

解决

  关闭光照即可
  在这里插入图片描述

  查看点,是为了检查点对错,上面就是少计算了一个,所以变成圆柱,下面是对的了:
  在这里插入图片描述


上一篇:《OSG开发笔记(三十九):OSG中模型的透明度实现、球体透明度Demo
下一篇:持续补充中…


本文章博客地址:https://blog.csdn.net/qq21497936/article/details/144609131

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐