在OpenGL中绘制球体而不使用gluSphere()?

有没有任何教程,解释了如何在OpenGL中绘制球体而不必使用gluSphere()

许多OpenGL的3D教程只是在立方体上。 我已经search,但绘制一个球体的大部分解决scheme是使用gluSphere() 。 还有一个网站有代码在这个网站上绘制一个球体,但它不能解释绘制球体的背后的math。 我也有其他版本的如何绘制在多边形领域,而不是四边形在该链接。 但是,我不明白这些代码是如何绘制的。 我希望能够可视化,以便我可以在需要时修改球体。

你可以做的一个方法是从一个带有三angular形的柏拉图立体开始 – 例如八面体 。 然后,将每个三angular形recursion地分解成更小的三angular形,如下所示:

递归绘制三角形

一旦你有足够数量的点,你将它们的vector标准化,使它们与固体中心的距离都是恒定的。 这会导致两侧凸起成类似于球体的形状,随着您增加点数的增加,平滑度也会增加。

这里的归一化意味着移动一个点,使得它相对于另一个点的angular度是相同的,但是它们之间的距离是不同的。 这是一个二维的例子。

在这里输入图像描述

A和B相隔6个单位。 但是,假设我们想要find距离A有12个单位的AB线上的一个点。

在这里输入图像描述

我们可以说C是A的距离为12的B的归一化forms。我们可以用这样的代码获得C:

 #returns a point collinear to A and B, a given distance away from A. function normalize(a, b, length): #get the distance between a and b along the x and y axes dx = bx - ax dy = by - ay #right now, sqrt(dx^2 + dy^2) = distance(a,b). #we want to modify them so that sqrt(dx^2 + dy^2) = the given length. dx = dx * length / distance(a,b) dy = dy * length / distance(a,b) point c = new point cx = ax + dx cy = ay + dy return c 

如果我们对许多点进行归一化处理,对于相同的A点和相同的距离R,归一化的点都将位于中心A和半径为R的圆弧上。

鼓鼓的线段

在这里,黑点从一条线开始并“凸出”成一条弧线。

这个过程可以扩展到三个维度,在这种情况下,你得到一个球体而不是一个圆圈。 只需添加一个dz组件到标准化函数。

标准化的多边形

1级鼓起的八面体3级鼓起的八面体

如果你看看Epcot的球体,你可以在工作中看到这种技术。 这是一个十二面体,凸出的面孔,使其看起来更圆。

我将进一步解释一种使用纬度和经度生成球体的stream行方式(另一种方式, icospheres ,在本文写作时已经被解释为最受欢迎的答案)。

一个球体可以用下面的参数方程表示:

Fuv )= [cos(u)* sin(v)* r,cos(v)* r,sin(u)* sin(v)* r]

哪里:

  • r是半径;
  • u是经度,范围从0到2π; 和
  • v是纬度,范围从0到π。

生成球体则涉及以固定间隔评估参数函数。

例如,为了生成16行的经度,沿着u轴将会有17个网格线,以π/ 8(2π/ 16)(第17行绕回)为步长。

以下伪代码通过定期评估参数函数生成三angular网格(这适用于任何参数曲面函数,而不仅仅是球体)。

在下面的伪代码中, UResolution是沿着U轴的网格点的数量(这里是经度线), VResolution是沿着V轴的网格点的数量(这里是纬度线)

 var startU=0 var startV=0 var endU=PI*2 var endV=PI var stepU=(endU-startU)/UResolution // step size between U-points on the grid var stepV=(endV-startV)/VResolution // step size between V-points on the grid for(var i=0;i<UResolution;i++){ // U-points for(var j=0;j<VResolution;j++){ // V-points var u=i*stepU+startU var v=j*stepV+startV var un=(i+1==UResolution) ? EndU : (i+1)*stepU+startU var vn=(j+1==VResolution) ? EndV : (j+1)*stepV+startV // Find the four points of the grid // square by evaluating the parametric // surface function var p0=F(u, v) var p1=F(u, vn) var p2=F(un, v) var p3=F(un, vn) // NOTE: For spheres, the normal is just the normalized // version of each vertex point; this generally won't be the case for // other parametric surfaces. // Output the first triangle of this grid square triangle(p0, p2, p1) // Output the other triangle of this grid square triangle(p3, p1, p2) } } 

样本中的代码很快就被解释了。 你应该看看函数void drawSphere(double r, int lats, int longs)lat参数定义了你的球体中有多less条水平线, lon了多less条垂直线。 r是你的球体的半径。

现在在lat / lon进行双重迭代,使用简单的三angular函数计算顶点坐标。

所计算的顶点现在使用glVertex...()作为GL_QUAD_STRIP发送到您的GPU,这意味着您将发送每个两个顶点,形成前一个发送的四个顶点。

所有你现在要了解的是三angular函数是如何工作的,但是我想你可以很容易地理解它。

如果你想像狐狸一样狡猾,你可以半英寸的GLU代码。 查看MesaGL源代码(http://cgit.freedesktop.org/mesa/mesa/)。;

请参阅OpenGL红皮书: http : //www.glprogramming.com/red/chapter02.html#name8它通过多边形细分来解决问题。

我的例子如何使用“三angular形带”绘制一个“极地”的球体,它包括绘制成对的点:

 const float PI = 3.141592f; GLfloat x, y, z, alpha, beta; // Storage for coordinates and angles GLfloat radius = 60.0f; int gradation = 20; for (alpha = 0.0; alpha < GL_PI; alpha += PI/gradation) { glBegin(GL_TRIANGLE_STRIP); for (beta = 0.0; beta < 2.01*GL_PI; beta += PI/gradation) { x = radius*cos(beta)*sin(alpha); y = radius*sin(beta)*sin(alpha); z = radius*cos(alpha); glVertex3f(x, y, z); x = radius*cos(beta)*sin(alpha + PI/gradation); y = radius*sin(beta)*sin(alpha + PI/gradation); z = radius*cos(alpha + PI/gradation); glVertex3f(x, y, z); } glEnd(); } 

input的第一个点(glVertex3f)如下参数方程,第二个点移动一个alphaangular度(从下一个平行)。

一种方法是制作一个面向相机的四边形,并写一个顶点和片段着色器,渲染看起来像一个球体的东西。 你可以使用公式在网上find一个圆圈/球体。

一件好事就是球体的轮廓看起来从任何angular度都是一样的。 但是,如果球体不在透视图的中心,那么它可能更像是一个椭圆。 你可以计算出这个公式,并把它们放在片段阴影中。 然后,如果玩家确实有一名玩家在球体周围的三维空间中移动,则光线阴影需要随着玩家的移动而改变。

任何人都可以评论,如果他们已经尝试过,或者如果它太昂贵,实用?

尽pipe接受的答案解决了这个问题,但最后还是有一点误解。 十二面体是(或可能是)正多面体,所有的面都有相同的面积。 这似乎是Epcot(顺便说一句,根本不是十二面体 )的情况。 由于@Kevin提出的解决scheme没有提供这个特性,我想我可以添加一个方法。

生成一个N面多面体的好方法是将所有的顶点放在同一个球面上, 并且所有的面都有相同的面积,从一个二十面体开始,迭代地对其三angular面进行细分和归一化(正如接受的答案中所build议的) 。 例如十二面体实际上是截断的二十面体 。

规则的二十面体有20个面(12个顶点),可以很容易地从3个金色的矩形构造; 只是以此为起点,而不是八面体。 你可以在这里find一个例子。

我知道这有点偏离主题,但我相信如果有人来这里寻找这个具体案例,这可能会有所帮助。