Книги

OpenGL / FPC - Глава 8

На этот раз займемся функциями глубины. Чтобы объяснить, что они делают, рассмотрим пример.

Пусть мы рисуем два треугольника один поверх другого, а затем вращаем матрицу. Как правило, ожидается, что два треугольника будут поворачиваться вокруг оси. Что ж, посмотрим, что происходит в реальности.

  glClear( GL_COLOR_BUFFER_BIT );
  glLoadIdentity();
  glRotatef( rotation, 0.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, 0.0);
    glVertex3f(1.0, -1.0, 0.0);
    glColor3f(0.0, 1.0, 0.0);  
    glVertex3f(0.0, 1.0, 1.0);
    glVertex3f(-1.0, -1.0, 1.0);
    glVertex3f(1.0, -1.0, 1.0);
  glEnd();

Скачайте пример, скомпилируйте и запустите. Посмотрите внимательно. Что-то не так: зеленый треугольник всегда располагается поверх красного, даже когда он должен быть позади его. Странно, правда?

То, что один примитив располагается позади другого, еще не означает, что OpenGL прорисует их в правильном расположении. Фактически OpenGL рисует все фигуры от конца к началу. Первая фигура, что была нарисована, находится позади следующей, и так далее. Поскольку мы всегда рисуем красный треугольник перед зеленым, он всегда закрывается последним.

Имеется несколько возможностей сделать рисунок "правильным". Первая состоит в сортировке фигур таким способом, чтобы наиболее далекий примитив рисовался вначале. Другой состоит в использовании функций глубины, которые сделают эту работы за вас. Каждому пикселю присваивается значение глубины. При рисовании новой поверхности, это значение используется для проверки, располагается ли фигура позади других.

Для активирования функций глубины, достаточно просто вызвать glEnable(). Конечно, следует дать дополнительную информацию о том, как должен работать буфер глубины, и проч. Вот новые строки для процедуры OpenGL_Init.

  glClearDepth( 1.0);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

Первая строка определяет значение, присваиваемое при очистке буфера глубины. Она похожа на команду glClearColor(), но используется для буфера глубины. Проверка глубины активируется путем вызова glEnable(GL_DEPTH_TEST);.

В качестве функции глубины используется glDepthFunc(GL_LEQUAL); GL_LEQUAL означает "меньше или равно", то есть рисуется все, что имеет глубину, меньшую или равную текущей. Значение для буфера глубины рассчитывается как значение 1/Z. То есть Z-значение от 2 меньше, чем Z-значение у 1, поскольку 1/1 > 1/2. Для GL_LEQUAL Z-значение от 2 будет рисоваться впереди фигуры с Z = 1.

Теперь вы должны понимать смысл аргумента glClearDepth(). Разрешенный диапазон — от 0.0 до 1.0. Если значение равно 1.0, и мы работаем с GL_LEQUAL, каждое новое значение меньше или равно единицы. Если значение при очистке равно 0.0 и используется LEQUAL, ничего нового не будет нарисовано, так как нельзя получить значение, меньшее, чем 0.0. В этом случае следует использовать GL_GREATER, но это приведет к тому, что близкие объекты будут закрываться далекими.

Мдя, это было непросто — особенно не на родном-то языке. Надеюсь, что суть понятна. Если нет, то скажу проще: вызвав glClearDepth(1.0) и glDepthFunc(GL_LEQUAL); все будет работать так, как мы "привыкли видеть".

Да, вот еще одна штука. Мы задаем значение для очистки, однако следует сказать OpenGL, что следует произвести реальную очистку. Очистка дополняется командой glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); и все заработает. Здесь — полный исходник. Как можно увидеть, теперь треугольники рисуются в правильном порядке.

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