osgearth 嵌入opengl的方式<二>

📅 2026/7/1 10:00:22
osgearth 嵌入opengl的方式<二>
一、效果在屏幕的左下角添加一个测试的三角形没啥实际意义。这种是通过继承osg::GraphicsOperation类并重写operator()(osg::GraphicsContext* context)方法来实现的属于“图形设备命令队列”的一部分。它直接投递到 OSG 渲染后端的执行队列中完全绕过了场景图的裁剪和遍历。它适合用来执行“后台任务”或“全局性操作”。线程安全与异步执行GraphicsContext::add是线程安全的。你可以在任何工作线程中构造 OpenGL 指令然后投递到渲染线程执行非常适合做流式数据更新如动态纹理上传、PBO像素缓冲区对象异步回读。精准的帧同步你可以通过设置Operation的keep参数控制它是一次性执行执行完销毁还是每帧都执行。这比在Drawable里做全局状态清理要干净得多。不污染场景图当你需要做全屏后处理特效如 Blit位块传输操作、清屏、或者绑定 FrameBuffer Object帧缓冲对象FBO进行离屏渲染时用 Operation 绝对不会干扰主场景图的包围盒计算。二、代码#pragma comment(lib, opengl32.lib) class MyTriangleTask : public osg::GraphicsOperation { public: MyTriangleTask() : osg::GraphicsOperation(MyTriangle, true) {} virtual void operator()(osg::GraphicsContext* context) { // 1. 保存当前状态 glPushAttrib(GL_ALL_ATTRIB_BITS); // 2. 设置正交投影使得坐标直接对应窗口像素或简单NDC // 获取视口大小 const osg::Viewport* vp context-getState()-getCurrentViewport(); if (!vp) return; int width vp-width(); int height vp-height(); // 设置投影矩阵为窗口像素坐标范围0,0)到(width,height) glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, width, 0, height, -10000, 10000); // 设置模型视图为单位矩阵 glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // 3. 绘制三角形使用屏幕坐标例如在窗口中央画一个小三角形 glColor3f(1.0f, 0.0f, 0.0f); glBegin(GL_TRIANGLES); glVertex3f(10, 100,0); glVertex3f(100 ,10,0); glVertex3f(10, 10,0); glEnd(); // 4. 恢复矩阵和状态 glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); } };三、调用osg::GraphicsContext * gc m_rpViewer-getCamera()-getGraphicsContext(); if(gc)gc-add(new MyTriangleTask());四、总结这种方式需要注意的是没有裁剪没有变换因为绕过了场景图你在 Operation 里画的坐标是绝对的 NDC归一化设备坐标或窗口坐标。如果你想画一个随相机移动的 3D 物体千万别用这个否则它会“钉”在屏幕上或者因不在视锥内而被硬件裁剪掉。状态需完全自理Operation 执行时OSG 不会为你应用StateSet。你必须在operator()函数体内手动glPushAttrib和glPopAttrib否则你的 GL 状态改动可能会影响下一帧的正常渲染。执行时机通过add添加的操作默认会在当前帧的渲染末尾或下一帧开始前执行。如果顺序依赖强比如要在场景绘制前清空某个 FBO需要设置合适的RenderStage阶段或优先级。