在OpenGL中投影纹理

8

通过将近裁剪平面设置为1而不是0(不确定为什么一开始会这样),已经解决了问题。请参见骨架代码的问题,以及Adrian的答案,了解其如何运作和原理。

我有几个不同的相机位置,我的场景只包含一个四边形。

这个四边形恰好在第一帧中投影到视口/窗口上。我想从这个相机位置投影纹理到四边形上。该纹理也完全覆盖了视口。

我做的第一件事是

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

我最终得到了这样的结果(图片非本人所拍)alt text
然后我意识到,当然,它需要是一个投射变换。根据这些笔记的说法:
  1. 模型视图转换以使投影适合场景。
  2. 投射变换(透视或正交)。
  3. 比例因子和偏置映射近剪裁平面到纹理坐标。
现在它已经可以工作了,这里是代码的大致实现:
// 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应该包含投影仪的变换而不是视角相机的变换。虽然我不确定这是否能解决你的问题。 - Adrian Lopez
是的,这是投影仪。我确定我提供了正确的细节。即使我将透视/观察调用更改为使用相同的相机细节,它看起来仍然不对... - CakeMaster
这两个相机在问题出现时是否共享完全相同的参数--方向、位置和视锥体?为什么您要根据投影仪设置视图,而根据视图相机设置纹理坐标?否则,您的变换和眼空间系数看起来与您引用的注释中的相同,所以此时我对可能发生的事情感到困惑。 - Adrian Lopez
是的,为了测试这个,我正在尝试将其投影回到完全相同的相机中。一旦这样做成功,我可以尝试其他相机。我也很困惑 :( - CakeMaster
根据注释,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" 完全相同,那这一点就无所谓了。 - Adrian Lopez
我刚刚找到了!近裁剪平面需要设置为1。然后它就可以工作了(虽然是倒置的,但缩放(0.5,-0.5,1)可以解决)。否则你的建议是正确的。我会接受你的答案并在问题上做个记录。谢谢。 - CakeMaster
1个回答

4
请查看glTexGen文档(在您的情况下,您需要使用适当的系数集合与GL_EYE_LINEAR一起使用,如下所述),以及glEnable(GL_TEXTURE_GEN_*)。当为特定纹理坐标分量(S、T、R和/或Q)启用texgen功能时,您通过glTexCoord指定的这些分量的值将被忽略,并且根据指定的glTexGen模式生成纹理坐标。
通过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)是长度为1的向量,则上述点积操作的结果表示正在处理的顶点与该平面之间的距离。如果在四个纹理分量上启用了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矩阵应包含从对象空间到纹理空间的任何操作所需的操作:建模、查看和投影变换以从对象坐标转换为归一化设备坐标,加上缩放和偏移变换以从归一化设备坐标转换为纹理空间。

非常感谢您提供的所有信息,我现在正在尝试实施它。 - CakeMaster
我运气不太好。我的四边形只有一个颜色纹理 - 看起来它可能是被极度放大,所以我们只能看到一个像素。我将扩展问题。 - CakeMaster
1
我注意到你的代码中没有通过glTexGen指定任何纹理坐标分量的系数。我还注意到你没有设置GL_TEXTURE矩阵。你应该将glTexGen系数设置为类似于(1.0, 0.0, 0.0, 0.0)的S,(0.0, 1.0, 0.0, 0.0)的T等。这将直接将你的眼空间坐标投影到对象空间中,然后你可以将视图和投影变换应用到GL_TEXTURE矩阵中,从而将对象空间转换为纹理空间。 - Adrian Lopez
另外,针对您的特定目的,在设置系数的glTexGen调用之前和之后,您希望GL_MODELVIEW矩阵保持不变。为了获得正确的纹理坐标,请像对待GL_MODELVIEW/GL_PROJECTION一样将您的模型视图和投影变换应用于GL_TEXTURE,并且不要忘记通过缩放和转换s和t分量0.5作为最后一步,以使最终的纹理坐标位于(0,1)范围内。 - Adrian Lopez
再次感谢。是的,现在看起来合理多了,但纹理被平铺了大约4次(即变得太小),而且长宽比似乎不对。我会再次更新细节,也许还有最后一件事情我错过了? - CakeMaster
我已编辑我的答案,修复了解释中的各种错误,并为您的原问题提供了更好的答案。 - Adrian Lopez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接