如何在金属中使用texture2d_array数组?

2024-04-02

我一直在尝试使用texture2d_array来应用金属中的实时滤镜。但我没有得到正确的结果。

我像这样创建纹理数组,

Code: Class MetalTextureArray.

class MetalTextureArray {
private(set) var arrayTexture: MTLTexture
private var width: Int
private var height: Int

init(_ width: Int, _ height: Int, _ arrayLength: Int, _ device: MTLDevice) {
    self.width = width
    self.height = height

    let textureDescriptor = MTLTextureDescriptor()

    textureDescriptor.textureType = .type2DArray
    textureDescriptor.pixelFormat = .bgra8Unorm
    textureDescriptor.width = width
    textureDescriptor.height = height
    textureDescriptor.arrayLength = arrayLength

    arrayTexture = device.makeTexture(descriptor: textureDescriptor)
}

func append(_ texture: MTLTexture) -> Bool {
    if let bytes = texture.buffer?.contents() {
        let region = MTLRegion(origin: MTLOrigin(x: 0, y: 0, z: 0), size: MTLSize(width: width, height: height, depth: 1))

        arrayTexture.replace(region: region, mipmapLevel: 0, withBytes: bytes, bytesPerRow: texture.bufferBytesPerRow)

        return true
    }

    return false
}

}

我像这样将此纹理编码到 renderEncoder 中,

Code:

let textureArray = MetalTextureArray.init(firstTexture!.width, firstTexture!.height, colorTextures.count, device)

        _ = textureArray.append(colorTextures[0].texture)
        _ = textureArray.append(colorTextures[1].texture)
        _ = textureArray.append(colorTextures[2].texture)
        _ = textureArray.append(colorTextures[3].texture)
        _ = textureArray.append(colorTextures[4].texture)

        renderEncoder.setFragmentTexture(textureArray.arrayTexture, at: 1)

最后我像这样访问片段着色器中的texture2d_array,

Code:

struct RasterizerData {
    float4 clipSpacePosition [[position]];
    float2 textureCoordinate;

};

    multipleShader(RasterizerData in [[stage_in]],
                texture2d<half> colorTexture [[ texture(0) ]],
                texture2d_array<half> texture2D [[ texture(1) ]])
{
    constexpr sampler textureSampler (mag_filter::linear,
                                      min_filter::linear,
                                      s_address::repeat,
                                      t_address::repeat,
                                      r_address::repeat);

    // Sample the texture and return the color to colorSample

    half4 colorSample = colorTexture.sample (textureSampler, in.textureCoordinate);

    float4 outputColor;

    half red = texture2D.sample(textureSampler, in.textureCoordinate, 2).r;
    half green = texture2D.sample(textureSampler, in.textureCoordinate, 2).g;
    half blue = texture2D.sample(textureSampler, in.textureCoordinate, 2).b;

    outputColor = float4(colorSample.r * red, colorSample.g * green, colorSample.b * blue, colorSample.a);

    // We return the color of the texture
    return outputColor;
}

我附加到纹理数组的纹理是从大小为 256 * 1 的 acv 曲线文件中提取的纹理。

在这段代码中half red = texture2D.sample(textureSampler, in.textureCoordinate, 2).r;我将最后一个参数指定为 2,因为我认为它是要访问的纹理的索引。但我不知道这意味着什么。

但完成所有这些后,我得到了黑屏。即使我有其他片段着色器,它们都工作正常。但对于这个片段着色器,我遇到了黑屏。我认为对于这段代码half blue = texture2D.sample(textureSampler, in.textureCoordinate, 2).b我越来越0对于所有红色、绿色和蓝色值。

Edit 1:

按照建议,我使用 blitcommandEncoder 来复制纹理,但仍然没有结果。

我的代码放在这里,

我的 MetalTextureArray 类已进行修改。

方法追加是这样的。

  func append(_ texture: MTLTexture) -> Bool {
    self.blitCommandEncoder.copy(from: texture, sourceSlice: 0, sourceLevel: 0, sourceOrigin: MTLOrigin(x: 0, y: 0, z: 0), sourceSize: MTLSize(width: texture.width, height: texture.height, depth: 1), to: self.arrayTexture, destinationSlice: count, destinationLevel: 0, destinationOrigin: MTLOrigin(x: 0, y: 0, z: 0))
    count += 1
    return true
}

我像这样附加纹理

let textureArray = MetalTextureArray.init(256, 1, colorTextures.count, device, blitCommandEncoder: blitcommandEncoder)
for (index, filter) in colorTextures!.enumerated() {
     _ = textureArray.append(colorTextures[index].texture)
}
renderEncoder.setFragmentTexture(textureArray.arrayTexture, at: 1)

我的着色器代码是这样的

    multipleShader(RasterizerData in [[stage_in]],
                texture2d<half> colorTexture [[ texture(0) ]],
                texture2d_array<float> textureArray [[texture(1)]],
                const device struct SliceDataSource &sliceData [[ buffer(2) ]])
{
    constexpr sampler textureSampler (mag_filter::linear,
                                      min_filter::linear);

    // Sample the texture and return the color to colorSample
    half4 colorSample = colorTexture.sample (textureSampler, in.textureCoordinate);

    float4 outputColor = float4(0,0,0,0);

    int slice = 1;


float red = textureArray.sample(textureSampler, in.textureCoordinate, slice).r;
float blue = textureArray.sample(textureSampler, in.textureCoordinate, slice).b;
float green = textureArray.sample(textureSampler, in.textureCoordinate, slice).g;

outputColor = float4(colorSample.r * red, colorSample.g * green, colorSample.b * blue, colorSample.a);

    // We return the color of the texture
    return outputColor;
}

我仍然遇到黑屏。

在方法中textureArray.sample(textureSampler, in.textureCoordinate, slice);第三个参数是什么。我将其作为索引,并给出了一些随机索引来获取随机纹理。这是对的吗?

Edit 2:

我终于能够实施该建议,并通过使用得到了结果endEncoding在实现另一个编码器之前的方法,我得到了以下屏幕ACV负过滤器。

enter image description here.

有人可以建议我吗。

Thanks.


纹理数组和数组纹理之间存在差异。在我看来,你只是想要一组纹理。在这种情况下,您不应该使用texture2d_array;你应该使用array<texture2d<half>, 5> texture_array [[texture(1)]].

在应用程序代码中,您可以使用多个调用setFragmentTexture()将纹理分配给顺序索引,或者您可以使用setFragmentTextures()一次性将一堆纹理分配给一系列索引。

在着色器代码中,您可以使用数组下标语法来引用数组中的各个纹理(例如texture_array[2]).

如果您确实想使用数组纹理,那么您可能需要更改您的append()方法。首先,如果texture论证不是用makeTexture(descriptor:offset:bytesPerRow:)的方法MTLBuffer, then texture.buffer一直会nil。也就是说,如果纹理最初是从缓冲区创建的,则它们仅具有关联的缓冲区。要从纹理复制到纹理,您应该使用 blit 命令编码器及其copy(from:sourceSlice:sourceLevel:sourceOrigin:sourceSize:to:destinationSlice:destinationLevel:destinationOrigin:) method.

其次,如果要替换数组纹理的特定切片(数组元素)的纹理数据,则需要将该切片索引作为参数传递给replace()方法。为此,您需要使用replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:)方法,而不是replace(region:mipmapLevel:withBytes:bytesPerRow:)就像你现在正在做的那样。您当前的代码只是一遍又一遍地替换第一个切片(假设源纹理确实与缓冲区关联)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在金属中使用texture2d_array数组? 的相关文章

随机推荐