Chapter 8
Примеры интересных программ

8.5  Рисуем кривые и поверхности

     В библиотеке glu имеются функции для создания кривых и поверхностей по точкам, аппроксимируя их сплайнами. Все это, по-моему так же круто, как и бесполезно. Здесь я рассмотрю создание поверхности по точкам, которые могут быть заданы в виде массива точек - { (x0, y0, z0), (x1, y1, z1), (x2, y2, z2), …} или в виде уравнения z(x,y). Задача, как правило, состоит в том, чтобы соединить каждые четыре соседние вершины многоугольником и приписать к ним координаты текстуры. В данной программе я наложу тестуру на поверхность, которая колеблется по синусу. Уравнение такой поверхности: z=sin(x+t). Параметр t - время нужен для задания анимации. Создайте новый проект с именем flag и скопируйте туда шаблон glaux.c. Объявите в функции display эту переменную следующим образом:

static double t=0;

…
 t+=0.1; // на каждом кадре увеличиваем ее значение.
  auxSwapBuffers();

     Код построения поверхности будет выглядить так. Вы проходите в двойном цикле по некоторой области в плоскости XY и вычисляете z в зависимости от х и y. Каждые четыре соседние вершины соединяете многоугольником. В данном случае, мы проходим в плоскости XY от точки (0,0) до точки (7,8). Текстуру можно было бы и не привязывать, но тогда бы был совсем не тот эффект. Привязка текстуры делается способом, описанным в главе "Работа с картинками". Левая нижняя точка {0,0, z(0,0)} на поверхности соответствует точке {0,0} на текстуре, а правая верхняя точка на поверхности {7,8,z(7,8)} соответствует точке {1,1} текстуры. Поэтому, если точка на поверхности имеет координаты (x,y), то к ней надо привязать точку текстуры с координатой (x/Max_X, y/Max_Y), т.е. просто приводим к диапазону 0-1. Max_X и Max_Y, как вы понимаете, равны 7 и 8. Ниже следует код функции display c комментариями.

// определяем шаг
#define dx 0.7
#define dy 0.8

void CALLBACK display(void)
{
static double t=0;
double x,y,z;

 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

 // устанавливаем цвет поверхности - белый
 // с другим цветом будет складываться цвет текстуры
 // а с белым будет видна сама текстура без искажений
 glColor3d(1,1,1);


 // немного повернем сцену
 glPushMatrix();
 glTranslated(-3,-3.5,0);

Проходим от точки (0,0) до (7-dy,8-dx)
for(y=0;y<9*dy;y+=dy)
  for(x=0;x<9*dx;x+=dx)
 {
   // будем соединять каждые четыре точки многоугольником
 glBegin(GL_POLYGON);

  // вячисляем z от координаты x и от времени t
  z = sin(x+t);
  // привязываем координаты текстуры к координатам поверхности
  glTexCoord2d(x/10/dx, y/10/dy);
  glVertex3d(x,y,z);


  // здесь значение z точно такое же,
  // т.к. z не зависит от y, a x у нас не изменился
  glTexCoord2d(x/10/dx, (y+dy)/10/dy);
  glVertex3d(x,y+dy,z);


  z = sin(x+dx+t);
  glTexCoord2d((x+dx)/10/dx, (y+dy)/10/dy);
  glVertex3d(x+dx,y+dy,z);

  glTexCoord2d((x+dx)/10/dx, y/10/dy);
  glVertex3d(x+dx,y,z);
 glEnd();
  }

glPopMatrix();


 t+=0.1;
  auxSwapBuffers();

}
Теперь измените положение камеры в функции resize:
gluLookAt( -2,3,5, 0,0,0, 0,1,0 );
И нам осталось загрузить текстуру. Объявите глобальную переменную
AUX_RGBImageRec* image;
Функцию main отредактируйте следующим образом.
void main()
{
float pos[4] = {3,3,3,1};
float dir[3] = {-1,-1,-1};

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

    auxInitPosition( 50, 10, 400, 400);
    auxInitDisplayMode( AUX_RGB | AUX_DEPTH | AUX_DOUBLE );
    auxInitWindow( "Glaux Template" );
    auxIdleFunc(display);
    auxReshapeFunc(resize);


    glEnable(GL_DEPTH_TEST);

    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    glLightfv(GL_LIGHT0, GL_POSITION, pos);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir);

    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialf(GL_FRONT, GL_SHININESS, 128.0);


	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	image = auxDIBImageLoad("photo.bmp");


    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);



	glTexImage2D(GL_TEXTURE_2D, 0, 3,
		         image->sizeX,
				 image->sizeY,
				 0, GL_RGB, GL_UNSIGNED_BYTE,
				 image->data);



  glEnable(GL_TEXTURE_2D);
auxMainLoop(display); }

Исходный файл смотрите здесь. Исполняемый файл здесь.

PS
В анимированном виде я смотрюсь гораздо лучше. Пивзавод балтика должен мне за рекламу продукта бочку пива поставить. И при том не одну.;-)