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

时间:2022-09-10 19:07:06

Are there any tutorials out there that explain how I can draw a sphere in OpenGL without having to use gluSphere()?

有没有什么教程可以解释我如何在OpenGL中绘制一个球体而不用使用gluSphere()?

Many of the 3D tutorials for OpenGL are just on cubes. I have searched but most of the solutions to drawing a sphere are to use gluSphere(). There is also a site that has the code to drawing a sphere at this site but it doesn't explain the math behind drawing the sphere. I have also other versions of how to draw the sphere in polygon instead of quads in that link. But again, I don't understand how the spheres are drawn with the code. I want to be able to visualize so that I could modify the sphere if I need to.

OpenGL的许多3D教程都是基于立方体的。我已经搜索过了,但是绘制球体的大多数方法都是使用gluSphere()。也有一个网站有在这个网站绘制球体的代码,但它没有解释绘制球体背后的数学原理。我还有其他版本的如何在多边形中画球体而不是在那个连杆中画四边形。但是,我还是不明白这些球是怎么用代码画出来的。我想把它形象化这样我就可以在需要的时候修改球面。

8 个解决方案

#1


230  

One way you can do it is to start with a platonic solid with triangular sides - an octahedron, for example. Then, take each triangle and recursively break it up into smaller triangles, like so:

一种方法是从一个三角形边的柏拉图固体开始,例如一个八面体。然后,取每个三角形,递归地将其分解成更小的三角形,如下所示:

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

Once you have a sufficient amount of points, you normalize their vectors so that they are all a constant distance from the center of the solid. This causes the sides to bulge out into a shape that resembles a sphere, with increasing smoothness as you increase the number of points.

一旦你有足够的点,你使它们的向量标准化,这样它们就和固体的中心保持恒定的距离。这将使边沿膨胀成类似于球体的形状,当你增加点的数量时,会增加平滑度。

Normalization here means moving a point so that its angle in relation to another point is the same, but the distance between them is different. Here's a two dimensional example.

标准化是指移动一个点,使它与另一个点的夹角相等,但它们之间的距离不同。这是一个二维的例子。

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

A and B are 6 units apart. But suppose we want to find a point on line AB that's 12 units away from A.

A和B是6个单位。但是假设我们想在直线AB上找到一个点它离a有12个单位。

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

We can say that C is the normalized form of B with respect to A, with distance 12. We can obtain C with code like this:

我们可以说C是B对A的标准化形式,距离是12。我们可以用如下代码获得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 = b.x - a.x
    dy = b.y - a.y
    #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
    c.x = a.x + dx
    c.y = a.y + dy
    return c

If we do this normalization process on a lot of points, all with respect to the same point A and with the same distance R, then the normalized points will all lie on the arc of a circle with center A and radius R.

如果我们对很多点进行归一化处理,都是关于同一个点a和相同距离R,那么标准化后的点都在圆弧上,圆心为a,半径为R。

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

Here, the black points begin on a line and "bulge out" into an arc.

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

This process can be extended into three dimensions, in which case you get a sphere rather than a circle. Just add a dz component to the normalize function.

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

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

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

If you look at the sphere at Epcot, you can sort of see this technique at work. it's a dodecahedron with bulged-out faces to make it look rounder.

如果你看看Epcot的球体,你可以看到这种技术在起作用。这是一个十二面体,有凸起的面,使它看起来更圆。

#2


15  

I'll further explain a popular way of generating a sphere using latitude and longitude (another way, icospheres, was already explained in the most popular answer at the time of this writing.)

我将进一步解释一种使用纬度和经度生成球体的流行方法(另一种方法,icosphere,在本文撰写时已经用最流行的答案解释了)。

A sphere can be expressed by the following parametric equation:

球面可以用以下参数方程表示:

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

F(u,v)=(cos(u)* sin(v)* r,cos(v)* r,罪(u)* sin(v)* r]

Where:

地点:

  • r is the radius;
  • r是半径;
  • u is the longitude, ranging from 0 to 2π; and
  • u是经度,从0到2π;和
  • v is the latitude, ranging from 0 to π.
  • v是纬度,从0到π。

Generating the sphere then involves evaluating the parametric function at fixed intervals.

生成球面需要以固定的间隔对参数函数进行评估。

For example, to generate 16 lines of longitude, there will be 17 grid lines along the u axis, with a step of π/8 (2π/16) (the 17th line wraps around).

例如,生成16行经度,会有17个网格线沿着u轴,一步的π/ 8(2π/ 16)(17线包裹住)。

The following pseudocode generates a triangle mesh by evaluating a parametric function at regular intervals (this works for any parametric surface function, not just spheres).

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

In the pseudocode below, UResolution is the number of grid points along the U axis (here, lines of longitude), and VResolution is the number of grid points along the V axis (here, lines of latitude)

在下面的伪代码中,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)
 }
}

#3


2  

The code in the sample is quickly explained. You should look into the function void drawSphere(double r, int lats, int longs). The parameters lat defines how many horizontal lines you want to have in your sphere and lon how many vertical lines. r is the radius of your sphere.

示例中的代码很快得到了解释。您应该查看函数void drawSphere(double r、int lats、int long)。参数lat定义了你想要在你的球体中有多少条水平线,以及垂直于多少条垂直线。r是球面的半径。

Now there is a double iteration over lat/lon and the vertex coordinates are calculated, using simple trigonometry.

现在在lat/lon上有一个双迭代,用简单的三角法计算顶点坐标。

The calculated vertices are now sent to your GPU using glVertex...() as a GL_QUAD_STRIP, which means you are sending each two vertices that form a quad with the previously two sent.

现在使用glVertex…()作为GL_QUAD_STRIP将计算出的顶点发送到GPU,这意味着您正在发送两个顶点,它们与前面两个发送的顶点组成一个四边形。

All you have to understand now is how the trigonometry functions work, but I guess you can figure it out easily.

你们现在需要理解的是三角函数是如何工作的,但我猜你们可以很容易地算出来。

#4


1  

If you wanted to be sly like a fox you could half-inch the code from GLU. Check out the MesaGL source code (http://cgit.freedesktop.org/mesa/mesa/).

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

#5


1  

See the OpenGL red book: http://www.glprogramming.com/red/chapter02.html#name8 It solves the problem by polygon subdivision.

参见OpenGL red book: http://www.glprogramming.com/red/chapter02.html#name8,它解决了多边形细分的问题。

#6


1  

Although the accepted answer solves the question, there's a little misconception at the end. Dodecahedrons are (or could be) regular polyhedron where all faces have the same area. That seems to be the case of the Epcot (which, by the way, is not a dodecahedron at all). Since the solution proposed by @Kevin does not provide this characteristic I thought I could add an approach that does.

虽然公认的答案解决了这个问题,但最后还是有一点误解。十二面体是(或可能是)规则多面体,所有面都有相同的面积。这似乎就是Epcot(顺便说一句,它根本不是十二面体)的情况。由于@Kevin提出的解决方案没有提供这种特性,我认为我可以添加一种方法。

A good way to generate an N-faced polyhedron where all vertices lay in the same sphere and all its faces have similar area/surface is starting with an icosahedron and the iteratively sub-dividing and normalizing its triangular faces (as suggested in the accepted answer). Dodecahedrons, for instance, are actually truncated icosahedrons.

一种生成一个n面多面体的好方法是,从一个二十面体开始,迭代地细分并规范化它的三角形面(如所接受的答案所示)。例如,十二面体实际上是被截断的二十面体。

Regular icosahedrons have 20 faces (12 vertices) and can easily be constructed from 3 golden rectangles; it's just a matter of having this as a starting point instead of an octahedron. You may find an example here.

通常的二十面四面体有20个面(12个顶点),可以很容易地从3个黄金矩形构造出来;这只是一个起点而不是八面体的问题。你可以在这里找到一个例子。

I know this is a bit off-topic but I believe it may help if someone gets here looking for this specific case.

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

#7


0  

My example how to use 'triangle strip' to draw a "polar" sphere, it consists in drawing points in pairs:

我的例子是如何用“三角形带”来画一个“极”球,它是成对地画点:

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();
}

First point entered (glVertex3f) is as follows the parametric equation and the second one is shifted by a single step of alpha angle (from next parallel).

第一个点(glVertex3f)是参数方程,第二点是由一个单步的阿尔法角(从下一个平行)移动。

#8


0  

One way is to make a quad that faces the camera and write a vertex and fragment shader that renders something that looks like a sphere. You could use equations for a circle/sphere that you can find on the internet.

一种方法是制作一个面向摄像机的四边形,并编写一个顶点和碎片着色器来渲染一个看起来像球体的物体。你可以在网上找到一个圆/球的方程。

One nice thing is that the silhouette of a sphere looks the same from any angle. However, if the sphere is not in the center of a perspective view, then it would appear perhaps more like an ellipse. You could work out the equations for this and put them in the fragment shading. Then the light shading needs to changed as the player moves, if you do indeed have a player moving in 3D space around the sphere.

一件很好的事情是,球体的轮廓从任何角度看都是一样的。然而,如果球体不在透视视图的中心,那么它可能看起来更像一个椭圆。你可以算出这个方程,并把它们放在碎片阴影中。当玩家移动时,光线阴影需要改变,如果你确实有玩家在三维空间围绕球体移动。

Can anyone comment on if they have tried this or if it would be too expensive to be practical?

有没有人能评论一下他们是否尝试过这种方法,或者这种方法是否太昂贵而不实用?

#1


230  

One way you can do it is to start with a platonic solid with triangular sides - an octahedron, for example. Then, take each triangle and recursively break it up into smaller triangles, like so:

一种方法是从一个三角形边的柏拉图固体开始,例如一个八面体。然后,取每个三角形,递归地将其分解成更小的三角形,如下所示:

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

Once you have a sufficient amount of points, you normalize their vectors so that they are all a constant distance from the center of the solid. This causes the sides to bulge out into a shape that resembles a sphere, with increasing smoothness as you increase the number of points.

一旦你有足够的点,你使它们的向量标准化,这样它们就和固体的中心保持恒定的距离。这将使边沿膨胀成类似于球体的形状,当你增加点的数量时,会增加平滑度。

Normalization here means moving a point so that its angle in relation to another point is the same, but the distance between them is different. Here's a two dimensional example.

标准化是指移动一个点,使它与另一个点的夹角相等,但它们之间的距离不同。这是一个二维的例子。

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

A and B are 6 units apart. But suppose we want to find a point on line AB that's 12 units away from A.

A和B是6个单位。但是假设我们想在直线AB上找到一个点它离a有12个单位。

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

We can say that C is the normalized form of B with respect to A, with distance 12. We can obtain C with code like this:

我们可以说C是B对A的标准化形式,距离是12。我们可以用如下代码获得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 = b.x - a.x
    dy = b.y - a.y
    #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
    c.x = a.x + dx
    c.y = a.y + dy
    return c

If we do this normalization process on a lot of points, all with respect to the same point A and with the same distance R, then the normalized points will all lie on the arc of a circle with center A and radius R.

如果我们对很多点进行归一化处理,都是关于同一个点a和相同距离R,那么标准化后的点都在圆弧上,圆心为a,半径为R。

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

Here, the black points begin on a line and "bulge out" into an arc.

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

This process can be extended into three dimensions, in which case you get a sphere rather than a circle. Just add a dz component to the normalize function.

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

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

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

If you look at the sphere at Epcot, you can sort of see this technique at work. it's a dodecahedron with bulged-out faces to make it look rounder.

如果你看看Epcot的球体,你可以看到这种技术在起作用。这是一个十二面体,有凸起的面,使它看起来更圆。

#2


15  

I'll further explain a popular way of generating a sphere using latitude and longitude (another way, icospheres, was already explained in the most popular answer at the time of this writing.)

我将进一步解释一种使用纬度和经度生成球体的流行方法(另一种方法,icosphere,在本文撰写时已经用最流行的答案解释了)。

A sphere can be expressed by the following parametric equation:

球面可以用以下参数方程表示:

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

F(u,v)=(cos(u)* sin(v)* r,cos(v)* r,罪(u)* sin(v)* r]

Where:

地点:

  • r is the radius;
  • r是半径;
  • u is the longitude, ranging from 0 to 2π; and
  • u是经度,从0到2π;和
  • v is the latitude, ranging from 0 to π.
  • v是纬度,从0到π。

Generating the sphere then involves evaluating the parametric function at fixed intervals.

生成球面需要以固定的间隔对参数函数进行评估。

For example, to generate 16 lines of longitude, there will be 17 grid lines along the u axis, with a step of π/8 (2π/16) (the 17th line wraps around).

例如,生成16行经度,会有17个网格线沿着u轴,一步的π/ 8(2π/ 16)(17线包裹住)。

The following pseudocode generates a triangle mesh by evaluating a parametric function at regular intervals (this works for any parametric surface function, not just spheres).

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

In the pseudocode below, UResolution is the number of grid points along the U axis (here, lines of longitude), and VResolution is the number of grid points along the V axis (here, lines of latitude)

在下面的伪代码中,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)
 }
}

#3


2  

The code in the sample is quickly explained. You should look into the function void drawSphere(double r, int lats, int longs). The parameters lat defines how many horizontal lines you want to have in your sphere and lon how many vertical lines. r is the radius of your sphere.

示例中的代码很快得到了解释。您应该查看函数void drawSphere(double r、int lats、int long)。参数lat定义了你想要在你的球体中有多少条水平线,以及垂直于多少条垂直线。r是球面的半径。

Now there is a double iteration over lat/lon and the vertex coordinates are calculated, using simple trigonometry.

现在在lat/lon上有一个双迭代,用简单的三角法计算顶点坐标。

The calculated vertices are now sent to your GPU using glVertex...() as a GL_QUAD_STRIP, which means you are sending each two vertices that form a quad with the previously two sent.

现在使用glVertex…()作为GL_QUAD_STRIP将计算出的顶点发送到GPU,这意味着您正在发送两个顶点,它们与前面两个发送的顶点组成一个四边形。

All you have to understand now is how the trigonometry functions work, but I guess you can figure it out easily.

你们现在需要理解的是三角函数是如何工作的,但我猜你们可以很容易地算出来。

#4


1  

If you wanted to be sly like a fox you could half-inch the code from GLU. Check out the MesaGL source code (http://cgit.freedesktop.org/mesa/mesa/).

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

#5


1  

See the OpenGL red book: http://www.glprogramming.com/red/chapter02.html#name8 It solves the problem by polygon subdivision.

参见OpenGL red book: http://www.glprogramming.com/red/chapter02.html#name8,它解决了多边形细分的问题。

#6


1  

Although the accepted answer solves the question, there's a little misconception at the end. Dodecahedrons are (or could be) regular polyhedron where all faces have the same area. That seems to be the case of the Epcot (which, by the way, is not a dodecahedron at all). Since the solution proposed by @Kevin does not provide this characteristic I thought I could add an approach that does.

虽然公认的答案解决了这个问题,但最后还是有一点误解。十二面体是(或可能是)规则多面体,所有面都有相同的面积。这似乎就是Epcot(顺便说一句,它根本不是十二面体)的情况。由于@Kevin提出的解决方案没有提供这种特性,我认为我可以添加一种方法。

A good way to generate an N-faced polyhedron where all vertices lay in the same sphere and all its faces have similar area/surface is starting with an icosahedron and the iteratively sub-dividing and normalizing its triangular faces (as suggested in the accepted answer). Dodecahedrons, for instance, are actually truncated icosahedrons.

一种生成一个n面多面体的好方法是,从一个二十面体开始,迭代地细分并规范化它的三角形面(如所接受的答案所示)。例如,十二面体实际上是被截断的二十面体。

Regular icosahedrons have 20 faces (12 vertices) and can easily be constructed from 3 golden rectangles; it's just a matter of having this as a starting point instead of an octahedron. You may find an example here.

通常的二十面四面体有20个面(12个顶点),可以很容易地从3个黄金矩形构造出来;这只是一个起点而不是八面体的问题。你可以在这里找到一个例子。

I know this is a bit off-topic but I believe it may help if someone gets here looking for this specific case.

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

#7


0  

My example how to use 'triangle strip' to draw a "polar" sphere, it consists in drawing points in pairs:

我的例子是如何用“三角形带”来画一个“极”球,它是成对地画点:

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();
}

First point entered (glVertex3f) is as follows the parametric equation and the second one is shifted by a single step of alpha angle (from next parallel).

第一个点(glVertex3f)是参数方程,第二点是由一个单步的阿尔法角(从下一个平行)移动。

#8


0  

One way is to make a quad that faces the camera and write a vertex and fragment shader that renders something that looks like a sphere. You could use equations for a circle/sphere that you can find on the internet.

一种方法是制作一个面向摄像机的四边形,并编写一个顶点和碎片着色器来渲染一个看起来像球体的物体。你可以在网上找到一个圆/球的方程。

One nice thing is that the silhouette of a sphere looks the same from any angle. However, if the sphere is not in the center of a perspective view, then it would appear perhaps more like an ellipse. You could work out the equations for this and put them in the fragment shading. Then the light shading needs to changed as the player moves, if you do indeed have a player moving in 3D space around the sphere.

一件很好的事情是,球体的轮廓从任何角度看都是一样的。然而,如果球体不在透视视图的中心,那么它可能看起来更像一个椭圆。你可以算出这个方程,并把它们放在碎片阴影中。当玩家移动时,光线阴影需要改变,如果你确实有玩家在三维空间围绕球体移动。

Can anyone comment on if they have tried this or if it would be too expensive to be practical?

有没有人能评论一下他们是否尝试过这种方法,或者这种方法是否太昂贵而不实用?