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();
}
相关推荐
西岸行者6 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意6 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码6 天前
嵌入式学习路线
学习
毛小茛6 天前
计算机系统概论——校验码
学习
babe小鑫6 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms6 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下6 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。6 天前
2026.2.25监控学习
学习
im_AMBER6 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J6 天前
从“Hello World“ 开始 C++
c语言·c++·学习