Самой сложной задачей является правильное вычисление координат всех вершин треугольников и формирование массива индексов Tria, с помощью которого команда glDrawElements обходит массив Vert при задании треугольников. Функция Sphere реализует алгоритм последовательного обхода сначала всех сферических треугольников вокруг полюсов сферы, а затем обхода сферических четырехугольников, образованных пересечением параллелей и меридианов. В процессе обхода формируется массив вершин vert. После этого обходы повторяются для того, чтобы заполнить массив индексов Tria. Северный и южный полюса обрабатываются индивидуально. Для осуществления обхода предварительно создаются константы:
Для упрощения восприятия алгоритма следует учитывать следующие особенности, связанные с порядком обхода вершин:
void Sphere(VERT *v, TRIA* t)
{
//====== Формирование массива вершин
//====== Северный полюс
v[0].v = CPointSD (0, gRad, 0);
v[0].n = CPoint3D (0, 1, 0);
v[0].с = gClr2;
//====== Индекс последней вершины (на южном полюсе)
UINT last = gnVert - 1; //====== Южный полюс
v[last].v = CPointSD (0, -gRad, 0);
v[last].n = CPointSD (0, -1, 0) ;
v[last].c = gnVert & 1 ? gClr2 : gClrl;
//====== Подготовка констант
double da = PI / (gnRings +2.),
db = 2. * PI / gnSects,
af = PI - da/2.;
bf = 2. * PI - db/2.;
//=== Индекс вершины, следующей за северным полюсом
UINT n = 1;
//=== Цикл по широтам
for (double a = da; a < af; a += da)
{
//=== Координата у постоянна для всего кольца
double у = gRad * cos(a),
//====== Вспомогательная точка
xz = gRad * sin(a);
//====== Цикл по секциям (долгота)
for (double b = 0.; b < bf; n++, b += db)
}
// Координаты проекции в экваториальной плоскости
double х = xz * sin(b), z = xz * cos(b);
//====== Вершина, нормаль и цвет
v[n].v = CPointSD (x, у, z);
v[n].n = CPointSD (x / gRad, у / gRad, z / gRad);
v[n].c = n & 1 ? gClrl : gClr2; } }
//====== Формирование массива индексов
//====== Треугольники вблизи полюсов
for (n = 0; n < gnSects; n++)
{
//====== Индекс общей вершины (северный полюс)
t[n] .11 = 0;
//====== Индекс текущей вершины
t[n] .12 = n + 1;
//====== Замыкание
t[n].13 = n == gnSects - 1 ? 1 : n + 2;
//====== Индекс общей вершины (южный полюс)
t [gnTria-gnSects+n] .11 = gnVert - 1;
t tgnTria-gnSects+n] . 12 = gnVert - 2 - n;
t [gnTria-gnSects+n] .13 = gnVert - 2
t ( (1 + n) % gnSects) ;
}
//====== Треугольники разбиения колец
//====== Вершина, следующая за полюсом
int k = 1;
//====== gnSects - номер следующего треугольника
S' n = gnSects;
for (UINT i = 0; i < gnRings; i++, k += gnSects) {
for (UINT j = 0; j < gnSects; j++, n += 2) {
//======= Индекс общей вершины
t[n] .11 = k + j;
//======= Индекс текущей вершины
t[n].12 = k + gnSects + j;
//======= Замыкание
t[n].13 = k + gnSects + ((j + 1) % gnSects)
//======= To же для второго треугольника
t[n + 1].11 = t[n].11;
t[n + 1].12 = t[n].13;
t[n + 1].13 = k + ((j + 1) % gnSects);
Для завершения работы осталось дополнить программу стандартным набором процедур, алгоритм функционирования которых вы уже изучили:
void_stdcall OnSize(GLsizei w, GLsizei h) { glViewport(0, 0, w, h);
}
void main ()
{
auxInitDisplayMode(AUX_RGB | AUX_DOUBLE) ;
auxInitPositiondO, 10, 512, 512);
auxInitwindow("Vertex Array");
Init() ;
auxReshapeFunc (OnSize) ;
auxIdleFunc (OnDraw) ;
auxMainLoop (OnDraw) ;
}
Запустите проект на выполнение и уберите возможные неполадки. Исследуйте функционирование программы, вводя различные значения глобальных параметров (регулировок). Попробуйте задать нечетное число секций. Объясните результат. В качестве упражнения введите возможность интерактивного управления степенью дискретизации сферы и исследуйте эффективность работы конвейера при ее увеличении.