OpenGL 3.2 Sphere - 纹理坐标

时间:2015-03-16 15:23:04

标签: opengl textures normals

我使用OpenGL 3.2渲染一个Sphere(在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线中)是未知的。我不知道我应该使用什么样的纹理 - 我只想要一个球(像大理石或足球)。下图显示顶点的生成方式(我没有10个声誉......):http://i.stack.imgur.com/h6B31.png

有人有想法吗?如果你的命题完全不同,包括一个新的算法,但有纹理坐标&amp;正常,它也很完美!

2 个答案:

答案 0 :(得分:0)

您只需通过标准化给定顶点即可计算法线。 因此,如果每个顶点都位于:

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)

法线

对于球体,法线与位置相同。至少只要球体在原点居中,并且半径为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,每个距离的变化在靠近极点时比在赤道附近高得多。这意味着如果您映射某种表示材质的纹理,则生成的图案的大小在整个球体上将不一致。

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