我已经渲染了一个 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
之后,这将导致一个固定的偏移。
适用于可编程管道和固定管道的另一种可能性是移动视口。假设窗口大小是vpHeight
的vpWidth
倍,并且要应用的偏移量是(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
glFrustum
和gluPerspective
会将当前矩阵乘以它们构建的射影 transfrom 矩阵,这就是为什么通常首先加载恒等式的原因。但是,它不一定是标识,这种情况是应该加载其他内容的罕见情况之一。
由于您希望以像素为单位移动,但该转换是在剪辑空间中应用的,因此您需要一些单位转换。由于剪辑空间只是归一化设备空间的同质表示形式,其中视锥体在所有 3 个维度上都是 [-1,1](因此视口在该空间中是 2x2 个单位大),因此可以使用以下内容:
glTranslate(x * 2.0f/viewport_width, y * 2.0f/viewport_height, 0.0f);
将输出偏移 (x,y)
像素。
请注意,虽然我为固定函数 GL 编写了这篇文章,但数学当然也适用于着色器,您可以简单地以相同的方式修改着色器使用的投影矩阵。