如何获得准确的片段屏幕位置,如顶点着色器中的gl_FragCoord?

时间:2014-11-17 04:55:04

标签: opengl unity3d glsl shader vertex-shader

我使用投影的gl_Position和屏幕参数进行了一些计算,但是在靠近相机的多边形中位置看起来是扭曲的。但是当我使用...时

vec2 fragmentScreenCoordinates = vec2(gl_FragCoord.x / _ScreenParams.x, gl_FragCoord.y / _ScreenParams.y);

......我得到了相当准确的xy结果。

漂亮的输出gl_FragCoord.xy坐标: enter image description here

从投影顶点计算会在整个面上产生插值,我不能用它来对屏幕对齐纹理进行采样。

gl_Position的丑陋插值输出: enter image description here

有没有办法在顶点着色器中生成这个gl_FragCoord类似的值?我真的想在顶点着色器中计算纹理坐标,以进行独立纹理读取,手动深度测试等。

或者我在这里可以使用哪些Unity内置值?

1 个答案:

答案 0 :(得分:7)

在顶点着色器中,设置

gl_Position = ...

在透视划分为标准化设备坐标之前,它必须位于剪辑空间中。这是因为OpenGL在4D空间中做了很多东西,并且是插值所必需的。

由于你只想在每个顶点的值而没有内插,你可以立即标准化(或者甚至可以leave out if using an orthographic projection)......

vec3 ndc = gl_Position.xyz / gl_Position.w; //perspective divide/normalize
vec2 viewportCoord = ndc.xy * 0.5 + 0.5; //ndc is -1 to 1 in GL. scale for 0 to 1
vec2 viewportPixelCoord = viewportCoord * viewportSize;

此处, viewportCoord 相当于您的fragmentScreenCoordinates,假设视口覆盖了窗口。

注意:正如@derhass指出的那样,如果几何与w = 0平面相交,则会失败。即可见三角形的顶点位于相机后面。

[修改]
评论讨论使用1到1像素最近邻居查找的坐标。正如@ AndonM.Coleman所说,改变坐标将起作用,但使用最近邻过滤更容易,更快捷。您还可以使用texelFetch,它完全绕过过滤:

  1. 抓住坐标:

    vec2 sampleCoord = (floor(viewportPixelCoord) + 0.5) / textureSize(mySampler);
    vec4 colour = texture(mySampler, sampleCoord);
    
  2. 最近邻过滤(不确定这在unity3d中是什么):

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //magnification is the important one here
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
  3. 使用texelFetch

    vec4 colour = texelFetch(mySampler, ivec2(viewportPixelCoord), 0);