【问题标题】:GLSL: How to get pixel x,y,z world position?GLSL:如何获得像素 x、y、z 世界位置?
【发布时间】:2011-06-21 10:28:58
【问题描述】:

我想根据它们在世界中的 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_ModelViewMatrix。

标签: opengl glsl fragment-shader


【解决方案1】:

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

现在的问题是,如果您使用 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 是像素坐标而不是世界坐标。

【讨论】:

  • 我无法让它工作,当我改变我的相机位置/旋转时它仍然会改变颜色。在编辑中查看我当前的代码。
  • @Rookie,对不起,我编辑了我的答案几次。您是否阅读并理解了这个最新版本?
  • “所以只需将两个不同的矩阵传递给您的顶点着色器”如何?对不起,我在 GLSL / 矩阵中很菜鸟......我不知道渲染在 opengl 内部是如何工作的。
  • 我不通过 glrotatef() 旋转我的对象(也不是缩放等)是 model_matrix 那么需要吗?该死的..我认为这将是一个简单的函数调用..但看起来我必须重写我的整个渲染代码......
  • 当我设置好数组后,我在片段着色器中调用什么来获取 xyz?
【解决方案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 规范,因为需要深入了解转换。

    【讨论】:

      猜你喜欢
      • 2018-10-24
      • 2019-02-16
      • 1970-01-01
      • 1970-01-01
      • 2016-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多