您如何以编程方式生成球体?


25

有人可以解释一下如何创建球体的顶点,索引和纹理坐标吗?令人惊讶的是缺少有关如何执行此操作的文档,这是我感兴趣的东西。

我尝试了显而易见的搜索,在gamedev.net上进行了搜索,等等。但是,没有什么可以涵盖世代的球形点,对其进行索引和构造。


6
我不会投票否决这个问题,但您是真的告诉我,google.com/search ? q=how+to+to+generate+a+sphere+vertices没有一个有用的结果吗?在这种情况下,您需要更详细地说明问题所在。


搜索icosphere。比笨拙的“极球”聪明得多,后者会产生无用的面孔。
Notabene 2011年

3
值得注意的是,出于某些简单目的,一个完美的“球体”是一个具有圆形纹理的四边形,面向镜头。
aaaaaaaaaaaaaa

这是在游戏中为天穹实现的方法。
danijar

Answers:


36

有两种通用方法:

在此处输入图片说明

最左边的称为uv-sphere,最右边的称为icosphere。

GLUT倾向于使用紫外线的方法:看功能glutSolidSphere()freeglut源代码

这是一篇有关制作icosphere的优秀文章:http ://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html

uv球看起来像一个地球仪。对于许多目的来说,它是非常好的,但是对于某些用例,例如,如果您要使球体变形,则不利的是,极点周围的顶点密度更大。这里的圈圈比较好,其顶点分布均匀。

您可能还会发现这很有趣:http : //kiwi.atmos.colostate.edu/BUGS/geodesic/text.html,它描述了一种将面部组织成区域的方法。

http://vterrain.org/Textures/spherical.html很好地描述了您如何选择对它们进行纹理处理。


2
尽管总体思路很好,但细分Schläfli{3,5}多面体并不是唯一的方法。通常,我更喜欢与Schläfli{4,*}系列(如果是球体,则为{4,3})进行UV映射。
马丁·索伊卡

细分的二十面体球体的生成成本更高,因为需要递归地细分这些面。
bobobobo

9

有两种方法可以做到这一点:

  1. 在球坐标系中行走theta和phi,生成面和Tris

  2. 创建二十面体并递归细分面,直到达到所需的细分为止。

球体使用球面坐标游走

对于第一种方法,您只需要使用double嵌套即可走theta和phi。行走theta和phi时,旋转三角形以创建球体。

在此处输入图片说明

执行该操作的代码如下所示:

for( int t = 0 ; t < stacks ; t++ ) // stacks are ELEVATION so they count theta
{
  real theta1 = ( (real)(t)/stacks )*PI ;
  real theta2 = ( (real)(t+1)/stacks )*PI ;

  for( int p = 0 ; p < slices ; p++ ) // slices are ORANGE SLICES so the count azimuth
  {
    real phi1 = ( (real)(p)/slices )*2*PI ; // azimuth goes around 0 .. 2*PI
    real phi2 = ( (real)(p+1)/slices )*2*PI ;

    //phi2   phi1
    // |      |
    // 2------1 -- theta1
    // |\ _   |
    // |    \ |
    // 3------4 -- theta2
    //

    //vertex1 = vertex on a sphere of radius r at spherical coords theta1, phi1
    //vertex2 = vertex on a sphere of radius r at spherical coords theta1, phi2
    //vertex3 = vertex on a sphere of radius r at spherical coords theta2, phi2
    //vertex4 = vertex on a sphere of radius r at spherical coords theta2, phi1

    // facing out
    if( t == 0 ) // top cap
      mesh->addTri( vertex1, vertex3, vertex4 ) ; //t1p1, t2p2, t2p1
    else if( t + 1 == stacks ) //end cap
      mesh->addTri( vertex3, vertex1, vertex2 ) ; //t2p2, t1p1, t1p2
    else
    {
      // body, facing OUT:
      mesh->addTri( vertex1, vertex2, vertex4 ) ;
      mesh->addTri( vertex2, vertex3, vertex4 ) ;
    }
  }
}

因此,请注意上面的内容,仅使用Tris而不是Quads来缠绕顶盖和底盖很重要。

二十面体球

要使用二十面体,只需生成二十面体的点,然后从中缠绕三角形。位于原点的二十面体顶点为

(0, ±1, ±φ)
1, ±φ, 0)
(±φ, 0, ±1)
where φ = (1 + 5) / 2 

然后,您只需要查看一个二十面体和这些顶点的风面图。我已经有在这里做的代码


任何想法如何获得半身,例如从theta = pi / 4到theta = 3pi * 4?就像这张图片:i.stack.imgur.com/Jjx2c.jpg我已经花了数天时间解决了这个问题。
蒂娜·J

3

如果点不必是局部一致的,而应该是全球统一的,而不必遵循任何一套模式,您可以用飞镖投掷算法的一个变体来分发ň半径在球体点[R ,平均dist分。这些值大致为:

  1. 如果要具有特定数量的顶点:
    • n =(所需的顶点数量)
    • dist = 2× r ×√(π / n
  2. 如果要在顶点之间具有特定的平均距离:
    • n = 4× π ×(r / 距离2
    • dist =(期望的平均距离)

在最简单的情况下,然后可以通过从(0,1)中选取两个均匀分布的变量uv并根据公式θ = 2× π × uϕ = arc 来计算极坐标,来随机地均匀拾取点cos(2× v -1); 然后消除太接近已经选取的点的任何点。有关稍微复杂且性能明显更好的算法,请参见Cline,Jeschke,White,Razdan和Wonka撰写的“ Dart Throwing on Surfaces ”。

选择了前四个点后(假设它们中的三个都没有退化,也就是说-它们不在同一个大圆上,但这不太可能),则可以在它们之间创建四个面,并且每次添加一个新点,您可以将其所属的面分为三个子面。

出于纹理化的目的,您可以将这些点映射到立方体贴图。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.