Подтвердить что ты не робот

GLSL: Как получить позицию x, y, z в пикселях?

Я хочу настроить цвета в зависимости от того, какое положение 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: добавлен мой полный код

4b9b3361

Ответ 1

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

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

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

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

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(), прежде чем начать преобразовывать объект. Обычно вы сначала должны преобразовывать камеру, а затем преобразовывать объект, который приведет к одной матрице, которая выполняет как функцию представления, так и модели. Но поскольку вы используете отдельные матрицы, вам нужно reset матрицу после преобразований камеры с помощью glLoadIdentity().

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

Ответ 2

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

т.

depth = gl_FragCoord.z / gl_FragCoord.w;

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

Но кто вообще заботится об обрезанных?

Ответ 3

Вам нужно передать матрицу World/Model в виде униформы вершинному шейдеру, а затем умножить ее на позицию вершины и отправить ее как изменяющуюся в шейдер фрагмента:

/*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;
}

Ответ 4

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

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