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

8
这个简单的金属着色器对提供了顶点四边形/三角形的颜色属性进行插值,将简单的渐变渲染到屏幕上:
#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向量,第四个元素设置为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,在y轴上从green=0.0green=1.0的渐变色:

(期望的渲染输出expected render output与实际的渲染输出actual render output)

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

我在这里做错了什么?

附注:(虽然这个虚拟片段逻辑可以很容易地使用顶点插值来完成,但我的实际片段逻辑不能)


当您不使用透视“相机”时,position.w仅为1。默认情况下,.xyz被.w除。 - user652038
1个回答

7

插值.position似乎对于每个片段产生了相同的值。

不是的,这些值只是非常大而已。在片段着色器中具有[[position]]限定符的变量以像素坐标表示。除以渲染目标尺寸,你会看到想要的结果,不过需要反转绿色值,因为Metal的习惯是将左上角定义为原点,而不是左下角。


哦,那就解释了。那是缺失的部分。现在可以工作了。非常感谢! - Raspy
8
你如何动态获取渲染目标的尺寸?你会将它们作为一种统一变量传递到着色器中吗?或者它们可以作为常量使用? - Bastiaan M. van de Weerd
1
+1 我也想知道是否有其他方法可以获取渲染目标的大小,而不是将其作为统一变量传递。@jessy - OliverD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接