Вычисление z-буфера из вывода glm :: project

Я хотел бы рассчитать z-буфер позиции объекта из вывода glm :: project. Расчет z-буфера в приведенном ниже коде https://en.wikipedia.org/wiki/Z-buffering.

Что я пробовал

int windowWidth = 800;
int windowHeight = 600;
float positions[] = {-42.5806f, 27.8838f, 49.9729f} // Example point
glm::mat4 model;
glm::mat4 view;
glm::mat4 proj;

view = glm::lookAt(
glm::vec3( 0.0f, 0.0f, 2.0f ),
glm::vec3( 0.0f, 0.0f, 0.0f ),
glm::vec3( 0.0f, 1.0f, 0.0f )
);

proj = glm::perspective( 45.0f, aspect, 0.1f, 10.0f );

// Get screen coordinates from an object point
glm::vec3 screenCoords = glm::project(
glm::vec3( positions[0], positions[1] , positions[2] ),
view*model,
proj,
glm::vec4( 0, 0, windowWidth, windowHeight )
);

// Calculating the z-buffer
int zFar = 10;
int zNear = 0.1;
float zBufferValue = (zFar+zNear ) / ( zFar-zNear ) + ( 1/screenCoords.z) * ( ( -2*zFar*zNear ) / ( zFar - zNear ) );

Эта проблема

Значение zBufferValue равно 1 независимо от того, как я поворачиваю свою модель или какую точку я использую. Согласно вики-странице значение должно быть между -1 (ближняя плоскость) и 1 (дальняя плоскость).

Что я делаю не так в своих расчетах?

0

Решение

Ваша последняя строка кода избыточна. Расчет глубины выполняется во время преобразования проекции (и последующего разделения перспективы). По сути что glm::project делает это:

// P:  projection matrix
// MV: modelview matrix
// v:  vertex to convert to screen space

vec4 result = P * MV * vec4(v, 1.0f);
result /= result.w;     // perspective divide

// convert X/Y/Z from normalized device coords to screen coords...
result.z = (result.z + 1.0f) * 0.5f;
// ...

return vec3(result);

Он также преобразует координаты X / Y из нормализованного пространства устройства [(-1, -1), (1, 1)] экранировать пространство [(0, 0), (viewport_width, viewport_height)] но поскольку вас интересует только буфер глубины, я оставил этот шаг выше.

Игнорируя последние 3 строки вашего кода, screenCoords.z должен содержать значение буфера глубины, эквивалентное тому, что вы получите от glReadPixels.

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

2

Другие решения

Вы применили формулу в той статье Википедии к неправильным значениям. Вы уже применили матрицу проекции с помощью glm :: project, что z' = ... формула делает. Таким образом, вы в основном применяете матрицу проекции дважды в своем коде.

Значения буфера глубины в OpenGL находятся в координатах окна, и они находятся в диапазоне [n, f], где n и f задаются с помощью glDepthRange(n, f) (по умолчанию 0 и 1). Вы можете прочитать это в 13.6.1 в спецификации. Эти значения не имеют ничего общего со значениями zNear и zFar, используемыми в матрице проекции.

glm::project просто принимает эти значения по умолчанию, и, поскольку он выводит координаты окна, это значение записывается в буфер глубины. Итак, правильный код просто:

float zBufferValue = screenCoords.z;
1

По вопросам рекламы [email protected]