如何在 Metal 中的片段着色器中获取片段坐标



这个最小的 Metal 着色器对根据顶点的颜色属性在屏幕上渲染一个简单的插值渐变(当提供顶点四边形/三角形时):

#include <metal_stdlib>
using namespace metal;
typedef struct {
    float4 position [[position]];
    float4  color;
} vertex_t;
vertex vertex_t vertex_function(const device vertex_t *vertices [[buffer(0)]], uint vid [[vertex_id]]) {
    return vertices[vid];
}
fragment half4 fragment_function(vertex_t interpolated [[stage_in]]) {
    return half4(interpolated.color);
}

。具有以下顶点:

{
  // x,    y,   z,   w,   r,   g,   b,   a    
     1.0, -1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0,
    -1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
    -1.0,  1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,
     1.0,  1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0,
     1.0, -1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0,
    -1.0,  1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0
}

目前为止,一切都好。它呈现众所周知的梯度三角形/四边形。
您几乎在每个GPU HelloWorld教程中找到的那个。


但是,我需要有一个片段着色器,而不是采用插值顶点颜色,而是根据屏幕上的片段位置计算颜色。它接收一个屏幕填充顶点的四边形,然后仅使用片段着色器来计算实际颜色。

据我了解,顶点的位置是一个float4,前三个元素是 3d 向量,第 4 个元素设置为 1.0

所以——我想——修改上面的内容应该很容易,让它简单地将顶点的位置重新解释为片段着色器中的颜色,对吧?

#include <metal_stdlib>
using namespace metal;
typedef struct {
    float4 position [[position]];
} vertex_t;
vertex vertex_t vertex_function(const device vertex_t *vertices [[buffer(0)]], uint vid [[vertex_id]]) {
    return vertices[vid];
}
fragment half4 fragment_function(vertex_t interpolated [[stage_in]]) {
    float4 color = interpolated.position;
    color += 1.0; // move from range -1..1 to 0..2
    color *= 0.5; // scale from range 0..2 to 0..1
    return half4(color);
}

。具有以下顶点:

{
  // x,    y,   z,   w,
     1.0, -1.0, 0.0, 1.0,
    -1.0, -1.0, 0.0, 1.0,
    -1.0,  1.0, 0.0, 1.0,
     1.0,  1.0, 0.0, 1.0,
     1.0, -1.0, 0.0, 1.0,
    -1.0,  1.0, 0.0, 1.0,
}

然而,我很惊讶地发现正在渲染一个颜色均匀(黄色)的屏幕,而不是在 x 轴上从 red=0.0red=1.0 的渐变,在 x 轴上从green=0.0green=1.0

(预期渲染输出与实际渲染输出)

interpolated.position似乎为每个片段产生相同的值。

我在这里做错了什么?

Ps:(虽然这个虚拟片段逻辑可以使用顶点插值轻松完成,但我的实际片段逻辑却不能。

插值位置似乎产生了相同的值 每个片段。

不,值非常大。片段着色器中带有 [[position]] 限定符的变量采用像素坐标。除以渲染目标尺寸,您将看到您想要的内容,除了必须反转绿色值,因为 Metal 的惯例是将左上角定义为原点,而不是左下角。

最新更新