OpenGL: вычислить координату пространства глаза из координаты пространства окна в GLSL? - PullRequest
3 голосов
/ 15 апреля 2011

Как мне вычислить координату пространства глаза из координат окна (пиксель в буфере кадра) + значение глубины пикселя в GLSL, пожалуйста (gluUnproject в GLSL, так сказать)?

Ответы [ 5 ]

3 голосов
/ 15 апреля 2011

Выглядит как дубликат GLSL преобразует gl_FragCoord.z ​​в пространство глаза z .

Редактировать (полный ответ):

// input: x_coord, y_coord, samplerDepth
vec2 xy = vec2(x_coord,y_coord); //in [0,1] range
vec4 v_screen = vec4(xy, texture(samplerDepth,xy), 1.0 );
vec4 v_homo = inverse(gl_ProjectionMatrix) * 2.0*(v_screen-vec4(0.5));
vec3 v_eye = v_homo.xyz / v_homo.w; //transfer from homogeneous coordinates
2 голосов
/ 15 апреля 2011

Предполагая, что вы застряли с фиксированной конвейерной моделью, видом и проекцией, вы можете просто реализовать точно формулу, приведенную на справочной странице gluUnProject .

Там нет инверсии матрицывстроенный в GLSL, так что в идеале вы бы так, чтобы на процессоре.Таким образом, вам нужно предоставить форму, обратную вашей составной матрице modelViewProjection.gl_FragCoord находится в координатах окна, поэтому вам также необходимо указать размеры вида.

Таким образом, вы, вероятно, в конечном итоге получите что-то вроде (кодирование внешне):

vec4 unProjectedPosition = invertedModelViewProjection * vec4( 
               2.0 * (gl_FragCoord.x - view[0]) / view[2] - 1.0, 
               2.0 * (gl_FragCoord.y - view[1]) / view[3] - 1.0,
               2.0 * gl_FragCoord.z - 1.0,
               1.0);

Если вы 'Если вы реализовали свой собственный аналог старого стека матриц, то вы, вероятно, отлично инвертируете матрицу.В противном случае, это, возможно, более сложная тема , чем вы ожидали, и вам может быть лучше использовать реализацию MESA с открытым исходным кодом (см. Invert_matrix, третья функция в этом файле), просто потому, что этохорошо проверено, если ничего другого.

0 голосов
/ 22 марта 2017

Я думаю, что все доступные ответы касаются проблемы с какой-либо стороны, а khronos.org имеет страницу Wiki с несколькими различными случаями, перечисленными и объясненными с помощью кода шейдера, поэтому его стоит опубликовать здесь Вычислить пространство глаза из пространства окна .

0 голосов
/ 29 июня 2013

Я только что понял, что нет необходимости делать эти вычисления во фрагментном шейдере.Вы можете сохранить пару операций, выполнив это на ЦП и умножив его на инверсию MVP (при условии, что glDepthRange(0, 1), не стесняйтесь редактировать):

glm::vec4 vp(left, right, width, height);
glm::mat4 viewportMat = glm::translate(
    vec3(-2.0 * vp.x / vp.z - 1.0, -2.0 * vp.y / vp.w - 1.0, -1.0))
  * glm::scale(glm::vec3(2.0 / vp.z, 2.0 / vp.w, 2.0));
glm::mat4 mvpInv = inverse(mvp);
glm::mat4 vmvpInv = mvpInv * viewportMat;
shader->uniform("vmvpInv", vmvpInv);

В шейдере:

vec4 eyePos = vmvpInv * vec4(gl_FragCoord.xyz, 1);
vec3 pos = eyePos.xyz / eyePos.w;
0 голосов
/ 16 апреля 2011

Ну, парень на opengl.org указал, что координаты пространства клипа, которые производит проекция, делятся на clipPos.w для вычисления нормализованных координат устройства. При обращении шагов от фрагмента к ndc к координатам пространства клипа, вам нужно восстановить это w (которое, как оказывается, -z из соответствующей координаты пространства обзора (камеры)), и умножить координату ndc на это значение, чтобы вычислить правильный клип пространственная координата (которую можно превратить в пространственную координату вида, умножив ее на матрицу обратной проекции).

В следующем коде предполагается, что вы обрабатываете буфер кадров в пост-обработке. При обработке во время визуализации геометрии вы можете использовать gl_FragCoord.z ​​вместо texture2D (sceneDepth, ndcPos.xy) .r.

Вот код:

uniform sampler2D sceneDepth;
uniform mat4 projectionInverse;
uniform vec2 clipPlanes; // zNear, zFar
uniform vec2 windowSize; // window width, height

#define ZNEAR clipPlanes.x
#define ZFAR clipPlanes.y

#define A (ZNEAR + ZFAR)
#define B (ZNEAR - ZFAR)
#define C (2.0 * ZNEAR * ZFAR)
#define D (ndcPos.z * B)
#define ZEYE -(C / (A + D))

void main() 
{
vec3 ndcPos;
ndcPos.xy = gl_FragCoord.xy / windowSize;
ndcPos.z = texture2D (sceneDepth, ndcPos.xy).r; // or gl_FragCoord.z
ndcPos -= 0.5;
ndcPos *= 2.0;
vec4 clipPos;
clipPos.w = -ZEYE;
clipPos.xyz = ndcPos * clipPos.w;
vec4 eyePos = projectionInverse * clipPos;
}

По сути, это GLSL-версия gluUnproject.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...