OpenGL: Как определить, перекрывается ли 3D (визуализированная) точка другими 3D (визуализированными) примитивами перед ней?

В моей программе OpenGL я последовательно делаю следующее:

// Drawing filled polyhedrons
// Drawing points using GL_POINTS
// Displaying information for each above point beside it

Для отображения информации о точке (скажем, идентификатора / номера точки) я конвертирую трехмерные координаты точки в координаты 2D-окна, используя gluProject(). Я пишу идентификатор точки в этом месте 2D-окна, используя glRasterPos() и код рендеринга 2D-символов.

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

Как определить, перекрывается ли 3D (визуализированная) точка другими 3D (визуализированными) примитивами перед ней? Или есть лучший способ отображать информацию о точках рядом с ней, только когда она не закрыта?

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

4 ответа

Решение

Если вы не желаете использовать второй проход запроса окклюзии, попробуйте сэмплировать Z-буфер для сравнения с вашей контрольной точкой.

Поскольку вы добавляете текст рядом с точкой, возьмите нормализованное значение буфера Z (скажем, с помощью gluProject) точки, а затем сравните это значение с выбранным значением Z-буфера (используя glReadPixels) в этой точке. Если ваша точка находится позади (больше) значения глубины, которое вы выбрали, ваша точка должна быть закрыта, и вы можете не рисовать текст.

Это, конечно, требует, чтобы вы отрисовывали всю свою геометрию перед текстом, но это не должно быть проблемой.

Образец кода:

// Assumed to already hold 3D coordinates of point
GLdouble point3DX, point3DY, point3DZ;

// Project 3D point coordinates to 2D
GLdouble point2DX, point2DY, point2DZ;  // 2D coordinates of point
gluProject( point3DX, point3DY, point3DZ,
            mMatrix, pMatrix, vMatrix,      // MVP matrices
            &point2DX, &point2DY, &point2DZ);

// Read depth buffer at 2D coordinates obtained from above
GLfloat bufDepth = 0.0;
glReadPixels(   static_cast<GLint>( point2DX ), static_cast<GLint>( point2DY ),     // Cast 2D coordinates to GLint
                1, 1,                                                               // Reading one pixel
                GL_DEPTH_COMPONENT, GL_FLOAT,
                &bufDepth);

// Compare depth from buffer to 2D coordinate "depth"
GLdouble EPSILON = 0.0001;  // Define your own epsilon
if (fabs(bufDepth - point2DZ) < EPSILON)
    // 3D point is not occluded
else
    // 3D point is occluded by something

Чтение из z-буфера может быть очень и очень медленным на современном оборудовании. Вот почему был изобретен окклюзионный запрос. Посмотрите расширение ARB-окклюзионного запроса. У него есть пара кадров задержки, прежде чем вы сможете получить результаты, но это не повлияет на вашу производительность.

Если окклюзионный запрос по какой-либо причине не сработает, следующий запасной вариант - выполнить программную операцию ray-intersect-world с использованием BSP-дерева (которое вообще не использует GL).

В дополнение к ответу Алана вы можете математически проверить окклюзию, проецируя луч из положения вашей камеры в вашу точку и определяя, пересекает ли он какую-либо из ваших геометрий. В Интернете имеется множество ссылок для тестирования пересечения луч-объект (см., Например, страницу пересечения объект / объект). Если у вас много геометрии, вы можете ускорить процесс, используя ограничивающие объемы или дерево BSP.

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

Ответ от Эшвина Нанджаппы был очень полезным. Я не эксперт по OpenGL, поэтому мне потребовалось некоторое время, чтобы выяснить, как получить матрицы MVP. Я делюсь кодом здесь, чтобы дополнить его пост:

    GLint viewport[4];
    GLdouble modelview[16];
    GLdouble projection[16];
    glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
    glGetDoublev( GL_PROJECTION_MATRIX, projection );
    glGetIntegerv( GL_VIEWPORT, viewport );
Другие вопросы по тегам