OpenSceneGraph(OSG)开发学习

功能模块 简介
osg 场景图核心类
osgDB 读写模型/图像文件
osgViewer 创建窗口/渲染主循环
osgGA 相机操作与输入事件处理
osgUtil 几何处理(求交、LOD、裁剪等)
osgText 文本绘制支持

示例1:渲染一个正方体

cpp 复制代码
#ifndef OSGWIDGET_H
#define OSGWIDGET_H

#include <QOpenGLWidget>
#include <osgViewer/Viewer>
#include <QMouseEvent>
class OSGWidget : public QOpenGLWidget {
    Q_OBJECT
public:
    explicit OSGWidget(QWidget* parent = nullptr);
    virtual ~OSGWidget() override;
protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;
    void mousePressEvent(QMouseEvent* event) override;
    void mouseReleaseEvent(QMouseEvent* event) override;
    void mouseMoveEvent(QMouseEvent* event) override;
    void wheelEvent(QWheelEvent* event) override;

private:
    osg::ref_ptr<osgViewer::Viewer> viewer;
    osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> graphicsWindow;
};

#endif // OSGWIDGET_H
cpp 复制代码
#include "osgwidget.h"
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/Material>
#include <osg/Light>
#include <osg/LightSource>
#include <osg/MatrixTransform>
#include <osgGA/TrackballManipulator>
#include <QDebug>
#include<QTimer>

OSGWidget::OSGWidget(QWidget* parent) : QOpenGLWidget(parent)
{
    // 1. 创建Viewer和图形窗口
    viewer = new osgViewer::Viewer;
    viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);

    graphicsWindow = new osgViewer::GraphicsWindowEmbedded(
        this->x(), this->y(), width(),height());
    graphicsWindow->getEventQueue()->getCurrentEventState()->setWindowRectangle(
           0, 0, width(), height());
    // 2. 配置相机(关键修改)
    osg::Camera* camera = viewer->getCamera();
    camera->setGraphicsContext(graphicsWindow);
    camera->setViewport(0, 0, width(), height());
    camera->setClearColor(osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f)); // 蓝色背景

    // 设置合理的投影矩阵
    camera->setProjectionMatrixAsPerspective(
        30.0f,                          // 视野角度
        float(width())/float(height()), // 宽高比
        0.1f,                          // 近平面
        100.0f                         // 远平面
    );

    // 3. 添加跟踪球控制器(支持鼠标交互)
    viewer->setCameraManipulator(new osgGA::TrackballManipulator);
     viewer->getCamera()->setGraphicsContext(graphicsWindow);
    viewer->getCameraManipulator()->setHomePosition(
        osg::Vec3(0, -5, 3),  // 眼睛位置
        osg::Vec3(0, 0, 0),    // 中心点
        osg::Vec3(0, 0, 1)     // 上方向
    );
    viewer->home();

    // 4. 创建带光照的红色立方体(关键修改)
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(), 1.0f)));

    // 设置红色材质
    osg::ref_ptr<osg::Material> material = new osg::Material;
    material->setDiffuse(osg::Material::FRONT, osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
    geode->getOrCreateStateSet()->setAttribute(material);

    // 5. 添加光源(关键修改)
    osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource;
    osg::ref_ptr<osg::Light> light = new osg::Light;
    light->setLightNum(0);
    light->setPosition(osg::Vec4(1.0f, 1.0f, 1.0f, 0.0f)); // 方向光
    light->setDiffuse(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
    light->setAmbient(osg::Vec4(0.2f, 0.2f, 0.2f, 1.0f));
    lightSource->setLight(light);

    // 6. 构建场景图
    osg::ref_ptr<osg::Group> root = new osg::Group;
    root->addChild(lightSource);
    root->addChild(geode);

    viewer->setSceneData(root);
    // 在构造函数最后添加
    qDebug() << "Viewer scene valid:" << (viewer->getSceneData() != nullptr);
    // 定时器保证最小刷新率(可选)
    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, [this](){
        if(!this->isVisible()) return;
        update();
    });
    timer->start(16); // ~60fps
}

void OSGWidget::initializeGL()
{
    viewer->realize();
    viewer->home();  // 重置视角到初始位置
}

void OSGWidget::paintGL()
{
    viewer->frame();
    update(); // 新增:强制持续刷新
}

void OSGWidget::resizeGL(int w, int h)
{
    graphicsWindow->resized(this->x(), this->y(), w, h);
    viewer->getCamera()->setViewport(0, 0, w, h);
    viewer->getCamera()->setProjectionMatrixAsPerspective(
        30.0f, float(w)/float(h), 0.1f, 100.0f);
}
OSGWidget::~OSGWidget()
{
    // 清理OSG资源
    if(viewer) {
        viewer->setSceneData(nullptr);
        viewer = nullptr;
    }
    graphicsWindow = nullptr;
}
// 新增事件处理函数实现
void OSGWidget::mousePressEvent(QMouseEvent* event) {
    graphicsWindow->getEventQueue()->mouseButtonPress(
        event->x(), event->y(),
        (event->button() == Qt::LeftButton) ? 1 :
        (event->button() == Qt::MiddleButton) ? 2 : 3);
    update(); // 新增:事件处理后立即请求重绘
}

void OSGWidget::mouseReleaseEvent(QMouseEvent* event) {
    graphicsWindow->getEventQueue()->mouseButtonRelease(
        event->x(), event->y(),
        (event->button() == Qt::LeftButton) ? 1 :
        (event->button() == Qt::MiddleButton) ? 2 : 3);
    update(); // 新增:事件处理后立即请求重绘
}

void OSGWidget::mouseMoveEvent(QMouseEvent* event) {
    graphicsWindow->getEventQueue()->mouseMotion(event->x(), event->y());
    update(); // 新增:事件处理后立即请求重绘
}

void OSGWidget::wheelEvent(QWheelEvent* event) {
    graphicsWindow->getEventQueue()->mouseScroll(
        event->angleDelta().y() > 0 ?
        osgGA::GUIEventAdapter::SCROLL_UP :
        osgGA::GUIEventAdapter::SCROLL_DOWN);
    update(); // 新增:事件处理后立即请求重绘
}
cpp 复制代码
#include <QApplication>
#include "osgwidget.h"

int main(int argc, char** argv) {
    QApplication app(argc, argv);
    // 强制使用软件渲染(解决虚拟机/驱动兼容性问题)
    qputenv("LIBGL_ALWAYS_SOFTWARE", "1");
    qputenv("QT_XCB_FORCE_SOFTWARE_OPENGL", "1");
    OSGWidget widget;
    widget.resize(800, 600);
    widget.setWindowTitle("OSG");
    widget.show();

    return app.exec();
}

示例2:渲染一个飞行器

cpp 复制代码
QT       += core gui opengl

greaterThan(QT_MAJOR_VERSION, 5)

TARGET = osgdemo2
TEMPLATE = app

CONFIG += c++17

DEFINES += QT_DEPRECATED_WARNINGS

LIBS += -L/usr/local/lib \
        -losg\
        -losgViewer\
        -losgGA\
        -losgDB\
        -lOpenThreads\
        -losgUtil
INCLUDEPATH += /usr/local/include

SOURCES += \
        main.cpp \
        graphicswindowqt.cpp

HEADERS += \
        graphicswindowqt.h

FORMS += \
        mainwindow.ui
cpp 复制代码
#ifndef GRAPHICSWINDOWQT_H
#define GRAPHICSWINDOWQT_H

#include <QOpenGLWidget>
#include <osgViewer/Viewer>
#include <osgViewer/GraphicsWindow>

class QInputEvent;
class GraphicsWindowQt : public QOpenGLWidget, public osgViewer::Viewer
{
    Q_OBJECT

public:
    GraphicsWindowQt(QWidget *parent = 0);
    ~GraphicsWindowQt();

    bool event(QEvent *e);
    void setKeyboardModifiers(QInputEvent *event);
    void keyPressEvent(QKeyEvent *event);
    void keyReleaseEvent(QKeyEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseDoubleClickEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void wheelEvent(QWheelEvent *event);
    void resizeEvent(QResizeEvent *event);
    void moveEvent(QMoveEvent *event);
    void timerEvent(QTimerEvent *);

protected:
    virtual void paintGL();

private:
    void init3D();
    osg::ref_ptr<osg::Camera> createCamera(int x,int y,int w,int h);

private:
    osg::ref_ptr<osg::Group> root;
    osgViewer::GraphicsWindow *window;
};

#endif // GRAPHICSWINDOWQT_H
cpp 复制代码
#include "graphicswindowqt.h"
#include <QInputEvent>
#include <QApplication>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgGA/GUIEventAdapter>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/StateSetManipulator>
#include <osg/ShapeDrawable>
#include <osg/Light>
#include <osg/LightSource>
#include <QDebug>
GraphicsWindowQt::GraphicsWindowQt(QWidget *parent)
    : QOpenGLWidget(parent)
{
    init3D();
    setMouseTracking(true);
    setFocusPolicy(Qt::StrongFocus);
}

GraphicsWindowQt::~GraphicsWindowQt()
{

}

bool GraphicsWindowQt::event(QEvent *e)
{
    switch (e->type()) {
    case QEvent::TouchBegin:
    case QEvent::TouchEnd:
    case QEvent::TouchUpdate: {
        QList<QTouchEvent::TouchPoint> touchPoints = static_cast<QTouchEvent *>(e)->touchPoints();
        unsigned int id = 0;
        unsigned int tapCount = touchPoints.size();

        osg::ref_ptr<osgGA::GUIEventAdapter> osgEvent(NULL);
        osgGA::GUIEventAdapter::TouchPhase phase = osgGA::GUIEventAdapter::TOUCH_UNKNOWN;
        foreach(const QTouchEvent::TouchPoint &touchPoint, touchPoints) {
            if (!osgEvent) {
                if (e->type() == QEvent::TouchBegin) {
                    phase = osgGA::GUIEventAdapter::TOUCH_BEGAN;
                    osgEvent = window->getEventQueue()->touchBegan(id, osgGA::GUIEventAdapter::TOUCH_BEGAN, touchPoint.pos().x(), touchPoint.pos().y());
                } else if (e->type() == QEvent::TouchEnd) {
                    phase = osgGA::GUIEventAdapter::TOUCH_ENDED;
                    osgEvent = window->getEventQueue()->touchEnded(id, osgGA::GUIEventAdapter::TOUCH_ENDED, touchPoint.pos().x(), touchPoint.pos().y(), tapCount);
                } else if (e->type() == QEvent::TouchUpdate) {
                    phase = osgGA::GUIEventAdapter::TOUCH_MOVED;
                    osgEvent = window->getEventQueue()->touchMoved(id, osgGA::GUIEventAdapter::TOUCH_MOVED, touchPoint.pos().x(), touchPoint.pos().y());
                }
            } else {
                osgEvent->addTouchPoint(id, osgGA::GUIEventAdapter::TOUCH_ENDED, touchPoint.pos().x(), touchPoint.pos().y());
                osgEvent->addTouchPoint(id, phase, touchPoint.pos().x(), touchPoint.pos().y());
            }
            id++;
        }
        break;
    }
    default:
        break;
    }
    return QOpenGLWidget::event(e);
}

void GraphicsWindowQt::setKeyboardModifiers(QInputEvent *event)
{
    int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier);
    unsigned int mask = 0;
    if (modkey & Qt::ShiftModifier) {
        mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
    }
    if (modkey & Qt::ControlModifier) {
        mask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
    }
    if (modkey & Qt::AltModifier) {
        mask |= osgGA::GUIEventAdapter::MODKEY_ALT;
    }

    window->getEventQueue()->getCurrentEventState()->setModKeyMask(mask);
    update();
}

void GraphicsWindowQt::keyPressEvent(QKeyEvent *event)
{
    setKeyboardModifiers(event);
    window->getEventQueue()->keyPress(event->key());
    qDebug() << "key pressed.";
    QOpenGLWidget::keyPressEvent(event);
    update();
}

void GraphicsWindowQt::keyReleaseEvent(QKeyEvent *event)
{
    setKeyboardModifiers(event);
    window->getEventQueue()->keyRelease(event->key());
    QOpenGLWidget::keyReleaseEvent(event);
    update();
}

void GraphicsWindowQt::mousePressEvent(QMouseEvent *event)
{
    int button = 0;
    switch (event->button()) {
    case Qt::LeftButton: button = 1; break;
    case Qt::MiddleButton: button = 2; break;
    case Qt::RightButton: button = 3; break;
    case Qt::NoButton: button = 0; break;
    default: button = 0; break;
    }
    setKeyboardModifiers(event);
    window->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
    update();
}

void GraphicsWindowQt::mouseReleaseEvent(QMouseEvent *event)
{
    int button = 0;

    switch (event->button()) {
    case Qt::LeftButton: button = 1; break;
    case Qt::MiddleButton: button = 2; break;
    case Qt::RightButton: button = 3; break;
    case Qt::NoButton: button = 0; break;
    default: button = 0; break;
    }

    setKeyboardModifiers(event);
    window->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);

    QOpenGLWidget::mouseReleaseEvent(event);
    update();
}

void GraphicsWindowQt::mouseDoubleClickEvent(QMouseEvent *event)
{
    int button = 0;
    switch (event->button()) {
    case Qt::LeftButton: button = 1; break;
    case Qt::MiddleButton: button = 2; break;
    case Qt::RightButton: button = 3; break;
    case Qt::NoButton: button = 0; break;
    default: button = 0; break;
    }
    setKeyboardModifiers(event);
    window->getEventQueue()->mouseDoubleButtonPress(event->x(), event->y(), button);

    QOpenGLWidget::mouseDoubleClickEvent(event);
    update();
}

void GraphicsWindowQt::mouseMoveEvent(QMouseEvent *event)
{
    setKeyboardModifiers(event);
    window->getEventQueue()->mouseMotion(event->x(), event->y());
    QOpenGLWidget::mouseMoveEvent(event);
    update();
}

void GraphicsWindowQt::wheelEvent(QWheelEvent *event)
{
    setKeyboardModifiers(event);
#if(QT_VERSION < QT_VERSION_CHECK(6,0,0))
    window->getEventQueue()->mouseScroll(
        event->orientation() == Qt::Vertical ?
            (event->delta() > 0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) :
            (event->delta() > 0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT));
#else
    window->getEventQueue()->mouseScroll(

        event->angleDelta().y() != 0 ?
            (event->angleDelta().y() > 0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) :
            (event->angleDelta().x() > 0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT));
#endif
    QOpenGLWidget::wheelEvent(event);
    update();
}

void GraphicsWindowQt::resizeEvent(QResizeEvent *event)
{
    const QSize &size = event->size();
    window->resized(x(), y(), size.width(), size.height());
    window->getEventQueue()->windowResize(x(), y(), size.width(), size.height());
    window->requestRedraw();
    QOpenGLWidget::resizeEvent(event);
}

void GraphicsWindowQt::moveEvent(QMoveEvent *event)
{
    const QPoint &pos = event->pos();
    window->resized(pos.x(), pos.y(), width(), height());
    window->getEventQueue()->windowResize(pos.x(), pos.y(), width(), height());

    QOpenGLWidget::moveEvent(event);
}

void GraphicsWindowQt::timerEvent(QTimerEvent *)
{
    update();
}

void GraphicsWindowQt::paintGL()
{
    if (isVisibleTo(QApplication::activeWindow())) {
        frame();
    }
}

void GraphicsWindowQt::init3D()
{
    osg::ref_ptr<osg::Node> nd = osgDB::readNodeFile("/mnt/hgfs/gongxiang/OpenSceneGraph-Data-3.4.0/OpenSceneGraph-Data/glider.osg");

    root = new osg::Group();

    root->addChild(nd);

    setCamera(createCamera(0, 0, width(), height()));

    setCameraManipulator(new osgGA::TrackballManipulator);
    addEventHandler(new osgViewer::StatsHandler);
    addEventHandler(new osgViewer::ThreadingHandler());
    addEventHandler(new osgViewer::HelpHandler);
    addEventHandler(new osgGA::StateSetManipulator(this->getCamera()->getOrCreateStateSet()));
    setThreadingModel(osgViewer::Viewer::SingleThreaded);

    setSceneData(root);
    realize();
    getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
    getCamera()->setNearFarRatio(0.000003f);

    //    setRunFrameScheme(ON_DEMAND);

    startTimer(10);
}

osg::ref_ptr<osg::Camera> GraphicsWindowQt::createCamera(int x, int y, int w, int h)
{
    window = new osgViewer::GraphicsWindowEmbedded(x, y, w, h);
    //    osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
    traits->windowDecoration = false;
    traits->x = x;
    traits->y = y;
    traits->width = w;
    traits->height = h;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;
    traits->windowDecoration = false;

    traits->setInheritedWindowPixelFormat = true;
    osg::ref_ptr<osg::Camera> camera = new osg::Camera;

    camera->setGraphicsContext(window);
    camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
    camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    camera->setProjectionMatrixAsPerspective(
        30.0f, double(traits->width) / double(traits->height), 1.0f, 10000.0f);
    camera->setClearColor(osg::Vec4f(0.1,0.3, 0.5,0.4));  //改背景色
    return camera.release();
}
cpp 复制代码
#include "mainwindow.h"
#include <QApplication>
#include "graphicswindowqt.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    GraphicsWindowQt w;
    w.show();
    w.resize(1200,800);
    return a.exec();
}

示例3:渲染一头牛

cpp 复制代码
#include "mainwindow.h"
#include <QApplication>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    osgViewer::Viewer viewer;
    viewer.setSceneData(osgDB::readNodeFile("/mnt/hgfs/gongxiang/cow.osg"));
    viewer.run();
    return a.exec();
}
相关推荐
九年义务漏网鲨鱼1 小时前
【大模型学习 | MINIGPT-4原理】
人工智能·深度学习·学习·语言模型·多模态
jz_ddk2 小时前
[学习] C语言数学库函数背后的故事:`double erf(double x)`
c语言·开发语言·学习
爱莉希雅&&&3 小时前
技术面试题,HR面试题
开发语言·学习·面试
Chef_Chen4 小时前
从0开始学习计算机视觉--Day08--卷积神经网络
学习·计算机视觉·cnn
weixin_446260854 小时前
Isaac Lab:让机器人学习更简单的开源框架
学习·机器人
永日456706 小时前
学习日记-spring-day42-7.7
java·学习·spring
Love__Tay9 小时前
笔记/云计算基础
笔记·学习·云计算
wuxuanok12 小时前
Web后端开发-分层解耦
java·笔记·后端·学习
wuxuanok13 小时前
Web后端开发-请求响应
java·开发语言·笔记·学习