Иллюстрированный самоучитель по Visual Studio.Net

         

Формирование массива вершин и индексов


Самой сложной задачей является правильное вычисление координат всех вершин треугольников и формирование массива индексов Tria, с помощью которого команда glDrawElements обходит массив Vert при задании треугольников. Функция Sphere реализует алгоритм последовательного обхода сначала всех сферических треугольников вокруг полюсов сферы, а затем обхода сферических четырехугольников, образованных пересечением параллелей и меридианов. В процессе обхода формируется массив вершин vert. После этого обходы повторяются для того, чтобы заполнить массив индексов Tria. Северный и южный полюса обрабатываются индивидуально. Для осуществления обхода предварительно создаются константы:

  • da — шаг изменения сферического угла а (широта),
  • db — шаг изменения сферического угла b (долгота),
  • af и bf — конечные значения углов.

    Для упрощения восприятия алгоритма следует учитывать следующие особенности, связанные с порядком обхода вершин:

  • После обработки северного и южного полюсов мы движемся вдоль первой широты (a=da) от востока к западу по невидимой части полусферы и возвращаемся назад по видимой ее части. Затем происходит переход на следующую широту (а += da) и цикл повторяется.

  • Координаты вершин (х, z) представляют собой проекции точек на экваториальную плоскость, а координата у постоянна для каждой широты.

  • При обработке одной секции кольца для двух треугольников формируется по три индекса:

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

    }

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




    Содержание раздела