GLSL: Как получить мировое положение пикселей x, y, z? - PullRequest
24 голосов
/ 04 февраля 2011

Я хочу настроить цвета в зависимости от положения xyz в мире.

Я попробовал это в своем фрагментном шейдере:

varying vec4 verpos;

void main(){
    vec4 c;
    c.x = verpos.x;
    c.y = verpos.y;
    c.z = verpos.z;
    c.w = 1.0;

    gl_FragColor = c;
}

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

Вот мой вершинный шейдер:

varying vec4 verpos;

void main(){
    gl_Position = ftransform();
    verpos = gl_ModelViewMatrix*gl_Vertex;
}

Edit2: изменен заголовок, поэтому я хочу мировые координаты, а не экранные!

Edit3: добавил мой полный код

Ответы [ 4 ]

30 голосов
/ 04 февраля 2011

В вершинном шейдере у вас есть gl_Vertex (или что-то еще, если вы не используете фиксированный конвейер), который является положением вершины в координатах модели.Умножьте матрицу модели на gl_Vertex, и вы получите положение вершины в мировых координатах.Присвойте это переменной варьирующейся , а затем прочитайте ее значение в фрагментном шейдере, и вы получите положение фрагмента в мировых координатах.

Теперь проблема в том, что вы надеваетене обязательно иметь какую-либо матрицу модели, если вы используете матрицу представления модели по умолчанию OpenGL, которая является комбинацией как модели, так и матрицы представления.Обычно я решаю эту проблему, имея две отдельные матрицы вместо одной матрицы вида модели:

  1. матрица модели (сопоставляет координаты модели с мировыми координатами) и
  2. матрица вида (сопоставляет мировые координаты).к координатам камеры).

Так что просто передайте две разные матрицы в ваш вершинный шейдер отдельно.Вы можете сделать это, определив

uniform mat4 view_matrix;
uniform mat4 model_matrix;

в начале вашего вершинного шейдера.И тогда вместо ftransform () произнесите:

gl_Position = gl_ProjectionMatrix * view_matrix * model_matrix * gl_Vertex;

В основной программе вы должны записать значения в обе эти новые матрицы.Во-первых, чтобы получить матрицу вида, выполните преобразования камеры с помощью glLoadIdentity (), glTranslate (), glRotate () или gluLookAt () или того, что вы предпочитаете, как обычно, но затем вызовите glGetFloatv (GL_MODELVIEW_MATRIX, & array);для того, чтобы получить данные матрицы в массив.И во-вторых, аналогичным образом, чтобы получить матрицу модели, также вызовите glLoadIdentity ();и выполнить преобразования объектов с помощью glTranslate (), glRotate (), glScale () и т. д. и, наконец, вызвать glGetFloatv (GL_MODELVIEW_MATRIX, & array);чтобы получить данные матрицы из OpenGL, чтобы вы могли отправить их в ваш вершинный шейдер.Особенно обратите внимание, что вам нужно вызвать glLoadIdentity () перед началом преобразования объекта.Обычно вы сначала преобразуете камеру, а затем преобразуете объект, в результате чего получится одна матрица, которая выполняет функции вида и модели.Но поскольку вы используете отдельные матрицы, вам необходимо сбросить матрицу после преобразований камеры с помощью glLoadIdentity ().

gl_FragCoord - это координаты пикселей, а не мировые координаты.

11 голосов
/ 17 февраля 2012

Или вы можете просто разделить координату z на координату w, что, по сути, отменяет перспективную проекцию; давая вам ваши исходные мировые координаты.

т.

depth = gl_FragCoord.z / gl_FragCoord.w;

Конечно, это будет работать только для не обрезанных координат.

Но кого это все равно волнует?

2 голосов
/ 28 июля 2017

Вам необходимо передать матрицу мира / модели как форму в вершинный шейдер, а затем умножить ее на положение вершины и отправить ее как переменную фрагментному шейдеру:

/*Vertex Shader*/

layout (location = 0) in vec3 Position

uniform mat4 World;
uniform mat4 WVP;

//World FragPos
out vec4 FragPos;

void main()
{
 FragPos = World * vec4(Position, 1.0);
 gl_Position = WVP * vec4(Position, 1.0);
}

/*Fragment Shader*/

layout (location = 0) out vec4 Color;

... 

in vec4 FragPos

void main()
{
 Color = FragPos;
}
0 голосов
/ 04 февраля 2011

Самый простой способ - передать мировое положение из вершинного шейдера через переменную.

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

...