如何将 2D 图像纹理正确映射到 icosphere

Car*_*guz 7 c++ opengl textures texture-mapping

我正在用 C++ 编写一个简单的图形引擎,它应该能够代表地球。地球被建模为一个icosphere,我计划使用每个顶点的法线来映射其纹理。为此,我本质上是尝试从顶点的法线获取垂直和水平坐标(分别为 φ 和 θ)(即纬度和经度)。

以下是实现我的方法的(已编辑的)函数(在生成新顶点时调用)。当参数是法向量时,它应该返回从(0,0)到 的纹理坐标:(1,1)n

glm::vec2 Icosphere::getTexCoord(glm::vec3 n)
{
    float theta = (atan2f(n.x, n.z) / PI) / 2.f + 0.5f;
    float phi = (asinf(-n.y) / (PI / 2.f)) / 2.f + 0.5f;
    return glm::vec2(theta, phi);
}
Run Code Online (Sandbox Code Playgroud)

然而,这正在产生意想不到的结果。通过这个测试图像,我的 icosphere 看起来像这样:

实施例1

实施例2

小白色和红色三角形位于(x,y,z) = (1,0,0)。在第一张图像中,我生成了具有较少三角形面 (320) 的 icosphere,而在后者中,生成了约 82k 个三角形的 icosphere。

我怀疑导致这些纹理“故障”的原因是坐标(0,*)(1,*)不被认为是相邻的。有没有正确的方法来做到这一点?

注意:这些是我的纹理参数:

/* Configure texture parameters: */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
Run Code Online (Sandbox Code Playgroud)

Car*_*guz 3

我终于克服了这个丑陋的纹理映射。这个问题确实是由 icosphere 中三角形的非均匀方向特性引起的。在二十面体中(以及在二十面体中),不可能在原点找到一个(0,0,0)不与任何三角形相交的平面。如果我们考虑地球,这意味着它的所有经线都与一些三角形相交。这也意味着在映射纹理时,位于纹理垂直边缘(即 tex.coord.(1,y)(0,y))的三角形将在任一侧具有一些顶点。发生这种情况时,纹理将从 插值x\xe2\x89\x881x\xe2\x89\x880,产生我的图像中显示的效果。

\n\n

为了解决这个问题,我将纹理环绕设置为GL_REPEAT并简单地强制一些顶点远离纹理坐标空间(即x > 1)。这允许纹理边缘相邻完美地映射纹理:

\n\n
/* Configure texture parameters: */\nglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Not GL_CLAMP_TO_EDGE.\nglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Not GL_CLAMP_TO_EDGE.\nglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\nglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\nglGenerateMipmap(GL_TEXTURE_2D);\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:

\n\n

修改边缘三角形的纹理坐标后(使用GL_CLAMP_TO_EDGE):

\n\n

结果1

\n\n

将纹理参数更改为GL_REPEAT

\n\n

在此输入图像描述

\n

  • 您如何检测哪些顶点远离纹理坐标空间?我不确定如何检测到这一点。 (4认同)