这个最小的金属着色器对基于顶点的颜色属性在屏幕上呈现简单的插值渐变(当提供顶点四边形/三角形时):
#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.0
到 red=1.0
和x轴的 green=0.0
到 green=1.0
的渐变:
(expected render output vs. actual render output)
interpolated.position
似乎为每个片段产生相同的值 .
我在这做错了什么?
Ps :(虽然这个虚拟片段逻辑可以很容易地使用顶点插值完成,但我的实际片段逻辑不能 . )
1 回答
不, Value 非常大 . 片段着色器中具有[[position]]限定符的变量位于像素坐标中 . 除以渲染目标尺寸,你会看到你想要的东西,除了必须反转绿色值,因为Metal的惯例是将左上角定义为此的原点,而不是左下角 .