项目实战:Qt+OSG三维建模基础框架v1.0.0(绘制直线,输入参数,绘制通道,支持windows、linux、国产麒麟系统)
需求
1. 使用 osg 替换 opengl 建模,osg 三维对象管理,性能优化,而 opengl 依赖 cpu 计算,且对场景管控不好;
2. 右侧鼠标绘图,绘制长度的通道,可以一边画图,同步根据图来进行长度的创建通道;(这部分暂没继续实现了);
3. 左侧侧是三维场景的框架,实现基本的功能:缩放、旋转、拽托场景中心,固定轴旋转;(这块是三维引擎,没有针对项目进行漫游器、事件处理器、相机口的调整了。)
4. 基准面,绘制预计大小的基准面(这块要做无限平面,暂时这么多,无限平面得做显示范围正交投影,否则远处的会扎堆成一块黑色,已解决未放入);
本项目 v1.0.0,实现一个建模的雏形,后续会逐渐完善。
《OSG 开发笔记(三十):OSG 加载动力学仿真 K 模型文件以及测试 Demo》
《项目实战:Qt+OSG 爆破动力学仿真三维引擎测试工具 v1.1.0(加载.K 模型,子弹轨迹模拟动画,支持 windows、linux、国产麒麟系统)》
《项目实战:Qt+OSG 三维建模基础框架 v1.0.0(绘制直线,输入参数,绘制通道,支持 windows、linux、国产麒麟系统)》
#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
#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🇲🇲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));
}
<span class="hljs-keyword">return</span> pGroup.<span class="hljs-built_in">get</span>();
}
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));
}
<span class="hljs-comment">// 为唯一的法线创建一个数组 法线: normal</span>
osg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = <span class="hljs-keyword">new</span> osg::Vec3Array;
pGeometry-><span class="hljs-built_in">setNormalArray</span>(pVec3ArrayNormal.<span class="hljs-built_in">get</span>());
{
pGeometry-><span class="hljs-built_in">setNormalBinding</span>(osg::Geometry::BIND_OVERALL);
pVec3ArrayNormal-><span class="hljs-built_in">push_back</span>(osg::<span class="hljs-built_in">Vec3</span>(normal.x, normal.y, normal.z));
}
<span class="hljs-comment">// 由保存的数据绘制2顶点的直线(注意:传入数据量不是直线数量,而是顶点数量,2个顶线一根线)</span>
pGeometry-><span class="hljs-built_in">addPrimitiveSet</span>(<span class="hljs-keyword">new</span> osg::<span class="hljs-built_in">DrawArrays</span>(osg::PrimitiveSet::QUADS, <span class="hljs-number">0</span>, pVec3Array-><span class="hljs-built_in">size</span>()));
<span class="hljs-comment">// pGeometry->setDataVariance(osg::Object::DYNAMIC);</span>
<span class="hljs-comment">// 入坑: 一直动态不刷新,写了这条之后,禁用显示列表就可以了</span>
pGeometry-><span class="hljs-built_in">setUseDisplayList</span>(<span class="hljs-literal">false</span>);
<span class="hljs-comment">// 向Geode类添加几何体(Drawable)</span>
pGeode-><span class="hljs-built_in">addDrawable</span>(pGeometry.<span class="hljs-built_in">get</span>());
}
<span class="hljs-keyword">return</span> pGeode.<span class="hljs-built_in">get</span>();
}
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);
<span class="hljs-comment">// 创建面具体操作</span>
{
<span class="hljs-comment">// 这里得方向是正对正方体</span>
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::<span class="hljs-built_in">createOneFace</span>(frontLeftTop , frontRightTop , frontRightBottom , frontLeftBottom,
<span class="hljs-number">1.0</span>, <span class="hljs-number">0.0</span>, <span class="hljs-number">0.0</span>);
pNodeFaceRight = OsgManager::<span class="hljs-built_in">createOneFace</span>(frontRightTop , behindRightTop , behindRightBottom, frontRightBottom,
<span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>, <span class="hljs-number">0.0</span>);
pNodeFaceBehind = OsgManager::<span class="hljs-built_in">createOneFace</span>(behindRightTop , behindLeftTop , behindLeftBottom , behindRightBottom,
<span class="hljs-number">0.0</span>, <span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>);
pNodeFaceLeft = OsgManager::<span class="hljs-built_in">createOneFace</span>(behindLeftTop , behindLeftBottom , frontLeftBottom , frontLeftTop,
<span class="hljs-number">1.0</span>, <span class="hljs-number">1.0</span>, <span class="hljs-number">0.0</span>);
pNodeFaceTop = OsgManager::<span class="hljs-built_in">createOneFace</span>(behindLeftTop , behindRightTop , frontRightTop , frontLeftTop,
<span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>, <span class="hljs-number">1.0</span>);
pNodeFaceBottom = OsgManager::<span class="hljs-built_in">createOneFace</span>(behindLeftBottom, behindRightBottom, frontRightBottom , frontLeftBottom,
<span class="hljs-number">1.0</span>, <span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>);
pGroupLeft-><span class="hljs-built_in">addChild</span>(pNodeFaceFront);
pGroupLeft-><span class="hljs-built_in">addChild</span>(pNodeFaceRight);
pGroupLeft-><span class="hljs-built_in">addChild</span>(pNodeFaceBehind);
pGroupLeft-><span class="hljs-built_in">addChild</span>(pNodeFaceLeft);
pGroupLeft-><span class="hljs-built_in">addChild</span>(pNodeFaceTop);
pGroupLeft-><span class="hljs-built_in">addChild</span>(pNodeFaceBottom);
}
pGroup-><span class="hljs-built_in">addChild</span>(pGroupLeft);
}
<span class="hljs-keyword">return</span> pGroup.<span class="hljs-built_in">get</span>();
}
QString OsgManager::debugInfo(Point3F point3f)
{
return QString("(%1, %2, %3)").arg(point3f.x).arg(point3f.y).arg(point3f.z);
}