Название: Компьютерная графика(Е.Н. Павенко)

Жанр: Информатика

Просмотров: 1428


2. поверхности безье

Математически фрагмент поверхности Безье задается  уравнением

S(u,v)=

где  – представляет собой множество  контрольных точек, а функции  – те же самые многочлены Бернштейна, что и для одного измерения. Значения  могут представлять вершины, нормали, цвета или текстурные координаты.

Поверхности Безье формируются в OpenGL примерно по той же методике, что и кривые, только роль функции инициализации играет не glMap1*(), а glMap2*(), а для считывания результатов следует обращаться к функции glEvalCoord2*() вместо glEvalCoord1*(). В обеих функциях нужно специфицировать данные, относящиеся к двум независимым параметрам u и v. Например, функция glMap2f() имеет такой формат вызова:

glMap2f(type, u_min, u_max, u_stride, u_order, v_min, v_max, v_stride, v_order, point_array);

Настройка функции вычисления на работу с бикубической поверхностью Безье, определенной на области (0,1)х(0,1), выполняется таким вызовом glMap2f():

glMap2f(GL_MAP_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, data);

Для обоих независимых переменных нужно задать порядок полинома (аргументы u_order и v_order) и количество значений параметра между сегментами (аргументы u_stride и v_stride), что обеспечивает дополнительную гибкость при формировании поверхности. Обратите внимание на то, что значение v_stride для второго параметра равно 12, поскольку в массиве опорных точек  data данные хранятся по строкам. Поэтому для перехода к следующему элементу этой же строки нужно «перешагнуть» три числа в формате float, а для перехода к следующему элементу в этом же столбце нужно «перешагнуть» через 3*4=12 чисел в формате float. Способ вызова программы расчета зависит от того, какой результат мы хотим получить, – вывести на экран сеть или сформировать многоугольники для последующего раскрашивания. Если ставится задача сформировать на экране сеть, то соответствующий фрагмент программы должен выглядеть примерно так:

            for(j=0; j<100; j++)

{

            glBegin(GL_LINE_STRIP);

                        for(i=0; i<100; i++)

                        glEvalCoord2f((float)i/100.0, (float)j/100.0);

            glEnd();

            glBegin(GL_LINE_STRIP);

                        for(i=0; i<100; i++)

                        glEvalCoord2f((float)j/100.0, (float)i/100.0);

            glEnd();

            }

Если же желательно сформировать множество многоугольников, то фрагмент должен выглядеть так:

            for(j=0; j<99; j++)

            {

                        glBegin(GL_QUAD_STRIP)

                        for(i=0; i<=100; i++)

                        {

                        glEvalCoord2f( (float)i/100.0, (float)j/100.0);

                        glEvalCoord2f( (float)(i+1)/100.0, (float)j/100.0);

                        }

                        glEnd();

            }         

Для работы на равномерной сетке следует использовать функции glMapGrid2*() и glEvalMesh2(). Тогда в самое начало программы, в ту часть, которая отвечает за инициализацию, нужно включить такой фрагмент:

glMapGrid2f(100, 0.0, 1.0, 100, 0.0, 1.0);

В функции отображения display() нужно вызвать glEvalMesh2():

glEvalMesh2(GL_FILL, 0, 100, 0, 100);

Для работы алгоритмов тонирования (закрашивания) сформированной поверхности при настройке режима учета освещения нужно дополнительно вызвать функцию glEnable(), передав ей в качестве аргумента константу GL_AUTO_NORMAL:

glEnable(GL_AUTO_NORMAL);

Это позволит OpenGL автоматически вычислять вектор нормали к каждому участку формируемой поверхности и использовать этот вектор при закрашивании участков этой поверхности.

Пример программы аппроксимации с помощью поверхности Безье функции z=sin(x+y):

#include <stdlib.h>

#include <GL/glut.h>

#include <math.h>

#include <stdio.h>

GLfloat ctrlpoints[6][6][3];

void initlights(void)

{

   GLfloat ambient[] = {1.0, 1.0, 1.0, 1.0};

   GLfloat position[] = {0.0, 0.0, 2.0, 1.0};

   GLfloat mat_diffuse[] = {1.0, 1.0, 1.0, 1.0};

   GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};

   GLfloat mat_shininess[] = {50.0};

   glEnable(GL_LIGHTING);

   glEnable(GL_LIGHT0);

   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);

   glLightfv(GL_LIGHT0, GL_POSITION, position);

   glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);

   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);

   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

}

void display(void)

{

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glPushMatrix();

   glRotatef(85.0, 1.0, 0.0, 0.0);

            glEvalMesh2(GL_FILL, 0, 10, 0, 10);

   glPopMatrix();

   glFlush();

}

void init(void)

{

            float x,y;

            int i,j;

for (i=0; i<6;i++)

{

            x=3.1415/5.0*(float)i;

            for(j=0; j<6; j++)

            {

                        y=3.1415/5.0*(float)j;

                        ctrlpoints[i][j][0]=x;

                        ctrlpoints[i][j][1]=y;

                        ctrlpoints[i][j][2]=sin(x+y);

            }

}

   glClearColor(0.0, 0.0, 0.0, 0.0);

   glEnable(GL_DEPTH_TEST);

   glMap2f(GL_MAP2_VERTEX_3, 0, 4, 3, 4,

           0, 4, 18, 4, &ctrlpoints[0][0][0]);

   glEnable(GL_MAP2_VERTEX_3);

   glEnable(GL_AUTO_NORMAL);

  glMapGrid2f(10, 0.0, 4.0, 10, 0.0, 4.0);

   initlights();       /* for lighted version only */

}

void reshape(int w, int h)

{

   glViewport(0, 0, 400, 400);

   glMatrixMode(GL_PROJECTION);

   glLoadIdentity();

         glOrtho(-1.0,2.0, -1.0, 2.0, -2.0, 2.0);

   glMatrixMode(GL_MODELVIEW);

   glLoadIdentity();

}

void keyboard(unsigned char key, int x, int y)

{

   switch (key) {

      case 27:

         exit(0);

         break;

   }

}

int main(int argc, char **argv)

{

   glutInit(&argc, argv);

   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

   glutInitWindowSize (500, 500);

   glutInitWindowPosition (100, 100);

   glutCreateWindow(argv[0]);

   init();

   glutReshapeFunc(reshape);

   glutDisplayFunc(display);

   glutKeyboardFunc(keyboard);

   glutMainLoop();

   return 0;

}

Порядок выполнения лабораторной работы

Отладить и запустить программу рисования кривой Безье, приведенную в тексте лабораторной работы.

Изобразить кривую Безье на основе данных, заданных преподавателем.

Отладить и запустить программу рисования поверхности Безье, приведенную в тексте лабораторной работы.

Изобразить поверхность Безье на основе данных, заданных преподавателем.

Контрольные вопросы

Математические основы использования бета-сплайнов в компьютерной графике.

Интерполяция и аппроксимация с использованием сплайнов.

Кривые и поверхности Безье. Математические основы.

Построение кривых и поверхностей Безье средствами OpenGL.