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