片段着色器混合 uv 坐标

Fragment shader mixes uv coordinates

提问人:Łukasz 提问时间:10/25/2023 更新时间:11/1/2023 访问量:66

问:

我试着理解着色器是如何工作的,只是第一步。通过一些教程,我制作了视图、顶点着色器和片段着色器。哇。它有效。

但是当我开始玩它时,我发现了一些非常令人惊讶的东西,我不知道如何处理它。以及为什么它的行为是这样的。

有传递给顶点着色器的顶点:

    let vertices = [
        Vertex(position:vector_float3( 1, 1, 0)),
        Vertex(position:vector_float3( 1,-1, 0)),
        Vertex(position:vector_float3(-1,-1, 0)), 
       
        Vertex(position:vector_float3( 1, 1, 0)),
        Vertex(position:vector_float3( -1, 1, 0)),
        Vertex(position:vector_float3(-1,-1, 0))
    ]

我能看到美丽的矩形。哇,如果我从片段着色器返回颜色,没有计算,更改......

但是,当我开始玩着色器时

fragment float4 fragmentShader(RasterizerData input [[stage_in]],
                               float2 uv [[point_coord]]) {
                           
    float2 coord = (uv - float2(0.5)) * 2;
    return (sin(coord.x*10)/2)+ 0.5;
}

结果与我预期的不同:

should be sinus wave on x axis

我以为 x 轴上只有窦波。

当我使用顶点顺序时,我可以得到不同的结果:

Wrrr

enter image description here

紫外线坐标总是“错”? 怎么了?我错过了什么?

金属 碎片着色器

评论

0赞 Jeshua Lacock 10/25/2023
提供指向您正在遵循的教程的链接会很有帮助。
0赞 Łukasz 10/25/2023
关于“如何画你的第一个三角形”的教程很少。只是设置环境,一步一步,没有额外的。我不明白,片段着色器坐标怎么可能取决于顶点。
0赞 Jeshua Lacock 10/25/2023
当然,但我想将你的结果以及你所做的事情与你所关注的内容进行比较。没有链接,我无法做到这一点。
0赞 Łukasz 10/25/2023
我在 Github 上做了 repo:github.com/typoland/PlayWithMetal。我认为这是我能做的最好的事情。
0赞 Jeshua Lacock 10/25/2023
我需要确切地看到你期望的结果是什么样子的。

答:

0赞 Spo1ler 10/29/2023 #1

point_coord是点基元,意思是.对于三角形,它是未定义的。MTLPrimitiveTypePoint

对于三角形,您实际需要的是提供或计算光栅器将在三角形上插值的 UV。UV 是一个 2 分量坐标,分量从 0 到 1,通常用于对纹理进行采样。在您的例子中,UV 将在屏幕的左上角为 (0, 0),在屏幕的右下角为 (1, 1)。

因此,您的代码将如下所示。在桥接头文件中,你会有一个结构

struct Vertex {
    vector_float3 position;
    vector_float2 texCoord;
}

然后在 Swift 中

let vertices = [
        Vertex(position:vector_float3( 1, 1, 0), texCoord:vector_float2(0, 0)),
        Vertex(position:vector_float3( 1,-1, 0), texCoord:vector_float2(0, 1)),
        Vertex(position:vector_float3(-1,-1, 0), texCoord:vector_float2(1, 1)), 
       
        Vertex(position:vector_float3( 1, 1, 0), texCoord:vector_float2(0, 0)),
        Vertex(position:vector_float3( -1, 1, 0), position:vector_float2(1, 0)),
        Vertex(position:vector_float3(-1,-1, 0), texCoord:vector_float2(1, 1))
    ]

然后,您需要在 中设置一个顶点属性,然后在顶点着色器中读取该属性,然后片段着色器将如下所示MTLVertexDescriptor

fragment float4 fragmentShader(RasterizerData input [[stage_in]]) {
                           
    float2 coord = (input.uv - float2(0.5)) * 2;
    return (sin(coord.x*10)/2)+ 0.5;
}

或者,如果你正在尝试做一个全屏片段着色器,你甚至可以只使用预定义的位置和UV数组。请记住,下面的代码段使用了一个覆盖整个屏幕的大三角形,而不是两个较小的相邻三角形,但它很容易修改。vertex_id

constant array<float3, 3> fullscreenTrianglePositions =
{
    float3{-1, -1, 0},
    float3{-1,  3, 0},
    float3{ 3, -1, 0},
};

constant array<float2, 3> fullscreenTriangleTexCoords =
{
    float2{0,  1},
    float2{0, -1},
    float2{2,  1},
};

struct FullscreenVertexOut
{
    float4 position [[ position ]];
    float2 texCoord;
};

vertex FullscreenVertexOut FullscreenTriangleVertex(ushort vertexId [[ vertex_id ]])
{
    FullscreenVertexOut out;
    out.position.xyz = fullscreenTrianglePositions[vertexId];
    out.position.w = 1;
    out.texCoord = fullscreenTriangleTexCoords[vertexId];
    return out;
}

评论

0赞 Łukasz 10/31/2023
太好了,但有些东西我不太明白:Vertex(position ..., position:: ....) — 相同的标签和双冒号。错字?C++?我有一个 Swift 结构顶点,其位置定义为vector_float3。
0赞 Spo1ler 11/1/2023
哦,我混淆了我的语法。不好意思。我要编辑我的答案。