如何在金属中使用texture2d_array数组? [英] How to use texture2d_array array in metal?

查看:238
本文介绍了如何在金属中使用texture2d_array数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have been trying to use texture2d_array for my application of live filters in metal. But I'm not getting the proper result.

我这样创建纹理数组,

代码: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中,

Im encoding this texture into the renderEncoder like this,

代码:

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,

Finally I'm accessing the texture2d_array in the fragment shader like this,

代码:

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曲线文件中提取的纹理.

The textures I'm appending to the texture array are the texture which are extracted from acv curve file which is of size 256 * 1.

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

In this code half red = texture2D.sample(textureSampler, in.textureCoordinate, 2).r; I gave the last argument as 2 because I thought it as the index of the texture to be accessed. But I don't know what it means.

但是在完成所有这些操作之后,我得到了黑屏.甚至我还有其他片段着色器,而且它们都工作正常.但是对于这个片段着色器,我正在黑屏.我认为对于此代码half blue = texture2D.sample(textureSampler, in.textureCoordinate, 2).b,对于所有红色,绿色和蓝色值,我都会得到0.

But after doing all these I'm getting the black screen. Even I have other fragment shaders and all of them are working fine. But for this fragment shader I'm getting black screen. I think for this code half blue = texture2D.sample(textureSampler, in.textureCoordinate, 2).b I'm getting 0 for all the red, green, and blue values.

根据建议,我使用了blitcommandEncoder复制纹理,但仍然没有结果.

As suggested I used blitcommandEncoder to copy the texture and still no result.

我的代码在这里

我的MetalTextureArray类进行了修改.

My MetalTextureArray class has come modifications.

方法追加是这样的.

  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);中,第三个参数是什么.我虽然将其作为索引,但我给出了一些随机索引来获取随机纹理.正确吗?

In the method textureArray.sample(textureSampler, in.textureCoordinate, slice); what is the third parameter. I though it as an index and I gave some random index to fetch the random texture. Is it correct?

我终于能够实现建议,并且在实现另一个编码器之前,使用endEncoding方法获得了结果,并且得到了带有ACV负滤波器的以下屏幕.

I finally able to implement the suggestion and I got the result by using endEncoding method before another encoder is implemented and I got the following screen with the ACV negative filter.

.

有人可以建议我吗?

谢谢.

推荐答案

纹理数组和纹理数组之间存在区别.在我看来,您只需要一系列纹理即可.在这种情况下,您不应使用texture2d_array.您应该使用array<texture2d<half>, 5> texture_array [[texture(1)]].

There's a difference between an array of textures and an array texture. It sounds to me like you just want an array of textures. In that case, you should not use texture2d_array; you should use array<texture2d<half>, 5> texture_array [[texture(1)]].

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

In the app code, you can either use multiple calls to setFragmentTexture() to assign textures to sequential indexes or you can use setFragmentTextures() to assign a bunch of textures to a range of indexes all at once.

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

In the shader code, you'd use array subscripting syntax to refer to the individual textures in the array (e.g. texture_array[2]).

如果确实要使用数组纹理,则可能需要更改append()方法.首先,如果未使用MTLBuffermakeTexture(descriptor:offset:bytesPerRow:)方法创建texture参数,则texture.buffer将始终为nil.也就是说,仅当纹理最初是从缓冲区创建的时,纹理才具有关联的缓冲区.要从一个纹理复制到另一个纹理,应使用blit命令编码器及其copy(from:sourceSlice:sourceLevel:sourceOrigin:sourceSize:to:destinationSlice:destinationLevel:destinationOrigin:)方法.

If you really do want to use an array texture, then you probably need to change your append() method. First, if the texture argument was not created with the makeTexture(descriptor:offset:bytesPerRow:) method of MTLBuffer, then texture.buffer will always be nil. That is, textures only have associated buffers if they were originally created from a buffer. To copy from texture to texture, you should use a blit command encoder and its copy(from:sourceSlice:sourceLevel:sourceOrigin:sourceSize:to:destinationSlice:destinationLevel:destinationOrigin:) method.

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

Second, if you want to replace the texture data for a specific slice (array element) of the array texture, you need to pass that slice index in as an argument to the replace() method. For that, you'd need to use the replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:) method, not the replace(region:mipmapLevel:withBytes:bytesPerRow:) as you're currently doing. Your current code is just replacing the first slice over and over (assuming the source textures really are associated with a buffer).

这篇关于如何在金属中使用texture2d_array数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆