简体   繁体   English

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

[英]How to get fragment coordinate in fragment shader in Metal?

This minimal Metal shader pair renders a simple interpolated gradient onto the screen (when provided with a vertex quad/triangle) based on the vertices' color attributes: 这个最小的金属着色器对基于顶点的颜色属性在屏幕上呈现简单的插值渐变(当提供顶点四边形/三角形时):

#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);
}

…with the following vertices: ...具有以下顶点:

{
  // 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
}

So far so good. 到现在为止还挺好。 It renders the well-known gradient triangle/quad. 它呈现众所周知的渐变三角形/四边形。
The one you find in pretty much every single GPU HelloWorld tutorial. 几乎每个GPU HelloWorld教程中都能找到的那个。


I however need to have a fragment shader that instead of taking the interpolated vertex color computes a color based on the fragments position on screen. 然而,我需要一个片段着色器,而不是采用插值的顶点颜色,根据屏幕上的片段位置计算颜色。 It receives a screen-filling quad of vertices and then uses only the fragment shader to calculate the actual colors. 它接收一个填充屏幕的四边形顶点,然后仅使用片段着色器来计算实际颜色。

From my understanding the position of a vertex is a float4 with the first three elements being the 3d vector and the 4th element set to 1.0 . 根据我的理解,顶点的位置是float4 ,前三个元素是3d矢量,第四个元素设置为1.0

So—I thought—it should be easy to modify the above to have it simply reinterpret the vertex' position as a color in the fragment shader, right? 所以 - 我想 - 应该很容易修改上面的内容,让它简单地将顶点的位置重新解释为片段着色器中的颜色,对吧?

#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);
}

…with the following vertices: ...具有以下顶点:

{
  // 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,
}

I was quite surprised however to find a uniformly colored (yellow) screen being rendered, instead of a gradient going from red=0.0 to red=1.0 in x-axis and green=0.0 to green=1.0 in x-axis: 然而,我很惊讶地找到了一个均匀着色的(黄色)屏幕,而不是在x轴上从red=0.0red=1.0在x轴上从green=0.0green=1.0的渐变:

( expected render output vs. actual render output ) 预期渲染输出实际渲染输出

The interpolated.position appears to be yielding the same value for each fragment. interpolated.position似乎为每个片段产生相同的值。

What am I doing wrong here? 我在这做错了什么?

Ps: (While this dummy fragment logic could have easily been accomplished using vertex interpolation, my actual fragment logic cannot.) Ps :(虽然这个虚拟片段逻辑可以很容易地使用顶点插值完成,但我的实际片段逻辑不能。)

The interpolated.position appears to be yielding the same value for each fragment. interpolated.position似乎为每个片段产生相同的值。

No, the values are just very large. 不,价值非常大。 The variable with the [[position]] qualifier, in the fragment shader, is in pixel coordinates. 片段着色器中具有[[position]]限定符的变量位于像素坐标中。 Divide by the render target dimensions, and you'll see what you want, except for having to invert the green value, because Metal's convention is to define the upper-left as the origin for this, not the bottom-left. 除以渲染目标尺寸,你会看到你想要的东西,除了必须反转绿色值,因为Metal的惯例是将左上角定义为此的原点,而不是左下角。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM