在类似 Doom 的引擎中使用 glTexCoord4f() 在三角形中实现正确的纹理映射
Posted
技术标签:
【中文标题】在类似 Doom 的引擎中使用 glTexCoord4f() 在三角形中实现正确的纹理映射【英文标题】:Implementing correct texture mapping in triangles with glTexCoord4f() in a Doom-like engine 【发布时间】:2021-11-23 06:57:19 【问题描述】:前段时间我问了一个与这个类似的问题,但在那种情况下,我试图纠正梯形的透视纹理映射,该梯形的水平线始终与glTexCoord4f()
平行,这相对简单。但是,现在我正在尝试在我的引擎中修复地板和天花板的纹理映射,问题是由于两者都取决于地图的形状,我需要使用三角形来填充地图可能的多边形形状包含。
我尝试了一些与用于在梯形上正确纹理映射相同的方法的变体,当我计算三角形边缘的大小(使用屏幕坐标)并将每个结果用于每个glTexCoord4f()
中都有不同的“q”,这就是代码当前的样子。
考虑到这一点,我如何在使用 glTexCoord4f()
时解决此问题?
这是我用来校正墙壁纹理映射的代码(功能性):
float u, v;
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
float sza = wyaa - wyab; //Size of the first vertical edge on the wall
float szb = wyba - wybb; //Size of the second vertical edge on the wall
//Does the wall have streeched textures?
if(!(*wall).streechTexture)
u = -texLength;
v = -texHeight;
else
u = -1;
v = -1;
glBindTexture (GL_TEXTURE_2D, texture.at((*wall).texture));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord4f(0, 0, 0, sza);
glVertex3f(wxa, wyaa + shearing, -tza * 0.001953);
glTexCoord4f(u * szb, 0, 0, szb);
glVertex3f(wxb, wyba + shearing, -tzb * 0.001953);
glTexCoord4f(0, v * sza, 0, sza);
glVertex3f(wxa, wyab + shearing, -tza * 0.001953);
glTexCoord4f(u * szb, v * szb, 0, szb);
glVertex3f(wxb, wybb + shearing, -tzb * 0.001953);
glEnd();
glDisable(GL_TEXTURE_2D);
这里是渲染地板和天花板的当前代码(需要修复):
glEnable(GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texture.at((*floor).texture));
float difA, difB, difC;
difA = vectorMag(Vertex(fxa, fyaa), Vertex(fxb, fyba)); //Size of the first edge on the triangle
difB = vectorMag(Vertex(fxb, fyba), Vertex(fxc, fyca)); //Size of the second edge on the triangle
difC = vectorMag(Vertex(fxc, fyca), Vertex(fxa, fyaa)); //Size of the third edge on the triangle
glBegin(GL_TRIANGLE_STRIP); //Rendering the floor
glTexCoord4f(ua * difA, va * difA, 0, difA);
glVertex3f(fxa, fyaa + shearing, -tza * 0.001953);
glTexCoord4f(ub * difB, vb * difB, 0, difB);
glVertex3f(fxb, fyba + shearing, -tzb * 0.001953);
glTexCoord4f(uc * difC, vc * difC, 0, difC);
glVertex3f(fxc, fyca + shearing, -tzc * 0.001953);
glEnd();
glBegin(GL_TRIANGLE_STRIP); //Rendering the ceiling
glTexCoord4f(uc, vc, 0, 1);
glVertex3f(fxc, fycb + shearing, -tzc * 0.001953);
glTexCoord4f(ub, vb, 0, 1);
glVertex3f(fxb, fybb + shearing, -tzb * 0.001953);
glTexCoord4f(ua, va, 0, 1);
glVertex3f(fxa, fyab + shearing, -tza * 0.001953);
glEnd();
glDisable(GL_TEXTURE_2D);
这是它的视觉效果图(为了比较,地板尝试正确的纹理映射失败,而天花板有仿射纹理映射):
我知道如果我只是设置一个正常的透视图会更容易,但这只会破坏引擎的整个目的。
【问题讨论】:
正如我在上一篇文章中提到的,我知道这会容易得多,但问题的关键在于手动进行 3D 渲染,其方式或多或少与时间做到了,但没有达到那么低的水平。 为什么要重复这个问题?不欢迎重复提问以吸引注意力。 在前面的例子中,我只处理梯形,并且在图像中可以看到,我已经纠正了它,但我错误地认为它会很容易纠正它在三角形上。另外,这只是我在这里的第二个帖子,我找不到关闭上一个问题或将其删除的方法。 之前的帖子可以删了,现在没什么大问题了。 @Dr.Ether 但是你在那里失去了所有的 cmets ......而且那些活跃在那里的人可能看不到这个新的化身。最好在原始帖子中编辑新信息并通过 cmets 通知用户...如果改进足够,即使已关闭的问题也可以重新打开... 【参考方案1】:这只是地板和天花板的问题(除非您的相机可以倾斜)。所以你可以像你一样渲染你的wals。但是对于地板和天花板,您有这些基本选项(正如我在您的旧重复帖子中提到的):
自行光栅化扫描线
因此,不是渲染三角形(旧的光线投射器没有这样做),而是使用点而不是三角形来逐个像素地渲染垂直线。因为 GL 更适合多边形基元,所以这会慢得多。请参阅此处的draw_scanline
函数:
使用透视图并传递z坐标
看起来您已经添加了 z 坐标。所以现在你只需要设置与你的墙壁渲染相匹配的透视图。 OpenGL 将自己完成其余的工作。所以你应该为你的GL_PROJECTION
矩阵添加类似gluPerspective 的东西。但仅适用于您的地板/天花板...
传递 z 坐标并覆盖片段着色器
所以你只需编写片段着色器,在其中计算 the perspective correct texture mapping correction 并输出所需的纹素颜色 +/- 一些光照。这里是着色器使用示例:
complete GL+GLSL+VAO/VBO C++ example更多信息见:
Ray Casting with different height size【讨论】:
感谢您的解决方案!前段时间我已经用Z距离纠正了,但我不明白“齐次坐标”的概念。过了一会儿,我才明白我应该将 Z 距离与屏幕坐标成比例,我不需要在墙上这样做,因为屏幕上墙壁的两个顶点的 Y 位置的减法返回了如果我进行“屏幕大小 * Z 距离”的计算,则值完全相同。以上是关于在类似 Doom 的引擎中使用 glTexCoord4f() 在三角形中实现正确的纹理映射的主要内容,如果未能解决你的问题,请参考以下文章