1

我正在尝试将屏幕的一小部分区域渲染为屏幕外纹理。这是我的应用程序中的屏幕截图功能的一部分,用户在屏幕上选择一个区域并将其保存到图像中。虽然屏幕上的区域可能是 250x250 像素,但保存的图像可能会大很多,例如 1000x1000 像素。

我了解使用 FBO 渲染到纹理的过程。在定义剪辑场景的投影矩阵以便只渲染屏幕截图区域时,我大部分时间都被卡住了。

4

2 回答 2

2

我相信你可以在不改变投影矩阵的情况下做到这一点。毕竟,如果您考虑一下,您并不想更改投影。您想要更改投影几何体的哪一部分映射到您的渲染表面。投影后的坐标系为 NDC(标准化设备坐标)。控制 NDC 如何映射到渲染表面的变换是视口变换。您可以通过参数来控制视口转换glViewport()

如果将视口尺寸设置为渲染表面的大小,则将 [-1.0, 1.0] 的 NDC 范围映射到渲染表面。要将 NDC 范围的子范围渲染到您的表面,您需要相应地放大指定的视口大小。假设将原始图像的 1/4 映射到表面宽度,将视口宽度设置为表面宽度的 4 倍。

要将标准 NDC 范围的子范围映射到您的表面,您还需要调整视口的原点。在这种情况下,视口原点值变为负值。继续前面的示例,要从图像中间开始映射 1/4 或原始图像,视口原点的 x 值将是表面宽度的 -2 倍。

这是我想出的关于如何调整视口的想法。使用以下定义:

winWidth: width of original window
winHeight: height of original window
xMin: minimum x-value of zoomed region in original window coordinates
xMax: maximum x-value of zoomed region in original window coordinates
yMin: minimum y-value of zoomed region in original window coordinates
yMax: maximum y-value of zoomed region in original window coordinates
fboWidth: width of FBO you use for rendering zoomed region
fboHeight: height of FBO you use for rendering zoomed region

为避免失真,您可能需要保持纵横比:

fboWidth / fboHeight = (xMax - xMin) / (yMax - yMin)

在以下所有内容中,大多数操作(尤其是除法)都必须以浮点执行。如果原始变量是整数,请记住使用类型转换,并将结果四舍五入为整数以获得最终结果。

xZoom = winWidth / (xMax - xMin);
yZoom = winHeight / (yMax - yMin);
vpWidth = xZoom * fboWidth;
vpHeight = yZoom * fboHeight;
xVp = -(xMin / (xMax - xMin)) * fboWidth;
yVp = -(yMin / (yMax - yMin)) * fboHeight;
glViewport(xVp, yVp, vpWidth, vpHeight);
于 2014-06-20T07:18:40.600 回答
0

您可能想了解gluPickMatrix的工作原理并使用现代 OpenGL 方法复制其功能。您可以在 Mesa3D 的实现中找到 gluPickMatrix 源代码。

虽然 gluPickMatrix 的初衷是用于选择模式渲染,但它也可以用于您想做的事情。

于 2014-06-19T17:56:35.083 回答