Java 生成球体顶点、索引和法线?

Java 生成球体顶点、索引和法线?,java,opengl,lwjgl,Java,Opengl,Lwjgl,我正在用LWJGL制作一个游戏,我正在尝试制作一个程序生成的行星(这个问题不一定与程序生成地形有关,我知道如何在平面上生成,我认为这有点类似)。我的问题是,我如何编程生成具有顶点、索引和法线的球,并在中间有原点。我在互联网上四处寻找,只能找到生成顶点的方法。我不是要求你写代码,但我想在正确的方向上推动,或在这样做的一些资源。我希望生成自己的球体而不是从模型中导入一个球体的原因是,我可以轻松编辑顶点高度以生成地形、更改球体的大小以及轻松更改多边形计数。关于如何做到这一点,我的想法如下 获取构成圆周

我正在用LWJGL制作一个游戏,我正在尝试制作一个程序生成的行星(这个问题不一定与程序生成地形有关,我知道如何在平面上生成,我认为这有点类似)。我的问题是,我如何编程生成具有顶点、索引和法线的球,并在中间有原点。我在互联网上四处寻找,只能找到生成顶点的方法。我不是要求你写代码,但我想在正确的方向上推动,或在这样做的一些资源。我希望生成自己的球体而不是从模型中导入一个球体的原因是,我可以轻松编辑顶点高度以生成地形、更改球体的大小以及轻松更改多边形计数。关于如何做到这一点,我的想法如下

获取构成圆周的顶点数(数量越大,多边形越高)。把这个数字除以360,然后每个三角形都会被这个数字旋转成一个圆。然后使用相同的方法逐渐制作球体的其余部分。如果这是正确的方法,我将如何确定索引和法线

获取球体应距原点的顶点数和半径。确定每个三角形应旋转的量。从顶部以指定角度的两个三角形开始,然后从那里向外延伸,直到它以相同的角度到达球体下方,然后反转角度,以相同的方式完成底部。但我也不知道如何生成索引或法线。

生成顶点位置和法线 最简单的方法是从一个坐标系开始,在这个坐标系中,您可以想象一个规则的栅格间距,在纬度上从-90°到90°(或在径向角度上从-pi到pi),在经度上从0到360°。如果将此栅格从球坐标转换为笛卡尔坐标(半径为1或其他所需半径)

法线实际上很容易生成:因为球体的中心位于
(0,0,0)
,所以向量
(x,y,z)
的法线就是归一化向量
(x,y,z)/长度(x,y,z)

生成索引 还记得我是如何将球体描述为规则网格的吗?
更准确地说,网格上的点是
(经度、纬度)
成对的表单
(i*lon\u步长-90°,j*lat\u步长)
。通过使用索引
i*num\u lat\u steps+j

其中
num\u lat\u steps-1
j
的最大值。 要构建索引缓冲区,只需使用此索引将
(i,j)、(i+1,j)、(i,j+1)
(i+1,j+1)、(i,j+1)、(i+1,j)
处的顶点连接到网格内每个索引对的三角形


请注意,使用此方法时,有两个点(在lat=90°或lat=-90°时)在顶点缓冲区中多次出现。如果你想消除这些重复项,你的索引会变得有点棘手,但无论如何你可能不必这样做(这并没有那么大的开销)。

下面的伪代码通过沿层的周长叠加
layerTile
层和
圆周
顶点位置来创建一个球体

底层和顶层是盖子,中间的层是圆盘。 由于球体的中心是(0,0,0),因此顶点和法向量具有相同的方向。法向量被归一化,并从球体中心指向球面

纹理坐标包裹在两个半球上。因此,每层的半个圆盘的端点被添加为分离点。这对于具有纹理坐标V=1.0的点很重要,否则将是从纹理末端到下一半球上下一部分开始的脏过渡。在极轴帽上,顶点位置也是多个,具有不同的纹理坐标,以便获得干净的纹理过渡

AddVertex( x, y, z, nvX, nvY, nvZ, u, v );
AddFace( i1, i2, i3 );
AddFace( i1, i2, i3, i4 ) {AddFace( i1, i2, i3 ); AddFace( i1, i3, i4 ); }

int circumferenceTile = 18;
int layerTile = 18;
float radius = 1.0;
创建顶点和属性:

int circCnt = (int)( circumferenceTile + 0.5f );
if ( circCnt < 4 ) circCnt = 4;
int circCnt_2 = circCnt / 2;
int layerCount = (int)( layerTile + 0.5f );
if ( layerCount < 2 ) layerCount = 2;

for ( int tbInx = 0; tbInx <= layerCount; tbInx ++ )
{
  float v = ( 1.0 - (float)tbInx / layerCount );
  float heightFac = Math.sin( ( 1.0 - 2.0 * tbInx / layerCount ) * Math.PI/2.0 );
  float cosUp = Math.sqrt( 1.0 - heightFac * heightFac );
  float z = heightFac;
  for ( int i = 0; i <= circCnt_2; i ++ )
  {
    float u = (float)i / (float)circCnt_2;
    float angle = Math.PI * u;
    float x = Math.cos( angle ) * cosUp;
    float y = Math.sin( angle ) * cosUp;
    AddVertex( x * radius, y * radius, z * radius, x, y, z, u, v );
  }
  for ( int i = 0; i <= circCnt_2; i ++ )
  {
    float u = (float)i / (float)circCnt_2;
    float angle = Math.PI * u + Math.PI;
    float x = Math.cos( angle ) * cosUp;
    float y = Math.sin( angle ) * cosUp;
    AddVertex( x * radius, y * radius, z * radius, x, y, z, u, v );
  }
}
intcirccnt=(int)(周长+0.5f);
如果(circCnt<4)circCnt=4;
int circCnt_2=circCnt/2;
int layerCount=(int)(layerTile+0.5f);
如果(layerCount<2)layerCount=2;

对于(int-tbInx=0;tbInx),您可以通过叠加层来创建球体,或者您可以对现有实体(例如,二十面体)进行细分。法线的计算方法是否与Tobias Ribizel所说的相同?哦,好的,这很有意义。感谢您的帮助和详细回答,这很有帮助。
int circSize_2 = circCnt_2 + 1;
int circSize = circSize_2 * 2;
for ( int i = 0; i < circCnt_2; i ++  )
  AddFace( circSize + i, circSize + i + 1, i );
for ( int i = circCnt_2+1; i < 2*circCnt_2+1; i ++ )
  AddFace( circSize + i, circSize + i + 1, i );
for ( int tbInx = 1; tbInx < layerCount - 1; tbInx ++ )
{
  int ringStart = tbInx * circSize;
  int nextRingStart = (tbInx+1) * circSize;
  for ( int i = 0; i < circCnt_2; i ++ )
    AddFace( ringStart + i, nextRingStart + i, nextRingStart + i + 1, ringStart + i + 1 );
  ringStart += circSize_2;
  nextRingStart += circSize_2;
  for ( int i = 0; i < circCnt_2; i ++ )
    AddFace( ringStart + i, nextRingStart + i, nextRingStart + i + 1, ringStart + i + 1 );
}
int start = (layerCount-1) * circSize;
for ( int i = 0; i < circCnt_2; i ++ )
  AddFace( start + i + 1, start + i, start + i + circSize );
for ( int i = circCnt_2+1; i < 2*circCnt_2+1; i ++ )
  AddFace( start + i + 1, start + i, start + i + circSize );