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 );