代码改变世界

实用指南:OSG多视口与多通道渲染核心技术解析

2025-12-07 12:19  tlnshuju  阅读(0)  评论(0)    收藏  举报

OSG 的 多视口 (Multi-Viewport)多通道/多遍渲染 (Multi-Pass / Multi-Channel) 知识框架。这是实现复杂渲染技术(如 RTT、阴影贴图、后期处理、立体渲染等)的基础。


OSG 多视口与多通道知识框架详解

I. 核心原理与概念

在 OSG 中,多视口和多通道渲染都是基于 OpenGL 的 帧缓冲区对象 (FBO)渲染上下文 (GraphicsContext) 进行组织的。

1. 视口 (Viewport)

视口是渲染结果最终显示的矩形区域,定义了屏幕或 FBO 附件上的像素坐标。

  • OpenGL 原理: 通过 glViewport(x, y, width, height) 函数设置。它将 NDC (Normalized Device Coordinates, 规范化设备坐标,∈[−1,1]\in [-1, 1][1,1]) 映射到屏幕或 FBO 的像素坐标。
  • OSG 实践:osg::Camera 对象的 setViewport(osg::Viewport*)setViewport(x, y, w, h) 方法设置。
2. 相机 (osg::Camera)

osg::Camera 是 OSG 中实现多视口和多通道渲染的核心。它封装了 OpenGL 的渲染状态(如视口、清除颜色、深度测试、FBO 绑定等)。

属性作用
ViewMatrix定义视点位置和方向 (OpenGL ModelView Matrix)
ProjectionMatrix定义投影类型 (透视/正交) 和裁剪范围
Viewport定义输出的屏幕/FBO 区域
RenderOrder决定相机绘制的顺序(如 PRE_RENDER, POST_RENDER
RenderTargetImplementation决定输出目标 (FRAME_BUFFER_OBJECTPIXEL_BUFFER)
Attach绑定 FBO 附件 (Texture2D, Image, RenderBuffer)
3. 多视口 (Multi-Viewport)

多视口是指在 同一个渲染窗口 (GraphicsContext) 中,使用 多个独立的 osg::Camera 在不同的屏幕区域进行渲染。

  • 原理: 每个 osg::Camera 都设置一个不同的 osg::Viewport。当 OSG 遍历场景图时,它会依次激活每个相机,调用其设置的 glViewport,然后使用该相机的状态渲染其子图。
  • 应用: 分屏显示、HUD (平视显示器)、小地图、显示不同视角的预览等。
4. 多通道/多遍渲染 (Multi-Pass / Multi-Channel Rendering)

多通道通常指两个概念:

  • Multi-Pass (多遍渲染): 使用多个独立的渲染过程(通常是 RTT 相机)来完成一个复杂的效果。前一通道的输出作为后一通道的输入。
    • 示例: 阴影贴图:Pass 1 渲染深度到 Shadow Map;Pass 2 渲染主场景,采样 Shadow Map。
  • Multi-Channel (多通道输出/MRT):单次渲染 过程中,通过帧缓冲区对象 (FBO) 的 多渲染目标 (MRT) 特性,同时将不同类型的数据输出到多个颜色附件中。
    • 示例: G-Buffer:单次渲染同时输出世界坐标、法线、颜色/纹理 ID、深度等。

II. 实践应用与代码实现

1. 多视口实现:分屏显示

实现方法是在主场景图的根节点下添加多个设置了不同视口的 osg::Camera

C++ 核心代码:

// 主视口/Viewer Camera(通常全屏)
osg::ref_ptr<osg::Camera> mainCamera = viewer->getCamera();
  mainCamera->setViewport(0, 0, 800, 600);
  mainCamera->addChild(mainScene.get());
  // 第二视口 (小地图/预览)
  osg::ref_ptr<osg::Camera> subCamera = new osg::Camera;
    subCamera->setViewport(600, 400, 200, 200); // 放在右上角 (x=600, y=400, w=200, h=200)
    subCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    subCamera->setClearColor(osg::Vec4(0.1f, 0.1f, 0.2f, 1.0f));
    subCamera->setProjectionMatrixAsPerspective(30.0, 1.0, 1.0, 1000.0);
    subCamera->setViewMatrixAsLookAt(osg::Vec3(0, 0, 50), osg::Vec3(0, 0, 0), osg::Vec3(0, 1, 0));
    subCamera->setRenderOrder(osg::Camera::POST_RENDER); // 确保在主场景之后绘制
    // 将子相机添加到场景图,由主 Viewer 驱动渲染
    osg::ref_ptr<osg::Group> root = new osg::Group;
      root->addChild(mainScene.get());
      root->addChild(subCamera.get());
2. 多通道/多遍渲染实现:RTT 链

这是最常见的复杂渲染结构,如您之前的高程计算需求。

通道/阶段目标相机类型RenderTargetImplementation
Pass 1 (Depth/Data)渲染 3D 模型,输出数据到 Texture Aosg::CameraFRAME_BUFFER_OBJECT
Pass 2 (Compute/Final)渲染 2D Quad,采样 Texture A,计算结果输出到 Texture Bosg::CameraFRAME_BUFFER_OBJECT 或 屏幕

C++ 核心代码 (Pass 1 RTT):

// Pass 1: depthCamera (RTT 到 Texture)
osg::ref_ptr<osg::Texture2D> depthTexture = new osg::Texture2D;
  depthTexture->setInternalFormat(GL_R32F);
  // ... (设置 textureSize, filter) ...
  osg::ref_ptr<osg::Camera> depthCamera = new osg::Camera;
    depthCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
    depthCamera->setRenderOrder(osg::Camera::PRE_RENDER);
    depthCamera->setViewport(0, 0, W, H);
    depthCamera->attach(osg::Camera::COLOR_BUFFER0, depthTexture.get()); // 绑定 FBO 附件
    depthCamera->addChild(scene_root.get()); // 渲染 3D 场景
    // Pass 2: computeCamera (读取 depthTexture 进行计算)
    // ... (略) ...
3. 多通道输出实现:MRT (Multi-Render Target)

单次渲染 中同时输出多个数据。

C++ 核心代码 (MRT Setup):

// Texture 1: 颜色/高程 (附件 0)
osg::ref_ptr<osg::Texture2D> tex0 = new osg::Texture2D;
  tex0->setInternalFormat(GL_R32F); // 高精度高程
  // Texture 2: 法线/NDC 深度 (附件 1)
  osg::ref_ptr<osg::Texture2D> tex1 = new osg::Texture2D;
    tex1->setInternalFormat(GL_RGBA8); // 法线或其他数据
    osg::ref_ptr<osg::Camera> mrtCamera = new osg::Camera;
      // ... (设置 Viewport, RenderOrder, FBO) ...
      // 【核心 MRT 绑定】
      mrtCamera->attach(osg::Camera::COLOR_BUFFER0, tex0.get()); // 附件 0
      mrtCamera->attach(osg::Camera::COLOR_BUFFER1, tex1.get()); // 附件 1
      // 【着色器 Program 绑定】
      osg::ref_ptr<osg::Program> program = new osg::Program;
        // ... (添加 Shader) ...
        osg::StateSet* ss = mrtCamera->getOrCreateStateSet();
        ss->setAttributeAndModes(program.get(), osg::StateAttribute::ON);

GLSL 核心代码 (MRT Fragment Shader):

#version 330 core
// 声明两个输出变量,分别对应 COLOR_BUFFER0 和 COLOR_BUFFER1
layout(location = 0) out float out_Elevation; // 附件 0 (R32F)
layout(location = 1) out vec4 out_Normal;     // 附件 1 (RGBA8)
void main()
{
    // ... (计算逻辑) ...
    out_Elevation = calculated_height;
    out_Normal = vec4(normalize(world_normal), 1.0);
}

III. 知识结构总结 (Mermaid 图)

在这里插入图片描述


IV. 关键属性对比表格

特性osg::Cameraosg::Viewportosg::Texture2Dosg::Image
GL 对应渲染状态、FBOglViewportglTexImage2D, glBindTextureCPU 内存缓冲区
主要作用定义渲染流程、矩阵、输出目标定义屏幕/FBO 上的像素区域GPU 内存存储,作为 FBO 附件或采样输入CPU 内存存储,作为 readPixels 目标或纹理数据源
多通道/MRT通过 attach(COLOR_BUFFERN, ...) 实现定义 MRT 的尺寸作为 FBO 的颜色附件 (输出)CPU 回读目标 (输出)
多遍渲染用于定义每个渲染通道 (Pass) 的状态Pass 1 输出,Pass 2 输入 (采样)