在 OpenGL 中投影纹理

Posted

技术标签:

【中文标题】在 OpenGL 中投影纹理【英文标题】:Projecting a texture in OpenGL 【发布时间】:2010-09-03 01:03:01 【问题描述】:

通过将剪裁平面附近设置为 1 而不是 0 来修复(不知道为什么会这样开始)。请参阅有关骨架代码的问题,以及 Adrian 的回答以了解其工作原理和原因。

我有几个不同的相机位置,我的场景由一个四边形组成。

四边形是这样的,它在第一帧中准确地投影到视口/窗口上。我想将这个相机位置的纹理投影到四边形上。纹理也完全覆盖了视口。

我做的第一件事是

    // GL_QUADS...
    glTexCoord2f( /*one corner of s,t space*/);
    glVertex3f(/* appropriate vertex */);;

最后得到了类似(图片不是我的)

然后我意识到是的,当然,它需要是一个投影转换。根据these notes:

    用于在场景中定向投影的模型视图变换。 投影变换(透视或正交)。 将近剪裁平面映射到纹理坐标的比例和偏差。

现在它可以工作了,下面是代码的粗略实现:

// in init code
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

double ratio = width/height;

// set up FROM modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();


gluPerspective(pcam._fov/ratio, ratio, 1, far_z);
gluLookAt(/* FROM camera's parameters */);

glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); //S, T, R and Q
GLfloat Splane[] = 1.f, 0.f, 0.f, 0.f; //S, T, R and Q, diagonal
glTexGenfv(GL_S,GL_EYE_PLANE,Splane); //S, T, R and Q

// -- load and bind texture --

glEnable(GL_TEXTURE_GEN_S); //S, T, R and Q

// scale and bias
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
glTranslatef(0.5,0.5,0.0);
glScalef(0.5,0.5,1);

gluPerspective(cam._fov/ratio, ratio, 1, far_z);
gluLookAt(/* TO camera's parameters */);

glBegin(GL_QUADS);
    glVertex3f(/* for each vertex */);
glEnd();
glDisable(GL_TEXTURE_GEN_S); //S, T, R and Q

【问题讨论】:

我认为您的 TO 和 FROM 相机可能混淆了。 FROM/pcam 是投影机吗? GL_TEXTURE 应该包含投影仪而不是视图相机的变换。不过,我不知道这是否能解决您的问题。 是的,它是投影仪。我确定我正确地提供了详细信息。即使我将透视/观察调用更改为使用相同的相机细节,它看起来也是错误的...... 在出现问题时,两个相机是否共享精确相同的参数——方向、位置和视锥体?为什么要根据投影仪设置 view 并根据视图相机设置纹理坐标?否则,您的变换和眼睛空间系数看起来与您引用的注释相同,所以在这一点上,我对可能发生的事情感到困惑。 是的,为了测试,我正试图将其投影回完全相同的相机中。一旦这个工作,我可以尝试其他相机。我也被难住了:( 根据 cmets 的说法,GL_EYE_LINEAR 对所有 S、T、R 和 Q 都启用,对吗?您是否还将 R 平面设置为 (0.0, 0.0, 1.0, 0.0) 并将 Q 平面设置为 (0.0, 0.0, 0.0, 1.0)?另外,我仍然不明白您为什么要使用投影仪(“pcam”)对象设置视图,但是既然您说它与“cam”完全相同,那么此时这并不重要。 【参考方案1】:

查看glTexGen 的文档(在您的情况下,您希望使用GL_EYE_LINEAR 以及如下所述的一组适当的系数)和glEnable(GL_TEXTURE_GEN_*)。当您为特定纹理坐标组件(S、T、R 和/或 Q)启用 texgen 功能时,您为这些组件(通过glTexCoord)指定的值将被忽略,而是根据指定的@987654326 生成纹理坐标@ 模式。

当通过GL_EYE_LINEAR 计算纹理坐标时,顶点坐标首先由当前的GL_MODELVIEW 矩阵转换到眼睛空间。一旦进入眼睛空间,对于每个启用的组件(S、T、R、Q),顶点坐标通过调用glTexGen 时定义的GL_MODELVIEW 矩阵的逆矩阵和点积进行变换然后获得结果坐标和发送到glTexGen 的系数之间的关系。对于每个启用的组件,生成的标量值成为纹理坐标的对应分量(S、T、R 和/或 Q),最终由GL_TEXTURE 矩阵转换以生成最终的纹理坐标。

对于每个纹理分量,发送到glTexGen的系数(a, b, c, d)定义了一个平面ax + by + cz + d = 0。假设(a, b, c)是一个单位向量长度,上述点积运算的结果表示该平面与正在处理的顶点之间的距离。如果为所有四个纹理组件启用GL_EYE_LINEAR,并且 S、T、R 和 Q 的平面方程分别定义为 (1.0, 0.0, 0.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0) 和 (0.0, 0.0, 0.0, 1.0),则为每个纹理组件生成的纹理坐标与原始对象空间顶点坐标完全相同。因此,GL_TEXTURE 矩阵应该包含将这些坐标从对象空间转换到纹理空间所需的任何操作:建模查看投影将对象坐标转换为标准化设备坐标的转换,以及将标准化设备坐标转换为纹理空间的 scalebias 转换。

【讨论】:

非常感谢这一切,我现在正在努力实现它。 我运气不太好。我的四边形是单一颜色的纹理——看起来它可能被极度放大了,所以我们只看到一个像素。我将扩大问题 我注意到您的代码中没有为任何纹理坐标组件指定系数(通过 glTexGen)。我还注意到您没有设置 GL_TEXTURE 矩阵。您应该将 glTexGen 系数设置为 S 的 (1.0, 0.0, 0.0, 0.0),T 的 (0.0, 1.0, 0.0, 0.0) 等。这会将您的眼睛空间坐标直接投影到对象空间中,您可以然后将您的视图和投影变换应用到 GL_TEXTURE 矩阵,以从对象空间变换到纹理空间。 此外,出于您的特定目的,您希望 GL_MODELVIEW 矩阵在调用 glTexGen 之前和之后保持不变,您可以在其中设置系数。要获得正确的纹理坐标,请像使用 GL_MODELVIEW/GL_PROJECTION 一样将模型视图和投影变换应用于 GL_TEXTURE,并且不要忘记将 s 和 t 分量缩放和变换 0.5 作为最后一步,以便最终纹理坐标位于内部(0,1) 范围。 再次感谢。是的,现在看起来更合理了,但是纹理平铺了大约 4 次(即出来太小),并且纵横比似乎不正确。我将再次更新详细信息,也许我错过了最后一件事?

以上是关于在 OpenGL 中投影纹理的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL中投影变换函数的实现

OpenGL中投影矩阵基础知识

openGL学习过程中资料总结

为啥我的 OpenGL 纹理不起作用?

OpenGL ES纹理

IOS – OpenGL ES 图像晕影扩散 GPUImageVignetteFilter