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

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

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


1. кривые безье

Кривая Безье задается векторной функцией одной переменной

C(u) = [ X(u), Y(u), Z(u)],

где  u изменяется в некоторой области, например, [0.0, 1.0].

Фрагмент поверхности Безье задается векторной функцией двух переменных

S(u, v) = [ X(u, v), Y(u, v), Z(u, v) ].

Для каждого значения u и v формула C( ) или S( ) вычисляет точку на кривой (поверхности). При использовании Безье-вычисления сначала выбирают функцию C( ) или S( ), включают ее (Безье-вычислитель), а затем используют команду glEvalCoord1( ) или glEvalCoord2( ) вместо команды glVertex*( ). В этом случае вершина кривой или поверхности может использоваться точно так же, как и любая другая вершина, например, для формирования точки или линии. Кроме того, другие команды автоматически генерируют серии вершин, образующих пространство регулярной однородной сетки по оси u (или по осям u и v ).     

Если  представляет набор контрольных точек, то уравнение C(u) =   – представляет собой кривую Безье при изменении u от 0.0 до 1.0, где – многочлен Бернштейна степени n, который задается следующим уравнением

    

В составе OpenGL имеются средства поддержки работы с кривыми и поверхностями Безье – Безье-вычислитель, которые позволяют вычислять значения полиномов Безье любого порядка. Безье вычислитель можно использовать для работы с полиномами от одной, двух, трех и четырех переменных.

Функция обработки полинома одной переменной настраивается в процессе инициализации OpenGL – программы посредством вызова функции

glMap1f(type, u_min, u_max, stride, order, point array)

Аргумент  type задает тип объекта, который будет представлен полиномом Безье. Можно назначить в качестве значения этого аргумента константы, задающие трех- и четырехмерные геометрические точки, цвет в формате RGBA, нормали, индексированные цвета и координаты текстур ( от одно- до четырехмерных).

            Указатель на массив опорных точек полинома передается функции через аргумент point_array. Аргументы u_min, u_max определяют область существования параметра полинома. Аргумент stride представляет собой количество значений параметра между сегментами кривой. Значение аргумента order должно быть равно количеству опорных точек. Для формирования кубической трехмерной кривой в форме В-сплайна, определенной на интервале (0,1), функции glMap1f() следует передать такой набор аргументов:

            point data[]= {…};

            glMap1f(GL_MAP_VERTEX_3, 0.0, 1.0, 3, 4, data);

После настройки функция активизируется посредством вызова:

            glEnable(type);

Если функция расчета активизирована, то можно получить от нее значения полинома, вызвав функцию:

            glEvalCoord1f(u);

Таким образом, обращение к glEvalCoord1f() может заменить обращение к функциям glVertex(), glColor(), glNormal(). Пусть, например, функция расчета настроена на формирование кривой Безье на интервале (0,10) по некоторому массиву опорных точек. Набор из 100 точек кривой, равноотстоящих на этом интервале можно получить с помощью такого фрагмента программы:

glBegin(GL_LINE_STRIP)

for(i=0; i<100; i++) glEvalCoord1f( (float)i/100.);

glEnd();           

Если значения параметра u распределены равномерно, то для вычисления точек на кривой следует использовать функции glMapGrid1f() и glEvalMesh1(), например:

            glMapGrid1f(100, 0.0, 10.0);

            glEvalMesh1(GL_LINE, 0, 100);

После вызова glMapGrid1f() устанавливается равномерная сетка в 100 отсчетов, а после вызова функции glEvalMesh1() будет сформирована кривая.

Пример программы вычисления и рисования полинома Безье.

#include <GL/glut.h>

#include <stdlib.h>

GLfloat ctrlpoints[4][3] = {

            { -4.0, -4.0, 0.0}, { -2.0, 4.0, 0.0},

            {2.0, -4.0, 0.0}, {4.0, 4.0, 0.0}};

void init(void)

{

   glClearColor(0.0, 0.0, 0.0, 0.0);

   glShadeModel(GL_FLAT);

   glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]);

   glEnable(GL_MAP1_VERTEX_3);

}

void display(void)

{

   int i;

   glClear(GL_COLOR_BUFFER_BIT);

   glColor3f(1.0, 1.0, 1.0);

   glBegin(GL_LINE_STRIP);

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

         glEvalCoord1f((GLfloat) i/30.0);

   glEnd();

   /* The following code displays the control points as dots. */

   glPointSize(5.0);

   glColor3f(1.0, 1.0, 0.0);

   glBegin(GL_POINTS);

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

         glVertex3fv(&ctrlpoints[i][0]);

   glEnd();

   glFlush();

}

void reshape(int w, int h)

{

   glViewport(0, 0, (GLsizei) w, (GLsizei) h);

   glMatrixMode(GL_PROJECTION);

   glLoadIdentity();

   if (w <= h)

      glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w,

               5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0);

   else

      glOrtho(-5.0*(GLfloat)w/(GLfloat)h,

               5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.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);

   glutInitWindowSize (500, 500);

   glutInitWindowPosition (100, 100);

   glutCreateWindow (argv[0]);

   init ();

   glutDisplayFunc(display);

   glutReshapeFunc(reshape);

   glutKeyboardFunc (keyboard);

   glutMainLoop();

   return 0;

}