GLSL: 如何获得像素的x,y,z世界位置?[英] GLSL: How to get pixel x,y,z world position?

本文是小编为大家收集整理的关于GLSL: 如何获得像素的x,y,z世界位置?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我想根据世界上哪个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:添加了我的完整代码

推荐答案

在顶点着色器中,您的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&array&array);为了将矩阵数据获取到数组.其次,以类似的方式获取模型矩阵,还请致电GloLationSidentity();并使用gltranslate(),glrotate(),glscale()等进行对象转换,最后调用glgetFloatV(gl_modelview_matrix,&array);要从OpenGL中获取矩阵数据,因此您可以将其发送到顶点着色器.特别要注意,您需要在开始转换对象之前调用glloadidentity().通常,您首先要转换摄像头,然后转换对象,从而导致一个同时执行视图和模型功能的矩阵.但是,由于您使用的是单独的矩阵,因此需要使用GLOLASIDENTITY()的相机转换后重置矩阵.

gl_fragcoord是像素坐标,而不是世界坐标.

其他推荐答案

,或者您可以将Z坐标除以W坐标,从而基本上没有透视投影;给您原始的世界坐标.

即.

depth = gl_FragCoord.z / gl_FragCoord.w;

当然,这仅适用于非剪辑坐标..

但是谁在乎被剪裁的人?

其他推荐答案

您需要将世界/模型矩阵作为统一传递到顶点着色器,然后将其乘以顶点位置,然后将其作为变化的片段着色器发送:

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

本文地址:https://www.itbaoku.cn/post/2091089.html

问题描述

I want to adjust the colors depending on which xyz position they are in the world.

I tried this in my fragment shader:

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

but it seems that the colors change depending on my camera angle/position, how do i make the coords independent from my camera position/angle?

Heres my vertex shader:

varying vec4 verpos;

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

Edit2: changed title, so i want world coords, not screen coords!

Edit3: added my full code

推荐答案

In vertex shader you have gl_Vertex (or something else if you don't use fixed pipeline) which is the position of a vertex in model coordinates. Multiply the model matrix by gl_Vertex and you'll get the vertex position in world coordinates. Assign this to a varying variable, and then read its value in fragment shader and you'll get the position of the fragment in world coordinates.

Now the problem in this is that you don't necessarily have any model matrix if you use the default modelview matrix of OpenGL, which is a combination of both model and view matrices. I usually solve this problem by having two separate matrices instead of just one modelview matrix:

  1. model matrix (maps model coordinates to world coordinates), and
  2. view matrix (maps world coordinates to camera coordinates).

So just pass two different matrices to your vertex shader separately. You can do this by defining

uniform mat4 view_matrix;
uniform mat4 model_matrix;

In the beginning of your vertex shader. And then instead of ftransform(), say:

gl_Position = gl_ProjectionMatrix * view_matrix * model_matrix * gl_Vertex;

In the main program you must write values to both of these new matrices. First, to get the view matrix, do the camera transformations with glLoadIdentity(), glTranslate(), glRotate() or gluLookAt() or what ever you prefer as you would normally do, but then call glGetFloatv(GL_MODELVIEW_MATRIX, &array); in order to get the matrix data to an array. And secondly, in a similar way, to get the model matrix, also call glLoadIdentity(); and do the object transformations with glTranslate(), glRotate(), glScale() etc. and finally call glGetFloatv(GL_MODELVIEW_MATRIX, &array); to get the matrix data out of OpenGL, so you can send it to your vertex shader. Especially note that you need to call glLoadIdentity() before beginning to transform the object. Normally you would first transform the camera and then transform the object which would result in one matrix that does both the view and model functions. But because you're using separate matrices you need to reset the matrix after camera transformations with glLoadIdentity().

gl_FragCoord are the pixel coordinates and not world coordinates.

其他推荐答案

Or you could just divide the z coordinate by the w coordinate, which essentially un-does the perspective projection; giving you your original world coordinates.

ie.

depth = gl_FragCoord.z / gl_FragCoord.w;

Of course, this will only work for non-clipped coordinates..

But who cares about clipped ones anyway?

其他推荐答案

You need to pass the World/Model matrix as a uniform to the vertex shader, and then multiply it by the vertex position and send it as a varying to the fragment shader:

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