GLSL:如何获得像素x,y,z世界位置?

时间:2011-02-04 15:13:50

标签: opengl glsl fragment-shader

我想根据它们在世界上的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;
}

编辑2:更改了标题,所以我想要世界坐标,而不是屏幕坐标!

编辑3:添加了我的完整代码

4 个答案:

答案 0 :(得分:30)

在顶点着色器中,你有gl_Vertex(或者你不使用固定管道的其他东西),它是模型坐标中顶点的位置。通过gl_Vertex乘以模型矩阵,您将获得世界坐标中的顶点位置。将其分配给变化的变量,然后在片段着色器中读取其值,您将获得片段在世界坐标中的位置。

现在问题在于,如果使用OpenGL的默认模型视图矩阵,它不一定有任何模型矩阵,OpenGL是模型矩阵和视图矩阵的组合。我通常通过使用两个单独的矩阵而不是一个模型视图矩阵来解决这个问题:

  1. 模型矩阵(将模型坐标映射到世界坐标)和
  2. 视图矩阵(将世界坐标映射到摄像机坐标)。
  3. 所以只需将两个不同的矩阵分别传递给顶点着色器。您可以通过定义

    来完成此操作
    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是像素坐标而不是世界坐标。

答案 1 :(得分:11)

或者你可以将z坐标除以w坐标,这实际上与透视投影无关;给你原始的世界坐标。

depth = gl_FragCoord.z / gl_FragCoord.w;

当然,这只适用于非剪裁坐标..

但是谁又关心被剪掉的呢?

答案 2 :(得分:2)

您需要将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;
}

答案 3 :(得分:-1)

最简单的方法是通过变量变量从顶点着色器向下传递世界位置。

但是,如果你真的必须从gl_FragCoord重建它,唯一的方法是反转导致gl_FragCoord坐标的所有步骤。如果你真的必须这样做,请参考OpenGL规范,因为必须深入理解转换。