Java 生成球体顶点、索引和法线?
我正在用LWJGL制作一个游戏,我正在尝试制作一个程序生成的行星(这个问题不一定与程序生成地形有关,我知道如何在平面上生成,我认为这有点类似)。我的问题是,我如何编程生成具有顶点、索引和法线的球,并在中间有原点。我在互联网上四处寻找,只能找到生成顶点的方法。我不是要求你写代码,但我想在正确的方向上推动,或在这样做的一些资源。我希望生成自己的球体而不是从模型中导入一个球体的原因是,我可以轻松编辑顶点高度以生成地形、更改球体的大小以及轻松更改多边形计数。关于如何做到这一点,我的想法如下 获取构成圆周的顶点数(数量越大,多边形越高)。把这个数字除以360,然后每个三角形都会被这个数字旋转成一个圆。然后使用相同的方法逐渐制作球体的其余部分。如果这是正确的方法,我将如何确定索引和法线 或 获取球体应距原点的顶点数和半径。确定每个三角形应旋转的量。从顶部以指定角度的两个三角形开始,然后从那里向外延伸,直到它以相同的角度到达球体下方,然后反转角度,以相同的方式完成底部。但我也不知道如何生成索引或法线。生成顶点位置和法线 最简单的方法是从一个坐标系开始,在这个坐标系中,您可以想象一个规则的栅格间距,在纬度上从-90°到90°(或在径向角度上从-pi到pi),在经度上从0到360°。如果将此栅格从球坐标转换为笛卡尔坐标(半径为1或其他所需半径) 法线实际上很容易生成:因为球体的中心位于Java 生成球体顶点、索引和法线?,java,opengl,lwjgl,Java,Opengl,Lwjgl,我正在用LWJGL制作一个游戏,我正在尝试制作一个程序生成的行星(这个问题不一定与程序生成地形有关,我知道如何在平面上生成,我认为这有点类似)。我的问题是,我如何编程生成具有顶点、索引和法线的球,并在中间有原点。我在互联网上四处寻找,只能找到生成顶点的方法。我不是要求你写代码,但我想在正确的方向上推动,或在这样做的一些资源。我希望生成自己的球体而不是从模型中导入一个球体的原因是,我可以轻松编辑顶点高度以生成地形、更改球体的大小以及轻松更改多边形计数。关于如何做到这一点,我的想法如下 获取构成圆周
(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 );