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


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

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

8 74

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

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

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

normalized polygons

level 1 bulging octahedronlevel 3 bulging octahedron

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

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

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

F(u,v) = [ Кос(х)*Син(В)*Р, потому что(в)*р, Син(х)*Син(В)*Р ]

где:

  • 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...() как a 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 золотых прямоугольников; это просто вопрос в том, чтобы иметь это в качестве отправной точки вместо октаэдра. Вы можете найти пример здесь.

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

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

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-пространстве вокруг сферы.

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