在类似 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 函数:

    Efficient floor/ceiling rendering in Raycaster

    使用透视图并传递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() 在三角形中实现正确的纹理映射的主要内容,如果未能解决你的问题,请参考以下文章

游戏引擎剖析

Doom Emacs 简介

游戏引擎作为 EXE 和游戏作为 DLL?

DOOM启世录 pdf 下载

hdu 5239 Doom

DOOM启世录 PDF下载