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