Я хотел бы рассчитать 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 (дальняя плоскость).
Что я делаю не так в своих расчетах?
Ваша последняя строка кода избыточна. Расчет глубины выполняется во время преобразования проекции (и последующего разделения перспективы). По сути что 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 приведенные выше значения будут отличаться от того, что хранится в буфере глубины.
Вы применили формулу в той статье Википедии к неправильным значениям. Вы уже применили матрицу проекции с помощью glm :: project, что z' = ...
формула делает. Таким образом, вы в основном применяете матрицу проекции дважды в своем коде.
Значения буфера глубины в OpenGL находятся в координатах окна, и они находятся в диапазоне [n, f], где n и f задаются с помощью glDepthRange(n, f)
(по умолчанию 0 и 1). Вы можете прочитать это в 13.6.1 в спецификации. Эти значения не имеют ничего общего со значениями zNear и zFar, используемыми в матрице проекции.
glm::project
просто принимает эти значения по умолчанию, и, поскольку он выводит координаты окна, это значение записывается в буфер глубины. Итак, правильный код просто:
float zBufferValue = screenCoords.z;