相当于glsl顶点着色器中的gl_FragCoord

时间:2014-05-28 11:11:15

标签: position screen glsl shader vertex

我试图在顶点着色器内获取顶点的屏幕位置, 我在这里看到了其他一些帖子,但我无法找到对我有用的答案。 这就是我在顶点着色器中得到的结果:

#version 400
layout (location = 0) in vec3 inPosition;
uniform mat4 MVP; // modelViewProjection
uniform vec2 window;

void main()
{
    // vertex in screen space
    vec2 fake_frag_coord = (MVP * vec4(inPosition,1.0)).xy;
    float X = (fake_frag_coord.x*window.x/2.0) + window.x;
    float Y = (fake_frag_coord.y*window.y/2.0) + window.y;
}

它工作得不好而且我知道奇怪的是在顶点着色器中做一个奇怪的想法,但是我想把我的顶点偏移乘以2d纹理,所以我需要找到像素的顶点最重要的是能够将它乘以纹理的像素。

谢谢! 路易斯

3 个答案:

答案 0 :(得分:1)

我已使用正确的术语更正了顶点着色器,并向您展示了GL计算gl_FragCoord(窗口空间)时实际发生的转换的确切顺序。

#version 400
layout (location = 0) in vec4 inPosition; // Always use vec4, it makes life easier!
uniform mat4 MVP; // modelViewProjection
uniform vec2 window;

void main()
{
    // Vertex in clip-space
    vec4 fake_frag_coord  = (MVP * inPosition);     // Range:   [-w,w]^4

    // Vertex in NDC-space
    fake_frag_coord.xyz /= fake_frag_coord.w;       // Rescale: [-1,1]^3
    fake_frag_coord.w    = 1.0 / fake_frag_coord.w; // Invert W

    // Vertex in window-space
    fake_frag_coord.xyz *= vec3 (0.5) + vec3 (0.5); // Rescale: [0,1]^3
    fake_frag_coord.xy  *= window;                  // Scale and Bias for Viewport

    // Assume depth range: [0,1] --> No need to adjust fake_frag_coord.z

    [...]
}

纹理坐标和窗口空间坐标是非常不同的东西。通常,您需要传统纹理提取的标准化坐标,这意味着您需要范围为[0,1]的坐标。

幸运的是,窗口空间和纹理空间共享相同的原点约定(0,0)=左下角,因此您可以剪切下面的线以获得适当的纹理坐标:

    fake_frag_coord.xy  *= window;                  // Scale and Bias for Viewport

答案 1 :(得分:1)

我认为Andon M. Coleman的答案很好。但是,我想用问题中讨论的方法指出一个更普遍的问题:在所有中,顶点可能没有有意义的屏幕空间位置。

顶点可能位于视锥体之外。如果您绘制的顶点保证位于平截头体中,或者您只绘制点,则这不会成为问题。

但如果你有一个与近平面相交的基元,它将会失败。您可能会认为在这种情况下,您只是在NDC空间中得到一些在[-1,1]之外的坐标,如果您只是使用它们为顶点指定一些输出值,那么剪切状态将使其正确。但这种假设是错误的。即使对于平截头体外的顶点,你可能会在NDC空间中的[-1,1]中得到完美的值,并且它看起来好像顶点位于相机的中以用于所有顶点实际上,他们躺在相机背后。并且没有后续裁剪阶段能够解决这个问题。

实现此权利的唯一方法是在执行除w之前实际执行剪切操作。这是你不想在顶点着色器中做的事情。

答案 2 :(得分:0)

如果你想让这个工作在js的一部分,这就是我改编Andon M. Coleman's回复的方式:

var winW = window.innerWidth;
var winH = window.innerHeight;

camera.updateProjectionMatrix();
// Not sure about the order of these! I was using orthographic camera so it didn't matter but double check the order if it doesn't work!
var MVP = camera.projectionMatrix.multiply(camera.matrixWorldInverse);

// position to vertex clip-space
var fake_frag_coord = position.applyMatrix4(MVP);                       // Range:   [-w,w]^4

// vertex to NDC-space
fake_frag_coord.x = fake_frag_coord.x / fake_frag_coord.w;  // Rescale: [-1,1]^3
fake_frag_coord.y = fake_frag_coord.y / fake_frag_coord.w;  // Rescale: [-1,1]^3
fake_frag_coord.z = fake_frag_coord.z / fake_frag_coord.w;  // Rescale: [-1,1]^3
fake_frag_coord.w = 1.0 / fake_frag_coord.w;                                // Invert W

// Vertex in window-space
fake_frag_coord.x = fake_frag_coord.x * 0.5;
fake_frag_coord.y = fake_frag_coord.y * 0.5;
fake_frag_coord.z = fake_frag_coord.z * 0.5;

fake_frag_coord.x = fake_frag_coord.x + 0.5;
fake_frag_coord.y = fake_frag_coord.y + 0.5;
fake_frag_coord.z = fake_frag_coord.z + 0.5;

// Scale and Bias for Viewport (We want the window coordinates, so no need for this)
fake_frag_coord.x = fake_frag_coord.x / winW;
fake_frag_coord.y = fake_frag_coord.y / winH;