如何正确地将 2D 图像纹理映射到 icosphere
How to properly map a 2D image texture to an icosphere
我正在用 C++ 编写一个简单的图形引擎,它应该能够代表地球。地球被建模为一个 icosphere,我计划使用每个顶点的法线来映射它的纹理。为此,我实际上是在尝试从顶点的法线获取垂直和水平坐标(分别为 φ 和 θ)(即纬度和经度)。
以下是实现我的方法的(edited)函数(在生成新顶点时调用)。当参数n
为法向量时,应该return纹理坐标从(0,0)
到(1,1)
:
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);
}
然而,这产生了意想不到的结果。使用 this test image,我的 icosphere 看起来像这样:
白色和红色小三角形位于 (x,y,z) = (1,0,0)
。在第一张图片中,我生成了三角形面较少的圆角球 (320),而在后者中,我生成了约 82k 个三角形的圆角球。
我怀疑导致这些纹理 "glitches" 的原因是坐标 (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);
我终于克服了这个丑陋的纹理映射。这个问题确实是由 icosphere 中三角形的特征 non-uniform 方向引起的。在 icosphere(以及二十面体)中,不可能在原点 (0,0,0)
找到不与任何三角形相交的平面。如果我们想到地球,这意味着它的所有 子午线 都与一些三角形相交。这也意味着在映射纹理时,位于纹理垂直边缘(即具有 tex.coord.(1,y)
和 (0,y)
)的三角形将在任一侧具有它们的一些顶点。发生这种情况时,纹理将从 x≈1
插值到 x≈0
,产生我的图像中显示的效果。
为了解决这个问题,我将纹理环绕设置为GL_REPEAT
,并简单地强制一些顶点远离纹理坐标space(即x > 1
)。这允许纹理边缘 相邻 并完美映射纹理:
/* Configure texture parameters: */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Not GL_CLAMP_TO_EDGE.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Not 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);
结果:
修改边缘三角形的纹理坐标后(GL_CLAMP_TO_EDGE
):
将纹理参数更改为 GL_REPEAT
:
我正在用 C++ 编写一个简单的图形引擎,它应该能够代表地球。地球被建模为一个 icosphere,我计划使用每个顶点的法线来映射它的纹理。为此,我实际上是在尝试从顶点的法线获取垂直和水平坐标(分别为 φ 和 θ)(即纬度和经度)。
以下是实现我的方法的(edited)函数(在生成新顶点时调用)。当参数n
为法向量时,应该return纹理坐标从(0,0)
到(1,1)
:
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);
}
然而,这产生了意想不到的结果。使用 this test image,我的 icosphere 看起来像这样:
白色和红色小三角形位于 (x,y,z) = (1,0,0)
。在第一张图片中,我生成了三角形面较少的圆角球 (320),而在后者中,我生成了约 82k 个三角形的圆角球。
我怀疑导致这些纹理 "glitches" 的原因是坐标 (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);
我终于克服了这个丑陋的纹理映射。这个问题确实是由 icosphere 中三角形的特征 non-uniform 方向引起的。在 icosphere(以及二十面体)中,不可能在原点 (0,0,0)
找到不与任何三角形相交的平面。如果我们想到地球,这意味着它的所有 子午线 都与一些三角形相交。这也意味着在映射纹理时,位于纹理垂直边缘(即具有 tex.coord.(1,y)
和 (0,y)
)的三角形将在任一侧具有它们的一些顶点。发生这种情况时,纹理将从 x≈1
插值到 x≈0
,产生我的图像中显示的效果。
为了解决这个问题,我将纹理环绕设置为GL_REPEAT
,并简单地强制一些顶点远离纹理坐标space(即x > 1
)。这允许纹理边缘 相邻 并完美映射纹理:
/* Configure texture parameters: */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Not GL_CLAMP_TO_EDGE.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Not 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);
结果:
修改边缘三角形的纹理坐标后(GL_CLAMP_TO_EDGE
):
将纹理参数更改为 GL_REPEAT
: