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

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

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

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

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

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

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


person Ashwin Nanjappa    schedule 21.08.2009    source источник
comment
Что еще вы пробовали, кроме 2-го прохода?   -  person Kyle Walsh    schedule 21.08.2009
comment
Кайл: Я не думал ни о чем, кроме метода множественных проходов.   -  person Ashwin Nanjappa    schedule 25.08.2009


Ответы (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
person Ron Warholic    schedule 21.08.2009
comment
Спасибо Сид Фаркус (22780)! Это сработало. Я дополнил ваш ответ некоторым примером кода. - person Ashwin Nanjappa; 25.08.2009

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

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

person Alan    schedule 23.08.2009
comment
Спасибо за указание на расширение запроса окклюзии. Я не могу позволить себе отставание в несколько рендеров, мне нужен правильный ответ с первого рендера, так что это мне не подходит. - person Ashwin Nanjappa; 25.08.2009
comment
Не могли бы вы отложить рендеринг текстовых панелей до тех пор, пока не будет получен ответ на запрос окклюзии? - person Alan; 26.08.2009
comment
Запрос окклюзии не должен отставать, и, по моему опыту, обычно этого не происходит. Вы можете вызвать glFlush() перед получением результатов запроса окклюзии, как я это делаю в одном случае приложения, и он работает нормально и не влияет на частоту кадров моего приложения (3D-игры). - person Razzupaltuff; 08.09.2009

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

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

person Incredulous Monk    schedule 25.08.2009
comment
Спасибо за предложение этого решения. Это слишком много для моего случая, когда мне просто нужно отобразить информацию о точке. Но это должно быть полезно для тех, кто проводит серьезное тестирование окклюзии. - person Ashwin Nanjappa; 25.08.2009

Ответ от Ашвина Нанджаппы был очень полезным. Я не эксперт 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 );
person GreenBubble    schedule 10.05.2018