Книги

OpenGL / FPC - Глава 10

А теперь займемся совсем другими вещами. Если вы посмотрите на пример из прошлой главы, то, наверно, заметите, что с перспективой там не все в порядке. Правильно, это из-за того, что мы пользуемся ортогональной проекцией, а не перспективной, о чем я уже упоминал в начале.

Так как больше людей хочет все-таки работать с "перспективой", я расскажу о перспективной проекции. Но для этого потребуется помощь извне. Для расчета перспективы используется модуль GLU. GLU означает "OpenGL Utility Library". Этот модуль помогает при работе с такими неудобоваримыми расчетами как перспектива, кривые линии или поверхности.

uses
  windows,      // Windows API Stuff
  gl,           // OpenGL API Stuff
  glu;          // OpenGL Utility Lib

Теперь можно рассчитывать перспективу посредством одного вызова нашей OpenGL_Init.

  glClearColor( 0.0, 0.0, 0.0, 0.0 );

  glViewport( 0, 0, width, height );
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();

  gluPerspective( 45.0, width/height, 0.1, 100.0);

  glMatrixMode( GL_MODELVIEW );
  glLoadIdentity();

  glClearDepth(1.0);                  // Depth Buffer Setup
  glEnable(GL_DEPTH_TEST);            // Enables Depth Testing
  glDepthFunc(GL_LEQUAL);             // The Type of Depth Test To do

Вместо glOrtho теперь используем gluPerspective. Обратите внимание, что функции, относящиеся к разным модулям, имеют разные префиксы. Так, все функции модуля GLU имеют префикс "glu".

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

Вы находитесь в синей точке, а ваше поле зрения обозначено красной областью. Угол охвата этого поля и есть первый аргумент

Второй аргумент — это aspect нашего окна. Мы уже использовали его для glOrtho, так что здесь проблем быть не должно. Зная этот параметр, OpenGL вычисляет видимую часть оси X. Подумайте об этом — aspect указывает, какое должно быть отношение ширины к высоте, а из значения первого параметра мы можем найти ширину.

Третий аргумент задает параметр для ближнего отсечения. Каждое значение Z, меньшее этого параметра, будет отсекаться. Эта величина может быть только положительной. Задать отрицательное значение для параметра для ближнего отсечения недопустимо.

Четвертый параметр — это параметр для дальнего отсечения. Всякое значение, большее передаваемого параметра, отображаться не будет. Однако надо помнить, что последние два аргумента представлены не в единицах оси Z, а в единицах, относящихся к наблюдателю (вам).

Все параметры приведены на этом наглядном рисунке.

Это не так сложно, просто непривычно. Надо привыкнуть. И обратите внимание, что трансляции и повороты сейчас должны быть немного более искусными, поскольку точка 0/0/0 теперь — это положение наблюдателя.

  glTranslatef(0.0,0.0,-5.0);
  glRotatef( rotation, 1.0, 1.0, 0.0 );                         

     glBegin( GL_TRIANGLES );

	glColor3f(1.0,0.0,0.0);
	 glVertex3f( 0.0, 1.0, 0.0);
	 glVertex3f(-1.0,-1.0, 1.0);
	 glVertex3f( 1.0,-1.0, 1.0);

	glColor3f(0.0,1.0,0.0);
	 glVertex3f( 0.0, 1.0, 0.0);
	 glVertex3f( 1.0,-1.0, 1.0);
	 glVertex3f( 1.0,-1.0, -1.0);

	glColor3f(0.0,0.0,1.0);
	 glVertex3f( 0.0, 1.0, 0.0);
	 glVertex3f( 1.0,-1.0, -1.0);
	 glVertex3f(-1.0,-1.0, -1.0);

	glColor3f(1.0,1.0,0.0);
	 glVertex3f( 0.0, 1.0, 0.0);
	 glVertex3f(-1.0,-1.0,-1.0);
	 glVertex3f(-1.0,-1.0, 1.0);

     glEnd();

     glBegin( GL_QUADS );

	glColor3f(1.0,0.0,1.0);
	 glVertex3f( 1.0,-1.0,-1.0);
	 glVertex3f( 1.0,-1.0, 1.0);
	 glVertex3f(-1.0,-1.0, 1.0);
	 glVertex3f(-1.0,-1.0,-1.0);

     glEnd();

Единственная разница состоит в том, что мы передвинули матрицу на 5 единиц вглубь экрана. Если бы все осталось, как прежде, то пирамида была бы построена вокруг наблюдателя, и он бы оказался внутри нее.

Здесь полный исходный код.

И последнее: если при компиляции возникает glu_sl.pp(36,6) Error: Illegal unit name: GLU, то это значит, что вы пользуетесь заголовочными файлами OpenGL старых версий. Добудьте новые с сайта FreePascal. Если (по каким-то причинам) вам не хочется этого делать, то придется править заголовочные файлы OpenGL. Вначале в каталоге C:\PP\UNITS\WIN32\ следует удалить или переименовать файлы GLU_SL.PPW и GLU_SL.OW. Затем в каталоге C:\PP\SOURCE\PACKAGES\OPENGL\WIN32\ следует отредактировать файл GLU_SL.PP. В строке PROGRAM слово GLU нужно заменить на GLU_SL. После этого скомпилируйте все и скопируйте файлы GLU_SL в C:\PP\UNITS\WIN32\. После этого все должно заработать.

Актуальные версии
FPC3.2.2release
Lazarus3.2release
MSE5.10.0release
fpGUI1.4.1release
links