Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Chast_II_Osn_progr_trekhmernoy_grafiki.doc
Скачиваний:
2
Добавлен:
01.05.2025
Размер:
1.83 Mб
Скачать

3. Пример: построение икосаэдра

Для демонстрации приемов, перечисленных в п.2., рассмотрим фрагменты программы, выполняющей построение икосаэдра. Икосаэдр – это правильный многогранник, имеющий 12 вершин и 20 граней (каждая грань – равносторонний треугольник). Икосаэдр можно считать грубой аппроксимацией сферы. Во фрагменте программы 4.1а в массивах заданы вершины икосаэдра и списки вершин каждой грани. После описания и инициализации массивов приведен цикл рисования этих граней.

const double X = .525731112119133606;

const double Z = .850650808352039932;

double vdata[12][3] = {

  {-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},

  {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},

  {Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}

};

int tindices[20][3] = {

  {0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},

  {8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},

  {7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},

  {6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };

for ( int i = 0; i < 20; i++ ) {

  /* Здесь могут быть вызовы функций для задания цвета */

  glBegin( GL_TRIANGLES );

    glVertex3dv( &vdata[tindices[i][0]][0] );

    glVertex3dv( &vdata[tindices[i][1]][0] );

    glVertex3dv( &vdata[tindices[i][2]][0] );

  glEnd();

}

Фрагмент программы 4.1а. Рисование икосаэдра.

Константы X и Z выбраны такими, чтобы расстояние от начала координат до каждой вершины икосаэдра равнялось 1.0. Координаты 12-ти вершин хранятся в массиве vdata[][]: 0-я вершина имеет координаты {-X, 0.0, Z}, 1-я – {X, 0.0, Z} и т.д. Массив tindices[][] задает правила построения треугольных граней из вершин. Например, первый треугольник формируется из 0-й, 4-й и 1-й вершины. Вершины треугольников в массиве tindices[][] перечислены так, что все грани будут иметь одинаковую ориентацию.

В строке с комментарием о цветовой информации можно вызвать функцию, задающую разный цвет для каждой (i-й) грани. Если всем граням присвоить одинаковый цвет, то на изображении они будут сливаться. При закраске граней одним цветом необходимо задавать нормали вершин и применять направленное освещение.

Если вершины полигональной сетки не задаются явно, как во фрагменте 4.1а, а рассчитываются по какому-либо алгоритму, целесообразно выполнять расчеты только один раз и затем хранить рассчитанные координаты вершин и нормалей в массивах или ваших собственных структурах данных.

3.1 Вычисление нормалей к граням икосаэдра

Для применения направленного освещения надо задать вектор нормали для каждой вершины икосаэдра. На плоских гранях икосаэдра вектор нормали одинаков у всех трех вершин (это нормаль к плоскости этой грани). Следовательно, для каждого набора из трех вершин нормаль надо задавать только один раз. Фрагмент программы 4.1б можно разместить в тех строках фрагмента 4.1а, которые отмечены комментарием "вызовы функций для задания цвета".

double d1[3], d2[3], norm[3];

for ( int j = 0; j < 3; j++ ) {

  d1[j] = vdata[tindices[i][1]][j] - vdata[tindices[i][0]][j];

  d2[j] = vdata[tindices[i][2]][j] - vdata[tindices[i][0]][j];

}

normcrossprod( d2, d1, norm );

glNormal3dv( norm );

Фрагмент программы 4.1б. Вычисление нормалей для вершин i-й грани икосаэдра.

Функция normcrossprod() вычисляет нормированное векторное произведение двух векторов (см. фрагмент 4.1в).

void normalize( double v[3] )

{

  double d = sqrt( v[0]*v[0]+v[1]*v[1]+v[2]*v[2] );

  if ( d == 0.0 )

    {

    // Ошибка: вектор нулевой длины

    return;

    }

  v[0] /= d; v[1] /= d; v[2] /= d;

}

void normcrossprod(const double v1[3], const double v2[3], double out[3])

{

  out[0] = v1[1]*v2[2] - v1[2]*v2[1];

  out[1] = v1[2]*v2[0] - v1[0]*v2[2];

  out[2] = v1[0]*v2[1] - v1[1]*v2[0];

  normalize(out);

}

Фрагмент программы 4.1в. Вычисление нормированного векторного произведения.

Нормали вершин не обязательно вычислять как нормаль к плоскости грани. Способ вычисления нормалей зависит от решаемой задачи. Допустим, вы хотите использовать икосаэдр в качестве аппроксимации сферической поверхности. Тогда нормали вершин надо вычислять как перпендикуляры к поверхности сферы, а не перпендикуляры к граням. Для сферы векторы нормали вычислить очень легко: вектор нормали для данной точки сферы совпадает с направлением радиуса для данной точки. В программе 4.1 вершины икосаэдра рассчитывались для икосаэдра, вписанного в единичную сферу. Поэтому в качестве координат нормалей можно взять координаты вершин (см. фрагмент 4.1г).

for ( int i = 0; i < 20; i++)

  {

  glBegin( GL_POLYGON );

    glNormal3dv( &vdata[tindices[i][0]][0] );

    glVertex3dv( &vdata[tindices[i][0]][0] );

    glNormal3dv( &vdata[tindices[i][1]][0] );

    glVertex3dv( &vdata[tindices[i][1]][0] );

    glNormal3dv( &vdata[tindices[i][2]][0] );

    glVertex3dv( &vdata[tindices[i][2]][0] );

  glEnd();

}

Фрагмент программы 4.1г. Рисование икосаэдральной аппроксимации сферы (в предположении, что используется направленное освещение).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]