Рисование сферы в OpenGL без использования gluSphere ()?
есть ли там какие-либо учебники, которые объясняют, как я могу нарисовать сферу в OpenGL без необходимости использовать gluSphere()
?
многие из 3D-учебников для OpenGL находятся только на кубах. Я искал, но большинство решений для рисования сферы, чтобы использовать gluSphere()
. Существует также сайт, который имеет код для рисования сферы в этот сайт но это не объясняет математику за рисованием сферы. У меня также есть другие версии того, как нарисовать сферу в полигоне вместо этого из квадроциклов в этом звене. Но опять же, я не понимаю, как сферы рисуются с помощью кода. Я хочу иметь возможность визуализировать, чтобы я мог изменить сферу, если мне нужно.
8 ответов:
один из способов сделать это-начать с Платоновского твердого тела с треугольными сторонами-an октаэдра, например. Затем возьмите каждый треугольник и рекурсивно разбейте его на меньшие треугольники, например:
Как только у вас будет достаточное количество точек, вы нормализуете их векторы так, чтобы все они находились на постоянном расстоянии от центра твердого тела. Это заставляет стороны выпирать в форму, которая напоминает сферу, с увеличением плавность по мере увеличения количества точек.
нормализация здесь означает перемещение точки так, чтобы угол его по отношению к другой точке то же, но расстояние между ними разное. Вот двумерный пример.
A и B-это 6 единиц друг от друга. Но предположим, что мы хотим найти точку на линии AB, которая находится на расстоянии 12 единиц от A.
можно сказать, что 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.
здесь черные точки начинаются на линии и" выпячиваются " в дугу.
этот процесс может быть расширен до трех измерений, в этом случае вы сделать шар, а не круг. Просто добавьте компонент dz в функцию нормализации.
Если вы посмотрите на сферы на 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...()
как aGL_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-пространстве вокруг сферы.
может кто-нибудь прокомментировать, если они пробовали это, или если это будет слишком дорого, чтобы быть практичным?