Рисование сферы в OpenGL без использования gluSphere ()?

есть ли какие-либо учебники, которые объясняют, как я могу нарисовать сферу в OpenGL без использования gluSphere()?

многие из 3D-учебников для OpenGL находятся только на кубах. Я искал, но большинство решений для рисования сферы, чтобы использовать gluSphere(). Существует также сайт, который имеет код для рисования сферы в этот сайт но это не объясняет математику, стоящую за рисованием сферы. У меня также есть другие версии того, как нарисовать сферу в polygon вместо этого из квадроциклов в этой ссылке. Но опять же, я не понимаю, как сферы рисуются с помощью кода. Я хочу иметь возможность визуализировать, чтобы я мог изменить сферу, если мне нужно.

8 ответов


один из способов сделать это-начать с платонического твердого тела с треугольными сторонами-an октаэдра, например. Затем возьмите каждый треугольник и рекурсивно разбейте его на меньшие треугольники, например:

recursively drawn triangles

Как только у вас будет достаточное количество точек, вы нормализуете их векторы так, чтобы все они находились на постоянном расстоянии от центра твердого тела. Это причиняет стороны выпячивать вне в форму которая походит сфера, с увеличивать гладкость по мере увеличения количества очков.

нормализация здесь означает перемещение точки так, чтобы угол его по отношению к другой точке то же, но расстояние между ними разное. Вот двумерный пример.

enter image description here

A и B разделены на 6 единиц. Но предположим, что мы хотим найти точку на линии AB, которая находится в 12 единицах от A.

enter image description here

можно сказать, что 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

Если мы сделаем этот процесс нормализации на многих точках, все относительно той же точки A и с тем же расстоянием R, то нормализованные точки будут лежать на дуге окружности с центром A и радиусом R.

bulging line segment

здесь черные точки начинаются на линии и" выпячиваются " в дугу.

этот процесс можно расширить в 3 измерения, в этом случае вы сделать шар, а не круг. Просто добавьте компонент dz в функцию normalize.

normalized polygons

level 1 bulging octahedronlevel 3 bulging octahedron

Если вы посмотрите на сферы на Эпкот, вы можете увидеть эту технику в работе. это додекаэдр с выпуклыми лицами, чтобы казаться круглее.


Я далее объясню популярный способ генерации сферы с использованием широты и долготы (другой путь,icospheres, уже было объяснено в самом популярном ответе на момент написания этой статьи.)

сфера может быть выражена следующим параметрическим уравнением:

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

где:

  • r - это радиус;
  • u - долгота в диапазоне от 0 до 2π; и
  • v - широта, в диапазоне от 0 до π.

генерация сферы затем включает в себя оценку параметрической функции через фиксированные интервалы.

например, чтобы создать 16 линий долготы, будет 17 линий сетки вдоль u ось, с шагом π/8 (2π/16) (17 линия обтекает).

следующий псевдокод генерирует треугольную сетку, оценивая параметрическую функцию через регулярные промежутки времени (это работает для любой функции параметрической поверхности, а не только сферы).

в псевдокоде ниже 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 определяет, сколько горизонтальных линий вы хотите иметь в своей сфере и lon сколько вертикальных линий. r - радиус сферы.

теперь есть двойная итерация над lat/lon и координаты вершин вычисляются с помощью простой тригонометрии.

вычисленные вершины теперь отправляются на ваш GPU с помощью glVertex...() как GL_QUAD_STRIP, что означает, что вы отправляете каждые две вершины, которые образуют квад с двумя ранее отправленными.

все, что вам нужно понять сейчас, это как работают функции тригонометрии, но я думаю, вы можете легко понять это.


Если вы хотите быть хитрым, Как лиса, вы можете на полдюйма код от GLU. Проверьте исходный код MesaGL (http://cgit.freedesktop.org/mesa/mesa/).


см. Красную книгу OpenGL:http://www.glprogramming.com/red/chapter02.html#name8 Он решает проблему путем разбиения полигона.


хотя принятый ответ решает вопрос, в конце есть небольшое заблуждение. додекаэдры являются (или могут быть) регулярными многогранниками, где все грани имеют одинаковую площадь. Это, по-видимому, относится к Epcot (который, кстати, не является додекаэдр на всех). Поскольку решение, предложенное @Kevin, не дает этой характеристики, я подумал, что могу добавить подход, который делает это.

хороший способ создания N-лицевого многогранника где все вершины лежат в одной сфере и все его грани имеют одинаковую площадь / поверхность, начиная с икосаэдра и итеративно подразделяя и нормализуя его треугольные грани (как предложено в принятом ответе). Додекаэдры, например, на самом деле усе икосаэдры.

регулярные икосаэдры имеют 20 граней (12 вершин) и могут быть легко построены из 3 золотых прямоугольников; это просто вопрос в том, чтобы иметь это в качестве отправной точки вместо октаэдра. Вы можете найти пример здесь.

Я знаю, что это немного не по теме, но я полагаю, это может помочь, если кто-то здесь ищет этот конкретный случай.


мой пример использования "треугольной полосы" для рисования "полярной" сферы, она состоит в рисовании точек попарно:

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

первая введенная точка (glVertex3f) является следующим параметрическим уравнением, а вторая смещена на один шаг Альфа-угла (от следующей параллели).


один из способов-сделать квадроцикл, обращенный к камере, и написать шейдер вершин и фрагментов, который отображает что-то похожее на сферу. Вы можете использовать уравнения для круга / сферы, которые вы можете найти в интернете.

одна хорошая вещь заключается в том, что силуэт сфера выглядит одинаково с любого угла. Однако, если сфера не находится в центре перспективного вида, то она, возможно, больше похожа на эллипс. Вы могли бы разработать уравнения для этого и поместить их в затенение фрагмента. Затем световое затенение должно изменяться по мере движения игрока, если у вас действительно есть игрок, движущийся в 3D-пространстве вокруг сферы.

может ли кто-нибудь прокомментировать, если они попробовали это или если это было бы слишком дорого, чтобы быть практичным?