OpenGL 3.2 球体 - 纹理坐标

OpenGL 3.2 Sphere - Texture coordinates

我正在使用 OpenGL 3.2 渲染球体(在 Java w/ LWJGL3 中)。

我已经有了一个生成球体顶点的工作算法(使用 GL_TRIANGLE_STRIP 原语)。但是,我不知道如何为这些顶点设置纹理坐标和法线。

    float angleA, angleB;
    float cos, sin;
    float r1, r2;
    float h1, h2;

    for (angleA = -90.0f; angleA < 90.0f; angleA += SPHERE_STEP) {
        r1 = (float) Math.cos(angleA * Math.PI / 180.0);
        r2 = (float) Math.cos((angleA + SPHERE_STEP) * Math.PI / 180.0);
        h1 = (float) Math.sin(angleA * Math.PI / 180.0);
        h2 = (float) Math.sin((angleA + SPHERE_STEP) * Math.PI / 180.0);

        for (angleB = 0.0f; angleB <= 360.0f; angleB += SPHERE_STEP) {
            cos = (float) Math.cos(angleB * Math.PI / 180.0);
            sin = -(float) Math.sin(angleB * Math.PI / 180.0);

            renderer.addVertex(r2*cos, h2, r2*sin, s1, t1, n1x, n1y, n1z);
            renderer.addVertex(r1*cos, h1, r1*sin, s2, t2, n2x, n2y, n2z);
        }
    }

我的问题是纹理坐标 s1、s2、t1 和 t2 以及法线 n1x、n1y、n2z、n2x、n2y、n2z(在两个 addVertex 行中)都是未知的。我也不知道我应该使用哪种纹理 - 我只想要一个球(如大理石或足球)。 folowwing 图像显示了生成顶点的方式(我没有 10 个声誉...):http://i.stack.imgur.com/h6B31.png

有人有想法吗?如果你的提议完全不同,包括一个新算法但有纹理坐标和法线,它也很完美!

您可以简单地通过归一化给定的顶点来计算法线。 所以,如果你的每个顶点都位于:

vec3(r2*cos, h2, r2*sin)
// and
vec3(r1*cos, h1, r1*sin)

...那么相应的法线将是:

normalize(vec3(r2*cos, h2, r2*sin))
// and 
normalize(vec3(r1*cos, h1, r1*sin))

他们只是在每个给定的点上指向球体之外。

然而,纹理有点困难。我建议阅读 this,以便理解这一点:

U = ((-Z/|X|) + 1)/2
V = ((-Y/|X|) + 1)/2

法线

对于球体,法线与位置相同。至少只要球体以原点为中心,并且半径为 1.0,发布的代码中的计算就是这种情况。如果您描绘几何形状,这很直观。球体的表面正交于一个从中心到表面各点的向量。

或者,如果您喜欢数学,可以使用 ab 作为参数化球体的两个角度:

    [ cos(b) * cos(a) ]
v = [ cos(b) * sin(a) ]
    [ sin(b)          ]

我们可以计算出两个梯度向量:

          [ - cos(b) * sin(a) ]
dv / da = [ cos(b) * cos(a)   ]
          [ 0                 ]

          [ - sin(b) * cos(a) ]
dv / db = [ - sin(b) * sin(a) ]
          [ cos(b)            ]

然后法线就是两个梯度向量的叉积:

[ cos(b) * cos(a) * cos(b)                                              ]
[ cos(b) * sin(a) * cos(b)                                              ]
[ cos(b) * sin(a) * sin(b) * sin(a) + cos(b) * cos(a) * sin(b) * cos(a) ]

  [ cos(b) * cos(a) * cos(b) ]
= [ cos(b) * sin(a) * cos(b) ]
  [ cos(b) * sin(b)          ]

= cos(b) * v

所以叉积是v的倍数。由于 v 已经是一个法线向量,法线与 v.

相同

这意味着如果您使用专门用于球体的着色器,您甚至不需要单独的法线顶点属性。您传入位置,并使用位置和法线的属性值。您可以照常使用不变的属性。对于位置,可以用球体半径缩放,用球体位置平移。

纹理坐标

至于纹理坐标,它们并不是真正唯一的。一种简单的方法是您基本上使用您已经用于参数化球体的两个角度。除了将它们缩放到 0.0 到 1.0 的范围之外。使用代码中的命名法,两个纹理坐标可以计算为:

s = angleB / 360.0f;
t = (angleA + 90.0f) / 180.0f;

这样做的缺点是间距很不相等。特别是对于 s,靠近两极的单位距离变化比赤道附近高得多。这意味着如果您映射表示 material 的某种纹理,则生成的图案的大小在整个球体上将不均匀。

另一种方法是使用立方体映射。您可以对立方体贴图的所有六个面使用相同的图案。然后,用于立方体映射的纹理坐标可以再次与您已经用于位置和法线的相同。所有三个属性的一组属性值!