我假设您正在绘制一些场景,并且您只想将该屏幕的一部分渲染到 FBO,该 FBO 的大小取决于您希望重绘的部分。或者换句话说,FBO 与您希望重绘的屏幕部分一样大。
创建适当大小的 FBO(可能需要 POT 尺寸)后,您需要将视口设置为与您正在重绘的部分的大小相同,并且原点保持在 (0,0)。接下来需要更改的是矩阵的投影部分,在大多数情况下为glOrtho 或glFrustum。这两个都有 4 个边框参数(左、右、上、下)。这些参数需要设置为您正在重绘的场景的哪个部分,这取决于两者,您的边框参数是如何在主场景上设置的,以及您的重绘矩形是在什么坐标系中定义的。例如,如果您想重绘屏幕左上角的 100x100 部分并使用glOrtho 和边框参数作为(0,0,viewWidth,viewHeight),那么您的新边框参数就是(0,0,100,100)。但是,如果您使用 (-1,-1,1,1) 之类的东西,则需要根据您的屏幕(缓冲区)大小来计算这些参数。
无论如何,您应该能够通过仅更改这两种方法来管理它。完成对 FBO 的绘图后不要忘记重置它们。
编辑:坐标系变换
虽然这个问题已经回答了很多次,但这里有一些数学代码可以从一个坐标系转换到另一个坐标系。通常从原始场景中插入您的真实参数,这应该为您提供转换后的边界参数,您应该将其插入到 FBO 平截头体中。
(我没有测试这个,所以可能已经犯了错误)
BorderParameters screenRect; // for instance (0, 0, 360, 480) (left, top, right, bottom)
BorderParameters redrawRect; // for instance (0, 0, 36, 48) (left, top, right, bottom)
BorderParameters frustumRect; // for instance (-1, ratio, 1, -ratio) (left, top, right, bottom)
BorderParameters outputRect; // result (insert into ortho or frustum)
outputRect.left = frustumRect.left + ((redrawRect.left-screenRect.left)/(screenRect.right-screenRect.left))*(frustumRect.right-frustumRect.left);
// -1 + ((0-0)/(360-0))*(1+1) = -1
outputRect.right = frustumRect.left + ((redrawRect.right-screenRect.left)/(screenRect.right-screenRect.left))*(frustumRect.right-frustumRect.left);
// -1 + ((36-0)/(360-0))*(1+1) = -.8
outputRect.bottom = frustumRect.top + ((redrawRect.bottom-screenRect.top)/(screenRect.bottom-screenRect.top))*(frustumRect.bottom-frustumRect.top);
// ratio + ((48-0)/(480-0))*(-ratio-ratio) = ratio - .2*ratio = .8*ratio
outputRect.top = frustumRect.top + ((redrawRect.top-screenRect.top)/(screenRect.bottom-screenRect.top))*(frustumRect.bottom-frustumRect.top);
// ratio + ((0-0)/(480-0))*(-ratio-ratio) = ratio
我有 50% 的把握,现在我想到了整个过程将与截锥体一起工作,但是,重绘部分可能会有轻微的偏移(如果它很大,则参数有问题)。
无论如何,更常见的做法是将整个场景绘制到 FBO,然后通过后期处理将其重绘到主缓冲区,而不是将所有元素重绘到一个小的 FBO,因为可能有很多元素需要重绘到 FBO。此外,如果您希望屏幕的许多(例如 10 个)小部分同时模糊,您会重绘整个场景 11 次以获得该场景加上 10 个 FBO 吗?