你能改变金属着色器中采样器的边界吗?

Can you change the bounds of a Sampler in a Metal Shader?

在 Metal Shader 文件的片段函数中,有没有办法重新定义纹理的 "bounds" 相对于样本将其视为归一化坐标的内容?

默认情况下,样本的值 0,0 是纹理的左上角 "pixel",1,1 是纹理的右下角 "pixel"。但是,我重新使用纹理进行绘图,并且在任何给定的渲染过程中,只有一部分纹理包含相关数据。

例如,在宽度:500 和高度:500 的纹理中,我可能只将数据复制到 0,0,250,250 区域。在我的片段函数中,我希望采样器将 1.0 的归一化坐标解释为 250 而不是 500。这可能吗?

我意识到我可以将采样器更改为使用像素寻址,但这有一些限制,如 Metal Shader Specification 中所述。

不,但是如果您知道要从中采样的区域,则可以很容易地在着色器中做一些数学运算来确定采样坐标。这通常与 texture atlases.

一起使用

假设您有一张 500x500 的图像,并且您想要对右下角的 125x125 区域进行采样(只是为了让事情更有趣)。您可以将此采样区域作为 float4 传递,将边界存储为 xyzw 组件中的(左、上、宽、高)。在这种情况下,边界将是 (375, 375, 125, 125)。您传入的纹理坐标是相对于此正方形的 "normalized"。着色器简单地将这些坐标缩放并偏置为纹素坐标,然后将它们归一化为整个纹理的尺寸:

fragment float4 fragment_main(FragmentParams in [[stage_in]],
                              texture2d<float, access::sample> tex2d [[texture(0)]],
                              sampler sampler2d [[sampler(0)]],
                              // ...
                              constant float4 &spriteBounds [[buffer(0)]])
{
    // original coordinates, normalized with respect to subimage
    float2 texCoords = in.texCoords;

    // texture dimensions
    float2 texSize = float2(tex2d.get_width(), tex2d.get_height());

    // adjusted texture coordinates, normalized with respect to full texture
    texCoords = (texCoords * spriteBounds.zw + spriteBounds.xy) / texSize;

    // sample color at modified coordinates
    float4 color = tex2d.sample(sampler2d, texCoords);
    // ...
}