OpenGL 3.2球体-纹理坐标

OpenGL 3.2球体-纹理坐标,opengl,textures,normals,Opengl,Textures,Normals,我正在使用OpenGL3.2(JavaW/LWJGL3)渲染一个球体 我已经有了一个生成球体顶点的有效算法(使用GL_三角形_条带原语)。但是,我不知道如何为这些顶点设置纹理坐标和法线 float angleA, angleB; float cos, sin; float r1, r2; float h1, h2; for (angleA = -90.0f; angleA < 90.0f; angleA += SPHERE_STEP) {

我正在使用OpenGL3.2(JavaW/LWJGL3)渲染一个球体

我已经有了一个生成球体顶点的有效算法(使用GL_三角形_条带原语)。但是,我不知道如何为这些顶点设置纹理坐标和法线

    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);
        }
    }
浮动角度A、角度B;
因为,罪恶;
浮球r1,r2;
浮子h1,h2;
对于(angleA=-90.0f;angleA<90.0f;angleA+=SPHERE_阶跃){
r1=(float)Math.cos(angleA*Math.PI/180.0);
r2=(float)Math.cos((angela+SPHERE_步长)*Math.PI/180.0);
h1=(float)Math.sin(angleA*Math.PI/180.0);
h2=(float)Math.sin((angleA+SPHERE_步长)*Math.PI/180.0);

对于(angleB=0.0f;angleB),只需对给定顶点进行规格化即可计算法线。 因此,如果每个顶点都位于:

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))
它们只是指向球体外的每个给定点

然而,纹理处理有点困难。为了理解这一点,我建议阅读:

U = ((-Z/|X|) + 1)/2
V = ((-Y/|X|) + 1)/2
常态 对于球体,法线与位置相同。至少只要球体以原点为中心,半径为1.0,这就是发布代码中的计算情况。如果您绘制几何图形,这是直观的。球体的曲面与从圆心到曲面上每个点的向量正交e

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

    [ 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
然后法线是两个梯度向量之间的叉积:

          [ - 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相同

这意味着,如果您专门为球体使用着色器,则法线甚至不需要单独的顶点属性。您可以传入位置,并将属性值同时用于位置和法线。您可以使用属性作为法线不变。对于位置,您可以使用球体半径对其进行缩放,然后使用e球体位置

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

s = angleB / 360.0f;
t = (angleA + 90.0f) / 180.0f;
这样做的缺点是间距非常不相等。特别是对于
s
,靠近两极时每距离的变化远高于赤道周围的变化。这意味着,如果映射某种表示材质的纹理,则生成的图案在整个球体上的大小将不均匀

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