这个最小的金属着色器对根据顶点的颜色属性在屏幕上渲染一个简单的插值渐变(当提供顶点四边形/三角形时):
#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 教程中找到它。
然而,我需要一个片段着色器,而不是采用插值顶点颜色来计算基于屏幕上片段位置的颜色。它接收一个填充屏幕的四边形顶点,然后仅使用片段着色器来计算实际颜色。
据我了解,顶点的位置是 a 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
到x 轴的渐变:red=1.0
green=0.0
green=1.0
interpolated.position
似乎为每个片段产生相同的值。
我在这里做错了什么?
Ps:(虽然这个虚拟片段逻辑可以很容易地使用顶点插值来完成,但我的实际片段逻辑却不能。)