如何在 opengl 中翻译屏幕中的投影对象

How to translate the projected object in screen in opengl

本文关键字:投影 对象 屏幕 翻译 opengl      更新时间:2023-10-16

我已经渲染了一个 3D 对象,它在图像中的 2D 投影是正确的。但是现在我想将 2d 投影对象移动一些像素。我该如何实现?

请注意,简单地平移 3d 对象是行不通的,因为在透视投影下,2d 投影对象可能会发生变化。我的目标是只移动图像中的 2d 对象,而不改变其形状和大小。

如果使用可编程管道,则可以在应用投影转换后应用转换。

您唯一需要注意的是,应用投影矩阵后转换的坐标具有将用于透视分割的w坐标。要使额外的翻译量在屏幕空间中保持不变,您必须将其乘以 w .顶点着色器的关键片段如下所示:

in vec4 Position;
uniform mat4 ModelViewProjMat;
uniform vec2 TranslationOffset;
void main() {
    gl_Position = ModelViewProjMat * Position;
    gl_Position.xy += TranslationOffset * gl_Position.w;
}

在透视除以w之后,这将导致一个固定的偏移。

适用于可编程管道和固定管道的另一种可能性是移动视口。假设窗口大小是vpHeightvpWidth倍,并且要应用的偏移量是(xOffset, yOffset),则可以将视口设置为:

glViewport(xOffset, yOffset, vpWidth + xOffset, vpHeight + yOffset);

这里需要注意的是,几何体仍将被相同的视图体积剪裁,但只有在应用剪裁后才会被视口变换移位。如果几何体完全适合原始视口,这将正常工作。但是,如果几何图形最初被裁剪,它仍将使用相同的平面进行裁剪,即使它在应用移位后实际上可能位于窗口内。

作为Reto Koradi答案的补充:您不需要着色器,也不需要修改您使用的视口(答案中提到了剪切问题)。您可以通过预先乘以一些平移来简单地修改投影矩阵(实际上将在投影变换之后最后应用):

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranstlate(x,y,z); // <- this one was added
glFrustum(...) or gluPerspective(...) or whatever you use

glFrustumgluPerspective会将当前矩阵乘以它们构建的射影 transfrom 矩阵,这就是为什么通常首先加载恒等式的原因。但是,它不一定是标识,这种情况是应该加载其他内容的罕见情况之一。

由于您希望以像素为单位移动,但该转换是在剪辑空间中应用的,因此您需要一些单位转换。由于剪辑空间只是归一化设备空间的同质表示形式,其中视锥体在所有 3 个维度上都是 [-1,1](因此视口在该空间中是 2x2 个单位大),因此可以使用以下内容:

glTranslate(x * 2.0f/viewport_width, y * 2.0f/viewport_height, 0.0f);

将输出偏移 (x,y) 像素。

请注意,虽然我为固定函数 GL 编写了这篇文章,但数学当然也适用于着色器,您可以简单地以相同的方式修改着色器使用的投影矩阵。