项目实战:Qt+OSG三维建模基础框架v1.0.0(绘制直线,输入参数,绘制通道,支持windows、linux、国产麒麟系统)

需求

  1.使用osg替换opengl建模,osg三维对象管理,性能优化,而opengl依赖cpu计算,且对场景管控不好;
  2.右侧鼠标绘图,绘制长度的通道,可以一边画图,同步根据图来进行长度的创建通道;(这部分暂没继续实现了);
  3.左侧侧是三维场景的框架,实现基本的功能:缩放、旋转、拽托场景中心,固定轴旋转;(这块是三维引擎,没有针对项目进行漫游器、事件处理器、相机口的调整了。)
  4.基准面,绘制预计大小的基准面(这块要做无限平面,暂时这么多,无限平面得做显示范围正交投影,否则远处的会扎堆成一块黑色,已解决未放入);
  本项目v1.0.0,实现一个建模的雏形,后续会逐渐完善。

 

相关博客

 

Demo v1.0.0

  请添加图片描述

  请添加图片描述

  请添加图片描述

 

模块化部署

  在这里插入图片描述

 

关键代码

OsgManager.h

#ifndef OSGMANAGER_H
#define OSGMANAGER_H

#include "osgQt/GraphicsWindowQt.h"
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

#include <osgGA/CameraManipulator>
#include <osgGA/StandardManipulator>
#include <osgGA/OrbitManipulator>
#include <osgGA/TrackballManipulator>
#include <osgGA/MultiTouchTrackballManipulator>
#include <osgGA/NodeTrackerManipulator>
#include <osgGA/TerrainManipulator>
#include <osgGA/FirstPersonManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/SphericalManipulator>
#include <osgGA/CameraViewSwitchManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/UFOManipulator>
#include <osgGA/StateSetManipulator>

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <osg/Switch>

#include <osg/MatrixTransform>

#include <osg/Depth>
#include <osg/LineWidth>
#include <osg/Point>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osg/Multisample>
#include <osg/PositionAttitudeTransform>

#include "osgCommon.h"

class OsgManager
{
public:
    OsgManager();

public:
    // 创建一个隧道
    static osg::ref_ptr<osg::Node> createTunnel(Point3F centerP, double width, double height, double length, double thickness);

public:
    // 创建一个面,输入四个点,输入四个点颜色
    static osg::ref_ptr<osg::Node> createOneFace(Point3F p1, Point3F p2, Point3F p3, Point3F p4,
                                   double r = 1.0f, double g = 1.0f, double b = 1.0f,double a = 1.0f,
                                   Point3F normal = Point3F(0.0f, 1.0f, 0.0f));
    // 创建一个长方体,输入中心点坐标,输入宽度,输入长度,输入颜色
    static osg::ref_ptr<osg::Node> createOneCuboid(Point3F centerP, double width, double height, double length,
                                     double r = 1.0f, double g = 1.0f, double b = 1.0f,double a = 1.0f);


public:
    static QString debugInfo(Point3F point3f);
};

#endif // OSGMANAGER_H

OsgManager.h

#include "OsgManager.h"

#include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")

OsgManager::OsgManager()
{

}

osg::ref_ptr<osg::Node> OsgManager::createTunnel(Point3F centerP, double width, double height, double length, double thickness)
{
    LOG << "隧道的中心点:" << debugInfo(centerP) << ", 宽度:" << width << "高度:" << height << "长度" << length;
    /**
    //        上
    //      =====
    //    //     \\
    //    ___    ___
    //    | |    | |
    // 左 | |    | | 右
    //    | |    | |
    //    ___    ___
    **/
    osg::ref_ptr<osg::Group> pGroup = new osg::Group;
    // 绘制左边部件
    {
        // 横向左是x轴正,里外外是y轴正,纵向上是z轴正
        // 计算左侧部件的中心点、宽度、高度、长度
        Point3F leftCenterP;
        leftCenterP.x = centerP.x - width / 2;
        leftCenterP.z = centerP.z;
        leftCenterP.y = centerP.y;
        LOG << "(" << leftCenterP.x << "," << leftCenterP.y << "," << leftCenterP.z << ")" << thickness << height << length;
        // 创建长方体
        pGroup->addChild(createOneCuboid(leftCenterP, thickness, height, length));
    }
    // 绘制右侧部件
    {
        // 横向左是x轴正,里外外是y轴正,纵向上是z轴正
        // 计算左侧部件的中心点、宽度、高度、长度
        Point3F rightCenterP;
        rightCenterP.x = centerP.x + width / 2;
        rightCenterP.z = centerP.z;
        rightCenterP.y = centerP.y;
        LOG << "(" << rightCenterP.x << "," << rightCenterP.y << "," << rightCenterP.z << ")" << thickness << height << length;
        // 创建长方体
        pGroup->addChild(createOneCuboid(rightCenterP, thickness, height, length));
    }
    // 顶部部件(注意:暂时用一个长方体替代)
    {
        // 横向左是x轴正,里外外是y轴正,纵向上是z轴正
        // 计算左侧部件的中心点、宽度、高度、长度
        Point3F topCenterP;
        topCenterP.x = centerP.x;
        topCenterP.z = centerP.z + height / 2 + thickness / 2;
        topCenterP.y = centerP.y;
        LOG << "(" << topCenterP.x << "," << topCenterP.y << "," << topCenterP.z << ")" << thickness << height << length;
        // 创建长方体
        pGroup->addChild(createOneCuboid(topCenterP, width + thickness, thickness, length));
    }

    return pGroup.get();
}

osg::ref_ptr<osg::Node> OsgManager::createOneFace(Point3F p1, Point3F p2, Point3F p3, Point3F p4,
                                                  double r, double g, double b, double a,
                                                  Point3F normal)
{
    // 绘制面
    osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
    {
        // 创建一个用户保存几何信息的对象
        osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;
        // 创建两个顶点的数组
        osg::ref_ptr<osg::Vec3Array> pVec3Array = new osg::Vec3Array;
        // 顶点关联
        pGeometry->setVertexArray(pVec3Array.get());
        // 添加顶点
        {
            pVec3Array->push_back(osg::Vec3(p1.x, p1.y, p1.z));
            pVec3Array->push_back(osg::Vec3(p2.x, p2.y, p2.z));
            pVec3Array->push_back(osg::Vec3(p3.x, p3.y, p3.z));
            pVec3Array->push_back(osg::Vec3(p4.x, p4.y, p4.z));
        }
        // 创建种颜色的数据
        osg::ref_ptr<osg::Vec4Array> pVec4Array = new osg::Vec4Array;
        // 颜色关联
        pGeometry->setColorArray(pVec4Array.get());
        {
            // 设置绑定方式颜色:所有顶点都绑定在一个颜色上(注意:此处若不绑定画笔,则表示使用之前绑定的画笔)
            pGeometry->setColorBinding(osg::Geometry::BIND_OVERALL);
            pVec4Array->push_back(osg::Vec4(r, g, b, a));
        }

        // 为唯一的法线创建一个数组    法线: normal
        osg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;
        pGeometry->setNormalArray(pVec3ArrayNormal.get());
        {
            pGeometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
            pVec3ArrayNormal->push_back(osg::Vec3(normal.x, normal.y, normal.z));
        }

        // 由保存的数据绘制2顶点的直线(注意:传入数据量不是直线数量,而是顶点数量,2个顶线一根线)
        pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, pVec3Array->size()));

    //    pGeometry->setDataVariance(osg::Object::DYNAMIC);

        // 入坑: 一直动态不刷新,写了这条之后,禁用显示列表就可以了
        pGeometry->setUseDisplayList(false);

        // 向Geode类添加几何体(Drawable)
        pGeode->addDrawable(pGeometry.get());
    }
    return pGeode.get();
}

osg::ref_ptr<osg::Node> OsgManager::createOneCuboid(Point3F centerP, double width, double height, double length,
                                                    double r, double g, double b, double a)
{
    LOG << "长方体的中心点:" << debugInfo(centerP) << ", 宽度:" << width << "高度:" << height << "长度" << length;
    osg::ref_ptr<osg::Group> pGroup = new osg::Group;
    {
        osg::ref_ptr<osg::Group> pGroupLeft = new osg::Group;
        // 左侧的中心点计算
        // 横向左是x轴正,里外外是y轴正,纵向上是z轴正
        double x = centerP.x - width / 2;
        double y = centerP.y - length / 2;
        double z = centerP.z - height / 2;
        LOG << centerP.z << height;
        // 左侧长方体的8点计算
        // 注意:这里点的左右保持视角相同,是正向观看,所以前后得左边都在屏幕左边
        Point3F frontLeftTop      = Point3F(x        , y         , z + height);
        Point3F frontRightTop     = Point3F(x + width, y         , z + height);
        Point3F frontRightBottom  = Point3F(x + width, y         , z         );
        Point3F frontLeftBottom   = Point3F(x        , y         , z         );
        Point3F behindLeftTop     = Point3F(x        , y + length, z + height);
        Point3F behindRightTop    = Point3F(x + width, y + length, z + height);
        Point3F behindRightBottom = Point3F(x + width, y + length, z         );
        Point3F behindLeftBottom  = Point3F(x        , y + length, z         );

        // 创建面具体操作
        {
            // 这里得方向是正对正方体
            osg::ref_ptr<osg::Node> pNodeFaceFront;
            osg::ref_ptr<osg::Node> pNodeFaceRight;
            osg::ref_ptr<osg::Node> pNodeFaceBehind;
            osg::ref_ptr<osg::Node> pNodeFaceLeft;
            osg::ref_ptr<osg::Node> pNodeFaceTop;
            osg::ref_ptr<osg::Node> pNodeFaceBottom;
            pNodeFaceFront  = OsgManager::createOneFace(frontLeftTop    , frontRightTop    , frontRightBottom , frontLeftBottom,
                                                        1.0, 0.0, 0.0);
            pNodeFaceRight  = OsgManager::createOneFace(frontRightTop   , behindRightTop   , behindRightBottom, frontRightBottom,
                                                        0.0, 1.0, 0.0);
            pNodeFaceBehind = OsgManager::createOneFace(behindRightTop  , behindLeftTop    , behindLeftBottom , behindRightBottom,
                                                        0.0, 0.0, 1.0);
            pNodeFaceLeft   = OsgManager::createOneFace(behindLeftTop   , behindLeftBottom , frontLeftBottom  , frontLeftTop,
                                                        1.0, 1.0, 0.0);
            pNodeFaceTop    = OsgManager::createOneFace(behindLeftTop   , behindRightTop   , frontRightTop    , frontLeftTop,
                                                        0.0, 1.0, 1.0);
            pNodeFaceBottom = OsgManager::createOneFace(behindLeftBottom, behindRightBottom, frontRightBottom , frontLeftBottom,
                                                        1.0, 0.0, 1.0);

            pGroupLeft->addChild(pNodeFaceFront);
            pGroupLeft->addChild(pNodeFaceRight);
            pGroupLeft->addChild(pNodeFaceBehind);
            pGroupLeft->addChild(pNodeFaceLeft);
            pGroupLeft->addChild(pNodeFaceTop);
            pGroupLeft->addChild(pNodeFaceBottom);
        }
        pGroup->addChild(pGroupLeft);
    }
    return pGroup.get();
}

QString OsgManager::debugInfo(Point3F point3f)
{
    return QString("(%1, %2, %3)").arg(point3f.x).arg(point3f.y).arg(point3f.z);
}
 

工程模板v1.0.0

  在这里插入图片描述

posted @ 2024-11-15 09:59  长沙红胖子Qt创微智科  阅读(21)  评论(0编辑  收藏  举报