1 项目介绍
改项目没有使用qt中的”OpenGLWidget“组件窗口,来实现qt与osg的结合,实现可视化;
本文所用方法:实现osgwidget类,osgwidget是继承的QWidget类,所以需要QWidget类或者子类的组件,将Widget内容设置成osgwidget即可,具体用什么widget,根据自身需要来设置就行。
该项目实现的是将osg嵌入到qt中,且代码直接可以运行的,不用其他隐藏操作。同时使用CompositeViewer,可以添加多个viewer,更加灵活的添加不同对象。
(1)该项目通过CompositeViewer,osg窗口中中间显示主要可视化对象,右下角加入了一个坐标轴,随主对象旋转而旋转,可以清晰的知道对象的旋转角度。
(2)在底部加入日志窗口,可以将后续操作在日志窗口中记录下来。
2 具体介绍
1)主界面搭建
按照这个框架设置界面,按钮加了两个事件,用来添加可绘制体的;不一定非要按照这个框架,选QWidget组件就行。
2)OSG环境
.pro文件配置osg环境
ROOT = D:\SWEnvironment\OSG
FORMS += mainwindow.ui
INCLUDEPATH += $${ROOT}\include
LIBS += $${ROOT}\lib\OpenThreadsd.lib
LIBS += $${ROOT}\lib\osgd.lib
LIBS += $${ROOT}\lib\osgDBd.lib
LIBS += $${ROOT}\lib\osgGAd.lib
LIBS += $${ROOT}\lib\osgQt5d.lib
LIBS += $${ROOT}\lib\osgTextd.lib
LIBS += $${ROOT}\lib\osgUtild.lib
LIBS += $${ROOT}\lib\osgViewerd.lib
QT += opengl
3)OSGWidget类
OSGWidget类实现了几何对象的旋转、平移、缩放以及键盘事件(上下左右键可以恢复几何对象的上下左右视图);代码如下:
OSGWidget.h
#ifndef OSGWIDGET_H
#define OSGWIDGET_H
#include <QWidget>
#include <QTimer>
#include <QTextCursor>
#include <QTextEdit>
#include <QString>
#include <osgViewer/CompositeViewer>
#include <osgQt/GraphicsWindowQt>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osg/LineWidth>
#include <osg/MatrixTransform>
#include <osg/Group>
#include <osgText/Text>
#include <osg/ShapeDrawable>
#include <vector>
#include <QDebug>
//qt控件需要在特定的类中初始化
static QTextEdit* logRestore;//日志窗口
static osg::ref_ptr<osg::Group> root = new osg::Group;//osg所有显示节点的根节点
//相机矩阵
//static osg::Vec3 position;//视点坐标
//static osg::Vec3 center;
//static osg::Vec3 up;
static void UpdateLog(QString text)
{
logRestore->insertPlainText(text);
//保持log文本编辑器在光标的最后一行(自动滚屏)
logRestore->moveCursor(QTextCursor::End);
}
//显示最佳区间[7.5,7.5,7.5]至[-7.5,-7.5,-7.5]
class OSGWidget : public QWidget, public osgViewer::CompositeViewer
{
public:
OSGWidget(QWidget* parent = 0, Qt::WindowFlags f = 0, osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::CompositeViewer::SingleThreaded);
QWidget* addViewWidget(osgQt::GraphicsWindowQt* gw);
osgQt::GraphicsWindowQt* createGraphicsWindow(int x, int y, int w, int h, const std::string& name = "", bool windowDecoration = false);
virtual void paintEvent(QPaintEvent* event);
osgViewer::Viewer* view;
osg::ref_ptr<osg::Geode> makeCoordinate();
protected:
QTimer _timer;
};
/*******************以下为视角控制函数***********************/
class ViewSelect : public osgGA::TrackballManipulator
{
public:
ViewSelect() :TrackballManipulator() {}
protected:
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us){
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::KEYDOWN:
moveToView(ea);
break;
default:
break;
}
if (ea.getHandled())
return false;
return osgGA::StandardManipulator::handle(ea, us);
}
private:
void moveToView(const osgGA::GUIEventAdapter& ea){
_thrown = false;
home(0.0); //this fuction does not trigger redraw
switch (ea.getKey())
{
case osgGA::GUIEventAdapter::KEY_Down: //TOP_VIEW :
this->setRotation(osg::Quat(1.0f, 0.0, 0.0, 0.0));
UpdateLog("旋转至下视图\n");
break;
case osgGA::GUIEventAdapter::KEY_Up: //BOTTOM_VIEW :
this->setRotation(osg::Quat(0.0f, 0.0f, 0.0f, 1.0f));
UpdateLog("旋转至上视图\n");
break;
case osgGA::GUIEventAdapter::KEY_Left: // LEFT_VIEW :
this->setRotation(osg::Quat(1.0f, -1.0, -1.0, 1.0f));
UpdateLog("旋转至左视图\n");
break;
case osgGA::GUIEventAdapter::KEY_Right: //RIGHT_VIEW:
this->setRotation(osg::Quat(1.0f, 1.0f, 1.0f, 1.0f));
UpdateLog("旋转至右视图\n");
break;
case osgGA::GUIEventAdapter::KEY_1:
this->setRotation(osg::Quat(0.0f,1.0f,1.0f,0.0f));
UpdateLog("旋转至后视图\n"); // BACK_VIEW:
break;
case osgGA::GUIEventAdapter::KEY_0:
this->setRotation(osg::Quat(1.0f, 0.0f, 0.0f, 1.0f));
UpdateLog("旋转至前视图\n");//FRONT_VIEW
break;
default:
break;
}
ea.setHandled(true); //been handled
}
};
class HUDAxis :public osg::Camera
{
public:
HUDAxis(){};
HUDAxis(HUDAxis const& copy, osg::CopyOp copyOp = osg::CopyOp::SHALLOW_COPY):Camera(copy, copyOp),
_mainCamera(copy._mainCamera){};
META_Node(osg, HUDAxis);
inline void setMainCamera(Camera* camera) { _mainCamera = camera; }
virtual void traverse(osg::NodeVisitor& nv){
double fovy, aspectRatio, vNear, vFar;
_mainCamera->getProjectionMatrixAsPerspective(fovy, aspectRatio, vNear, vFar);
//this->setProjectionMatrixAsOrtho(-10.0*aspectRatio, 10.0*aspectRatio, -10.0, 10.0, 2.0, -2.0); //设置投影矩阵,使缩放不起效果
this->setProjectionMatrixAsOrtho2D(-10.0 * aspectRatio, 10.0 * aspectRatio, -10.0, 10.0);
osg::Vec3 trans(8.5 * aspectRatio, -8.5, -8.0);
if (_mainCamera.valid() && nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
{
osg::Matrix matrix = _mainCamera->getViewMatrix();//改变视图矩阵,让移动位置固定
matrix.setTrans(trans);
this->setViewMatrix(matrix);
}//if
osg::Camera::traverse(nv);
}
protected:
virtual ~HUDAxis(){};
osg::observer_ptr<Camera> _mainCamera;
};
#endif // OSGWIDGET_H
OSGWidget.cpp
#include "OSGWidget.h"
#include <QGridLayout>
#include <QDebug>
//OSGWidget窗口
OSGWidget::OSGWidget(QWidget* parent, Qt::WindowFlags f, osgViewer::ViewerBase::ThreadingModel threadingModel)
{
setThreadingModel(threadingModel);
// disable the default setting of viewer.done() by pressing Escape.
setKeyEventSetsDone(0);
QWidget* popupWidget = addViewWidget(createGraphicsWindow(900, 100, 800, 600, "Popup window", true));
QGridLayout* grid = new QGridLayout;
grid->addWidget(popupWidget, 0, 0);
setLayout(grid);
connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
_timer.start(10);
}
QWidget* OSGWidget::addViewWidget(osgQt::GraphicsWindowQt* gw)
{
view = new osgViewer::Viewer;
addView(view);
osg::Camera* camera = view->getCamera();
camera->setGraphicsContext(gw);
const osg::GraphicsContext::Traits* traits = gw->getTraits();
camera->setClearColor(osg::Vec4(0.2, 0.2, 0.4, 1.0));
camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
camera->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(traits->width) / static_cast<double>(traits->height), 1.0f, 10000.0f);
view->addEventHandler(new osgViewer::StatsHandler);
//view->addEventHandler(new AddLinePointHandler);//添加鼠标事件需要在viewer的run()和rellize()之前
//view->setCameraManipulator(new ViewSelect());
gw->setTouchEventsEnabled(true);
return gw->getGLWidget();
}
osgQt::GraphicsWindowQt* OSGWidget::createGraphicsWindow(int x, int y, int w, int h, const std::string& name, bool windowDecoration)
{
osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->windowName = name;
traits->windowDecoration = windowDecoration;
traits->x = x;
traits->y = y;
traits->width = w;
traits->height = h;
traits->doubleBuffer = true;
traits->alpha = ds->getMinimumNumAlphaBits();
traits->stencil = ds->getMinimumNumStencilBits();
traits->sampleBuffers = ds->getMultiSamples();
traits->samples = ds->getNumMultiSamples();
return new osgQt::GraphicsWindowQt(traits.get());
}
void OSGWidget::paintEvent(QPaintEvent* event)
{
frame();
}
//创建三个坐标轴
osg::ref_ptr<osg::Geode> OSGWidget::makeCoordinate()
{
osg::ref_ptr<osg::Sphere> pSphereShape = new osg::Sphere(osg::Vec3(0, 0, 0), 0.1f);
osg::ref_ptr<osg::ShapeDrawable> pShapeDrawable = new osg::ShapeDrawable(pSphereShape.get());
pShapeDrawable->setColor(osg::Vec4(0.0, 0.0, 0.0, 1.0));
//创建保存几何信息的对象
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();
//创建四个顶点
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array();
v->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
v->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
v->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
v->push_back(osg::Vec3(0.0f, 1.0f, 0.0f));
v->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
v->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));
geom->setVertexArray(v.get());
//为每个顶点指定一种颜色
osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array();
c->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); //坐标原点为红色
c->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); //x red
c->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); //坐标原点为绿色
c->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); //y green
c->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); //坐标原点为蓝色
c->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); //z blue
//如果没指定颜色则会变为黑色
geom->setColorArray(c.get());
geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
//三个轴
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, 2)); //X
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 2, 2)); //Y
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 4, 2)); //Z
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
geode->getOrCreateStateSet()->setAttribute(new osg::LineWidth(3.0), osg::StateAttribute::ON);
geode->addDrawable(pShapeDrawable.get());
geode->addDrawable(geom.get());
return geode.release();
}
4)主类-MainWindow类
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
#include <osgViewer/CompositeViewer>
#include <osgQt/GraphicsWindowQt>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osg/LineWidth>
#include <osg/MatrixTransform>
#include "osgwidget.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
static OSGWidget* osgWidget;//osg显示窗口
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void init();
void creatHud();
void creatDrawPlane();
osg::ref_ptr<osg::Node> createLightSource(unsigned int num, const osg::Vec3d& trans,
const osg::Vec3d& vecDir);
osg::ref_ptr<osg::Geometry> createCubeEdgeWireframe();
osg::ref_ptr<osg::Geometry> createGradientPlane(int gridSize, std::vector<float>& attributeValues, osg::ref_ptr<osg::Vec4Array> colors);
private slots:
void on_tabWidget_tabCloseRequested(int index);
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tabWidget->clear();
init();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::init()
{
//初始化日志窗口和osg显示窗口
logRestore = new QTextEdit();
osgWidget = new OSGWidget(0, Qt::Widget, osgViewer::ViewerBase::SingleThreaded);
//osg显示窗口添加绘制平面
creatDrawPlane();
//osg显示窗口右下角添加hud
creatHud();
// root->addChild(points_ctrl);//子节点3
// root->addChild(lines_ctrl);//子节点4
ui->tabWidget->setTabsClosable(true);
//日志窗口填充文字编辑
logRestore->setReadOnly(true);
ui->bottomDockWidget->setWidget(logRestore);
osgWidget->view->setCameraManipulator(new ViewSelect());
osgWidget->view->setSceneData(root);
}
void MainWindow::creatHud()
{
osg::ref_ptr<HUDAxis> hudAxes = new HUDAxis;
hudAxes->addChild(osgWidget->makeCoordinate());
hudAxes->setMainCamera(osgWidget->view->getCamera());
hudAxes->setRenderOrder(osg::Camera::POST_RENDER);
hudAxes->setClearMask(GL_DEPTH_BUFFER_BIT);
hudAxes->setAllowEventFocus(false);
hudAxes->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
hudAxes->setName("hudAxes");
root->addChild(hudAxes);//子节点2
}
void MainWindow::creatDrawPlane()
{
osg::ref_ptr<osg::Vec3Array> planeVertices = new osg::Vec3Array();
planeVertices->push_back(osg::Vec3f(7.5f, 7.5f, 0.0f));//0
planeVertices->push_back(osg::Vec3f(7.5f, -7.5f, 0.0f));//1
planeVertices->push_back(osg::Vec3f(-7.5f, -7.5f, 0.0f));//2
planeVertices->push_back(osg::Vec3f(-7.5f, 7.5f, 0.0f));//3
planeVertices->push_back(osg::Vec3f(0.0f, 7.5f, 7.5f));//4
planeVertices->push_back(osg::Vec3f(0.0f, 7.5f, -7.5f));//5
planeVertices->push_back(osg::Vec3f(0.0f, -7.5f, -7.5f));//6
planeVertices->push_back(osg::Vec3f(0.0f, -7.5f, 7.5f));//7
planeVertices->push_back(osg::Vec3f(7.5f, 0.0f, 7.5f));//8
planeVertices->push_back(osg::Vec3f(7.5f, 0.0f, -7.5f));//9
planeVertices->push_back(osg::Vec3f(-7.5f, 0.0f, -7.5f));//10
planeVertices->push_back(osg::Vec3f(-7.5f, 0.0f, 7.5f));//11
planeVertices->push_back(osg::Vec3f(7.5f, 0.0f, 0.0f));//12
planeVertices->push_back(osg::Vec3f(-7.5f, 0.0f, 0.0f));//13
planeVertices->push_back(osg::Vec3f(0.0f, 0.0f, 7.5f));//14
planeVertices->push_back(osg::Vec3f(0.0f, 0.0f, -7.5f));//15
planeVertices->push_back(osg::Vec3f(0.0f, 7.5f, 0.0f));//16
planeVertices->push_back(osg::Vec3f(0.0f, -7.5f, 0.0f));//17
planeVertices->push_back(osg::Vec3f(0.0f, 0.0f, 0.0f));//18
osg::ref_ptr<osg::DrawElementsUInt> planeIndices = new osg::DrawElementsUInt(GL_QUADS, 48);
//xoy
(*planeIndices)[0] = 18; (*planeIndices)[1] = 12; (*planeIndices)[2] = 0; (*planeIndices)[3] = 16;
(*planeIndices)[4] = 18; (*planeIndices)[5] = 12; (*planeIndices)[6] = 1; (*planeIndices)[7] = 17;
(*planeIndices)[8] = 18; (*planeIndices)[9] = 13; (*planeIndices)[10] = 2; (*planeIndices)[11] = 17;
(*planeIndices)[12] = 18; (*planeIndices)[13] = 13; (*planeIndices)[14] = 3; (*planeIndices)[15] = 16;
//xoz
(*planeIndices)[16] = 18; (*planeIndices)[17] = 14; (*planeIndices)[18] = 8; (*planeIndices)[19] = 12;
(*planeIndices)[20] = 18; (*planeIndices)[21] = 14; (*planeIndices)[22] = 11; (*planeIndices)[23] = 13;
(*planeIndices)[24] = 18; (*planeIndices)[25] = 15; (*planeIndices)[26] = 9; (*planeIndices)[27] = 12;
(*planeIndices)[28] = 18; (*planeIndices)[29] = 15; (*planeIndices)[30] = 10; (*planeIndices)[31] = 13;
//yoz
(*planeIndices)[32] = 18; (*planeIndices)[33] = 16; (*planeIndices)[34] = 4; (*planeIndices)[35] = 14;
(*planeIndices)[36] = 18; (*planeIndices)[37] = 16; (*planeIndices)[38] = 5; (*planeIndices)[39] = 15;
(*planeIndices)[40] = 18; (*planeIndices)[41] = 17; (*planeIndices)[42] = 6; (*planeIndices)[43] = 15;
(*planeIndices)[44] = 18; (*planeIndices)[45] = 17; (*planeIndices)[46] = 7; (*planeIndices)[47] = 14;
osg::ref_ptr<osg::Vec4Array> quadsColors = new osg::Vec4Array;
quadsColors->push_back(osg::Vec4(0.2, 0.2, 0.2, 1));
osg::ref_ptr<osg::Geometry> geom_QUADS = new osg::Geometry;
geom_QUADS->setVertexArray(planeVertices.get());
geom_QUADS->addPrimitiveSet(planeIndices.get());
geom_QUADS->setColorArray(quadsColors);
geom_QUADS->setColorBinding(osg::Geometry::BIND_OVERALL);
osg::ref_ptr<osg::DrawElementsUInt> linesIndices = new osg::DrawElementsUInt(GL_LINES, 96);
//xoy
(*linesIndices)[0] = 18; (*linesIndices)[1] = 14;
(*linesIndices)[2] = 14; (*linesIndices)[3] = 8;
(*linesIndices)[4] = 8; (*linesIndices)[5] = 12;
(*linesIndices)[6] = 12; (*linesIndices)[7] = 18;
(*linesIndices)[8] = 18; (*linesIndices)[9] = 14;
(*linesIndices)[10] = 14; (*linesIndices)[11] = 11;
(*linesIndices)[12] = 11; (*linesIndices)[13] = 13;
(*linesIndices)[14] = 13; (*linesIndices)[15] = 18;
(*linesIndices)[16] = 18; (*linesIndices)[17] = 13;
(*linesIndices)[18] = 13; (*linesIndices)[19] = 2;
(*linesIndices)[20] = 2; (*linesIndices)[21] = 17;
(*linesIndices)[22] = 17; (*linesIndices)[23] = 18;
(*linesIndices)[24] = 18; (*linesIndices)[25] = 13;
(*linesIndices)[26] = 13; (*linesIndices)[27] = 3;
(*linesIndices)[28] = 3; (*linesIndices)[29] = 16;
(*linesIndices)[30] = 16; (*linesIndices)[31] = 18;
//xoz
(*linesIndices)[32] = 18; (*linesIndices)[33] = 12;
(*linesIndices)[34] = 12; (*linesIndices)[35] = 0;
(*linesIndices)[36] = 0; (*linesIndices)[37] = 16;
(*linesIndices)[38] = 16; (*linesIndices)[39] = 18;
(*linesIndices)[40] = 18; (*linesIndices)[41] = 12;
(*linesIndices)[42] = 12; (*linesIndices)[43] = 1;
(*linesIndices)[44] = 1; (*linesIndices)[45] = 17;
(*linesIndices)[46] = 17; (*linesIndices)[47] = 18;
(*linesIndices)[48] = 18; (*linesIndices)[49] = 15;
(*linesIndices)[50] = 15; (*linesIndices)[51] = 9;
(*linesIndices)[52] = 9; (*linesIndices)[53] = 12;
(*linesIndices)[54] = 12; (*linesIndices)[55] = 18;
(*linesIndices)[56] = 18; (*linesIndices)[57] = 15;
(*linesIndices)[58] = 15; (*linesIndices)[59] = 10;
(*linesIndices)[60] = 10; (*linesIndices)[61] = 13;
(*linesIndices)[62] = 13; (*linesIndices)[63] = 18;
//yoz
(*linesIndices)[64] = 18; (*linesIndices)[65] = 16;
(*linesIndices)[66] = 16; (*linesIndices)[67] = 4;
(*linesIndices)[68] = 4; (*linesIndices)[69] = 14;
(*linesIndices)[70] = 14; (*linesIndices)[71] = 18;
(*linesIndices)[72] = 18; (*linesIndices)[73] = 16;
(*linesIndices)[74] = 16; (*linesIndices)[75] = 5;
(*linesIndices)[76] = 5; (*linesIndices)[77] = 15;
(*linesIndices)[78] = 15; (*linesIndices)[79] = 18;
(*linesIndices)[80] = 18; (*linesIndices)[81] = 17;
(*linesIndices)[82] = 17; (*linesIndices)[83] = 6;
(*linesIndices)[84] = 6; (*linesIndices)[85] = 15;
(*linesIndices)[86] = 15; (*linesIndices)[87] = 18;
(*linesIndices)[88] = 18; (*linesIndices)[89] = 17;
(*linesIndices)[90] = 17; (*linesIndices)[91] = 7;
(*linesIndices)[92] = 7; (*linesIndices)[93] = 14;
(*linesIndices)[94] = 14; (*linesIndices)[95] = 18;
osg::ref_ptr<osg::Geometry> geom_lINES = new osg::Geometry;
geom_lINES->setVertexArray(planeVertices.get());
geom_lINES->addPrimitiveSet(linesIndices.get());
osg::ref_ptr<osg::Vec4Array> lineColors = new osg::Vec4Array;
lineColors->push_back(osg::Vec4(0., 0., 0., 1.));
geom_lINES->setColorArray(lineColors);
geom_lINES->setColorBinding(osg::Geometry::BIND_OVERALL);
/****************************设置上下左右近远六个光源,但是没写阴影*********************************/
osg::ref_ptr<osg::StateSet> stateset = root->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
stateset->setMode(GL_LIGHT6, osg::StateAttribute::ON); // GL_LIGHT0是默认光源
// 设置6个光源 解决光照问题
osg::Vec3d ptLight;
osg::Vec3d ptCenter = osg::Vec3d(0, 0, 0);
double dDis = 200000.0;
ptLight = ptCenter + osg::Z_AXIS * dDis;
osg::ref_ptr<osg::Node> pNodeLight = createLightSource(6, ptLight, -osg::Z_AXIS);
pNodeLight->setName("light0");
root->addChild(pNodeLight);
osg::ref_ptr<osg::Group> group = new osg::Group();
osg::ref_ptr<osg::Geode> geode_QUADS = new osg::Geode();
geode_QUADS->addDrawable(geom_QUADS.get());
osg::ref_ptr<osg::Geode> geode_LINES = new osg::Geode();
geode_LINES->addDrawable(geom_lINES.get());
group->addChild(geode_QUADS);
group->addChild(geom_lINES);
group->setName("DrawPlane");
root->addChild(group);//子节点1
}
osg::ref_ptr<osg::Node> MainWindow::createLightSource(unsigned int num, const osg::Vec3d &trans, const osg::Vec3d &vecDir)
{
osg::ref_ptr<osg::Light> light = new osg::Light;
light->setLightNum(num);
light->setDirection(vecDir);
osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource;
lightSource->setLight(light);
osg::ref_ptr<osg::MatrixTransform> sourceTrans = new osg::MatrixTransform;
sourceTrans->setMatrix(osg::Matrix::translate(trans));
sourceTrans->addChild(lightSource.get());
return sourceTrans.release();
}
void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
qDebug()<<index;
ui->tabWidget->removeTab(index);
}
void MainWindow::on_pushButton_clicked()
{
UpdateLog("生成显示窗口\n");
ui->tabWidget->addTab(osgWidget,"SemismicViewer");
}
// 创建边框的几何体
osg::ref_ptr<osg::Geometry> MainWindow::createCubeEdgeWireframe()
{
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
float size = 7.5f;
// 正方体的 8 个顶点
vertices->push_back(osg::Vec3(-size, -size, -size));
vertices->push_back(osg::Vec3(size, -size, -size));
vertices->push_back(osg::Vec3(size, size, -size));
vertices->push_back(osg::Vec3(-size, size, -size));
vertices->push_back(osg::Vec3(-size, -size, size));
vertices->push_back(osg::Vec3(size, -size, size));
vertices->push_back(osg::Vec3(size, size, size));
vertices->push_back(osg::Vec3(-size, size, size));
osg::ref_ptr<osg::DrawElementsUInt> edges = new osg::DrawElementsUInt(GL_LINES);
// 正方体边框的 12 条边
edges->push_back(0); edges->push_back(1);
edges->push_back(1); edges->push_back(2);
edges->push_back(2); edges->push_back(3);
edges->push_back(3); edges->push_back(0);
edges->push_back(4); edges->push_back(5);
edges->push_back(5); edges->push_back(6);
edges->push_back(6); edges->push_back(7);
edges->push_back(7); edges->push_back(4);
edges->push_back(0); edges->push_back(4);
edges->push_back(1); edges->push_back(5);
edges->push_back(2); edges->push_back(6);
edges->push_back(3); edges->push_back(7);
geometry->setVertexArray(vertices);
geometry->addPrimitiveSet(edges);
// 设置边框颜色为白色
osg::ref_ptr<osg::Vec4Array> edgeColors = new osg::Vec4Array;
edgeColors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
geometry->setColorArray(edgeColors, osg::Array::BIND_OVERALL);
// 设置线宽
osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth(1.6f); // 线宽
geometry->getOrCreateStateSet()->setAttributeAndModes(lineWidth, osg::StateAttribute::ON);
return geometry.release();
}
//颜色映射函数
// 随机生成的属性值范围
const float ATTRIBUTE_MIN = 0.0f;
const float ATTRIBUTE_MAX = 500.0f;
osg::Vec4 mapValueToColor(float value)
{
float normalized = (value - ATTRIBUTE_MIN) / (ATTRIBUTE_MAX - ATTRIBUTE_MIN); // 将值归一化到 [0, 1]
if (normalized <= 0.2f) // 红到黄
return osg::Vec4(1.0f, normalized / 0.2f, 0.0f, 1.0f);
else if (normalized <= 0.4f) // 黄到绿
return osg::Vec4(1.0f - (normalized - 0.2f) / 0.2f, 1.0f, 0.0f, 1.0f);
else if (normalized <= 0.6f) // 绿到青
return osg::Vec4(0.0f, 1.0f, (normalized - 0.4f) / 0.2f, 1.0f);
else if (normalized <= 0.8f) // 青到蓝
return osg::Vec4(0.0f, 1.0f - (normalized - 0.6f) / 0.2f, 1.0f, 1.0f);
else // 蓝色
return osg::Vec4(0.0f, 0.0f, 1.0f - (normalized - 0.8f) / 0.2f, 1.0f);
}
osg::ref_ptr<osg::Geometry> MainWindow::createGradientPlane(int gridSize, std::vector<float>& attributeValues, osg::ref_ptr<osg::Vec4Array> colors)
{
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
geometry->setUseDisplayList(false); // 禁用 Display List
geometry->setUseVertexBufferObjects(true); // 启用 VBO
float size = 15.0f;
float step = size / gridSize;
// 创建平面上的点和颜色
for (int i = 0; i <= gridSize; ++i)
{
for (int j = 0; j <= gridSize; ++j)
{
float x = -size / 2 + i * step;
float y = -size / 2 + j * step;
float z = 0.0f;
vertices->push_back(osg::Vec3(x, y, z));
// 为每个点生成一个随机属性值
float attributeValue = ATTRIBUTE_MIN + static_cast<float>(rand()) / RAND_MAX * (ATTRIBUTE_MAX - ATTRIBUTE_MIN);
attributeValues.push_back(attributeValue); // 存储属性值
colors->push_back(mapValueToColor(attributeValue)); // 将属性值映射到颜色
}
}
// 创建平面上的矩形图元
for (int i = 0; i < gridSize; ++i)
{
for (int j = 0; j < gridSize; ++j)
{
int idx0 = i * (gridSize + 1) + j;
int idx1 = idx0 + 1;
int idx2 = idx0 + (gridSize + 1);
int idx3 = idx2 + 1;
osg::ref_ptr<osg::DrawElementsUInt> quad = new osg::DrawElementsUInt(GL_QUADS);
quad->push_back(idx0);
quad->push_back(idx1);
quad->push_back(idx3);
quad->push_back(idx2);
geometry->addPrimitiveSet(quad);
}
}
geometry->setVertexArray(vertices);
geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); // 每个顶点有单独的颜色
return geometry.release();
}
void MainWindow::on_pushButton_2_clicked()
{
root->removeChild(0, root->getNumChildren());
osg::ref_ptr<osg::Geometry> cubeEdgesframe = createCubeEdgeWireframe();
osg::ref_ptr<osg::Geode> wireframeGeode = new osg::Geode;
wireframeGeode->addDrawable(cubeEdgesframe);
int gridSize = 6; // 6x6 网格,总共 36 个矩形
std::vector<float> attributeValues; // 存储每个点的属性值
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array; // 存储每个点的颜色
osg::ref_ptr<osg::Geometry> plane = createGradientPlane(gridSize, attributeValues, colors);
osg::ref_ptr<osg::Geode> planeGeode = new osg::Geode;
planeGeode->addDrawable(plane);
/****************************设置上下左右近远六个光源,但是没写阴影*********************************/
osg::ref_ptr<osg::StateSet> stateset = root->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
stateset->setMode(GL_LIGHT6, osg::StateAttribute::ON); // GL_LIGHT0是默认光源
// 设置6个光源 解决光照问题
osg::Vec3d ptLight;
osg::Vec3d ptCenter = osg::Vec3d(0, 0, 0);
double dDis = 200000.0;
ptLight = ptCenter + osg::Z_AXIS * dDis;
osg::ref_ptr<osg::Node> pNodeLight = createLightSource(6, ptLight, -osg::Z_AXIS);
pNodeLight->setName("light0");
root->addChild(pNodeLight);
creatHud();
root->addChild(wireframeGeode);
root->addChild(planeGeode);
}
3 效果图
初始运行图:
“SeismicViewer"按钮显示效果
"绘制面"
4 最后
如果需要添加自己的可视化对象,可以在"绘制面"方法中写自己的方法就行。