按像素值偏移 gl_Position 或 gl_Vertex

Raz*_*a O 3 opengl shader pixel vertex

我的属性包含像素值。我想用这个属性值来偏移我的 gl_vertex 。

问题是我的 gl_vertex 以世界单位为单位,而 offset\attribute 以像素为单位。

如果我将屏幕尺寸作为统一发送,然后将像素转换为 -1 到 1 值,并将其添加到最终的 gl_Position 中,我就可以做到这一点。但我现在不想管理屏幕尺寸事件并在每次绘制、我拥有的每个着色器时发送它。

有没有办法通过一些矩阵游戏或它们的逆矩阵来做到这一点?

为了方便起见,我想将 gl_Position 设置为像素 50,50。

vec4 myPixelValue = vec4(50,50,1,1);
gl_Position = <Something> * myPixelValue;
Run Code Online (Sandbox Code Playgroud)

- - 添加 - -

在我了解到如果不向着色器发送窗口大小就不可能做到这一点后,我决定发送该大小。我创建了以下顶点着色器代码

attribute vec2 spriteOffset;

uniform vec2 screenSize;

void main() 
{    
    vec2 screenConvert = vec2(2.0 / screenSize.x, -2.0 / screenSize.y);
    vec2 convertedPix = spriteOffset * screenConvert;

    gl_Position = (gl_ModelViewProjectionMatrix * gl_Vertex) + vec4(convertedPix, 0.0, 0.0);
}
Run Code Online (Sandbox Code Playgroud)

此代码仅适用于 2D(正交投影)。但不是 3D。我现在遇到了问题。我知道我还需要考虑 Z 值,但不知道如何。

任何人 ?

der*_*ass 5

来自 keltars 的评论:

尝试在标准化设备坐标而不是剪辑空间中进行计算。例如

vec4 clip = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_Position = vec4(clip.xyz / clip.w + vec3(convertexPix, 0.0), 1.0);
Run Code Online (Sandbox Code Playgroud)

您已经在另一条评论中说过它“完美运行”。我认为 keltar 的一般方法在这里是绝对正确的,但是这个实现有一些问题,并且不会正常工作,至少在一般情况下不会。

问题是,这会在着色器中手动进行透视划分,但裁剪(在着色器之后完成)必须在划分之前完成。如果您的图元与近平面相交,或者物体位于相机后面(现在甚至可能出现在您的面前),这尤其会给您带来错误的结果。

这也将破坏透视校正插值。

因此,最好修改方法以保持原始 w 不变,并使用类似以下内容的方法:

vec4 clip = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_Position = vec4(clip.xyz + vec3(clip.w * convertexPix, 0.0), clip.w);
Run Code Online (Sandbox Code Playgroud)