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

时间:2015-01-19 05:29:35

标签: c++ opengl

我渲染了一个三维物体,它在图像中的二维投影是正确的。但是现在我想将2d投影对象移动一些像素。我如何实现这一目标?

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

2 个答案:

答案 0 :(得分:2)

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

唯一需要注意的是,应用投影矩阵后的变换坐标有一个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的透视除法之后,这将产生固定的偏移量。

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

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

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

答案 1 :(得分:2)

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

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

glFrustumgluPerspective会将当前矩阵与它们构建的投影转换矩阵相乘,这就是人们通常首先加载身份的原因。但是,它不一定是身份,这种情况是少数情况下应该加载其他内容的情况之一。

由于您想要移动像素,但是在剪辑空间中应用了该转换,因此您需要进行一些单位转换。由于剪辑空间只是标准化设备空间的同质表示,其中平截头体在所有3个维度中都是[-1,1](因此视口在该空间中大于2x2单位),您可以使用以下内容:

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

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

请注意,虽然我为固定功能GL编写了这个,但数学当然也适用于着色器,你可以用同样的方式修改着色器使用的投影矩阵。