【问题标题】:Clone the image rendered to a window/screen for processing将渲染的图像克隆到窗口/屏幕进行处理
【发布时间】:2014-11-05 18:25:42
【问题描述】:

背景

我有一个用于开发汽车控制系统的程序,它结合使用 TCL 脚本语言和 OpenGL 来额外渲染汽车在道路上行驶的行为。

我正在做的是实现对它的 OculusRift 支持,到目前为止,我已经设法解决了传感器部分,通过右键单击汽车行驶的窗口,我可以将它发送到 oculus rift。到目前为止,它看起来像这样:Youtube-Video

程序的视觉部分已经有很多功能,包括调整 FOV、鱼眼镜头、相机方向、车内视图等选项。

查看软件文件夹后,我发现了一个 TCL 文件,其中包含以下几行:

// ... cut here

gl pushmatrix
gl loadidentity
gl translate $x $y $z
gl rotate $xrot 1 0 0
gl rotate $yrot 0 1 0
gl rotate $zrot 0 0 1
gl translate $offx $offy $offz
lassign [lrange [OGL get modelviewmatrix] 12 14] tx ty tz
gl popmatrix


dict set ::View($view) CameraMode FixedToBodyA
dict set ::View($view) xrot $xrot
dict set ::View($view) yrot $yrot
dict set ::View($view) zrot [expr $zrot + $zrot_eyeAngle]
dict set ::View($view) dist $conf(dist)
dict set ::View($view) VPtOffset_x $tx
dict set ::View($view) VPtOffset_y $ty
dict set ::View($view) VPtOffset_z $tz
dict set ::View($view) FieldOfView $conf(fov)
dict set ::View($view) AspectRatio $conf(AspectRatio)

return;
}

我没有找到任何处理渲染本身的行,但“gl”-命令足以让我明白这个 TCL 文件正在运行,直接附加到渲染过程。所以我用这个扩展了上面的内容:

// load a self written DLL that wraps OVR functionality (Github link bellow)

# now run tclovrGetData() from the loaded DLL to get sensor data
set data [tclovrGetData] 
// data = x y z xrot yrot zrot

gl pushmatrix
gl loadidentity
gl translate $x $y $z
gl rotate $xrot 1 0 0
...

Github link to the DLL

正如您在视频中看到的那样,它在显示器上看起来不错,但我们知道 Rift 的镜头会带来失真(对我来说只是轻微的)和相当多的色差。

我的想法

我想要的是每 10-20 毫秒在视频中的屏幕上抓取“图像/纹理/帧”(我对术语还是很陌生)并对其进行一些颜色过滤(我想看看是否我可以减少色差)。然后也许(为了使一切独立)用修改后的图像创建一个新窗口并将其发送到 Rift。基本上以所需的“格式”获取图像,以便能够对其执行计算。

我的想法是(因为我们附加到渲染过程)在上面的 TCL 文件中添加一些额外的行,这些行在我的 DLL 中调用可以执行以下操作的其他函数:

// Begin Oculus rendering loop
//1. get frame that is currently being rendered (in this process)
//2. copy this frame to memory
//3. perform some operations (color filtering) on this frame in memory
//4. send this frame to a new window

现在我的问题是:

  • 这样的事情可能吗?
  • 有人能指出我正确的方向吗? IE。我可以使用一些 gl 函数吗?
  • 也许 Direct3D 也可以工作?

我确实在 stackoverflow 上阅读了 This 的帖子,但未能理解:/

【问题讨论】:

  • 显示硬件不应该为您处理这种事情吗?必须在软件中完成硬件应该处理的各种事情永远不会高效或明智......
  • 是的,应该。 OculusRift 仍处于开发状态。我也不知道在使用 Oculus 软件进行渲染时是否进行了某种后处理以最小化这种情况。但至少我没有看到来自镜头的色差校正。我的第一个计划实际上是使用 Oculus 渲染功能。但我真的不知所措,特别是因为我对模拟器软件的访问权限有限,因此不完全知道如何获取纹理/帧信息以将它们重新路由到 Oculus 渲染引擎。

标签: c++ opengl directx tcl oculus


【解决方案1】:

这样的事情可能吗?

是的。但这可能不是最好的解决方案,因为将数据复制回 cpu 内存并在那里处理它很可能对实时应用程序来说不够快。

有人能指出我正确的方向吗? IE。我可以使用一些 gl 函数吗?

如果您真的想这样做,您首先必须将图像渲染到帧缓冲区(或者更好地说是附加到帧缓冲区的纹理)。然后可以通过您在相关文章 (glGetTexImage) 中找到的函数将此纹理复制到 cpu 内存。还有其他选项,例如像素缓冲区,可能会更快(see here)

更快的解决方案

所有这些方法都要求您将数据从 gpu mem 复制到 cpu mem,在那里进行处理并将所有内容复制回来。这需要在 gpu 和 cpu 之间进行大量同步,此外在 cpu 上处理图像会很慢。

根据可用的 OpenGL 功能,您可以使用多种方法在 gpu 上执行整个图像处理。最简单的可能是使用着色器:

  1. 将场景渲染到帧缓冲区
  2. 绘制一个带纹理的四边形,其中 来自 (1) 的纹理,在片段着色器中执行所有操作 必要的。

在这种方法中也不需要第二个窗口,因为后处理的四边形可以显示在第一个窗口中。有关 gpu 后处理的更多信息,您可以查看here

【讨论】:

  • 感谢您的回复。如果我没有正确阅读this,我基本上必须将目标FB绑定到我们自己的FB,进行处理,然后将我们的FB绑定回屏幕缓冲区(0)。有一件事还是有点不清楚。我假设每个进程只能有一个目标 FB,因此glBindFramebuffer(GL_FRAMEBUFFER, fbo); 将在同一个进程中进行调用时将正确的图像(在窗口中)绑定到我们的 FB。
  • 一个应用程序只能有一个backbuffer,但可以有多个framebuffer对象。
  • 好吧,我想我开始明白了。基本上,如果我执行以下操作:glBindFramebuffer(GL_FRAMEBUFFER, fbo);// now do operations on fboglBindFramebuffer(GL_FRAMEBUFFER, 0); 我将有效地选择fbo 作为渲染目标,然后我将处理fbo 内部的内容,一旦我打破界限在第 3 行。 fbo 中的内容会被渲染到屏幕上吗?
  • 是的。 FBO 允许您渲染到纹理或渲染缓冲区。当你将 0 绑定到 GL_FRAMEBUFFER 时,就绑定了窗口的后备缓冲区。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多