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

Ger*_*eri 1 opengl shader glsl unity-game-engine vertex-shader

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

vec2 fragmentScreenCoordinates = vec2(gl_FragCoord.x / _ScreenParams.x, gl_FragCoord.y / _ScreenParams.y);
Run Code Online (Sandbox Code Playgroud)

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

漂亮的输出gl_FragCoord.xy坐标: 在此输入图像描述

从投影顶点计算会导致整个面上的插值,我无法用于采样屏幕对齐纹理.

来自gl_Position的丑陋插值输出: 在此输入图像描述

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

或者有没有我可以在这里使用的Unity内置值?

joz*_*yqk 8

在顶点着色器中,设置

gl_Position = ...
Run Code Online (Sandbox Code Playgroud)

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

因为你只想值每一个顶点并没有什么插值,可以正常化的时候了(甚至可以离开了,如果使用正投影)...

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;
Run Code Online (Sandbox Code Playgroud)

假设视口覆盖窗口,viewportCoord这相当于您fragmentScreenCoordinates的.

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

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

  1. 捕捉坐标:

    vec2 sampleCoord = (floor(viewportPixelCoord) + 0.5) / textureSize(mySampler);
    vec4 colour = texture(mySampler, sampleCoord);
    
    Run Code Online (Sandbox Code Playgroud)
  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);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 用途texelFetch:

    vec4 colour = texelFetch(mySampler, ivec2(viewportPixelCoord), 0);
    
    Run Code Online (Sandbox Code Playgroud)