菜鸟教程小白 发表于 2022-12-13 02:34:31

ios - 如何在 Metal 中使用 texture2d_array 数组?


                                            <p><p>我一直在尝试使用 texture2d_array 在 Metal 中应用实时过滤器。但我没有得到正确的结果。</p>

<p>我正在创建这样的纹理数组,</p>

<p>代码:<code>Class MetalTextureArray</code>.</p>

<pre><code>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) -&gt; 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
}
</code></pre>

<p>}</p>

<p>我像这样将这个纹理编码到 renderEncoder 中,</p>

<p>代码:</p>

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

      _ = textureArray.append(colorTextures.texture)
      _ = textureArray.append(colorTextures.texture)
      _ = textureArray.append(colorTextures.texture)
      _ = textureArray.append(colorTextures.texture)
      _ = textureArray.append(colorTextures.texture)

      renderEncoder.setFragmentTexture(textureArray.arrayTexture, at: 1)
</code></pre>

<p>最后我像这样在片段着色器中访问 texture2d_array,</p>

<p>代码:</p>

<pre><code>struct RasterizerData {
    float4 clipSpacePosition [];
    float2 textureCoordinate;

};

    multipleShader(RasterizerData in [],
                texture2d&lt;half&gt; colorTexture [[ texture(0) ]],
                texture2d_array&lt;half&gt; 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;
}
</code></pre>

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

<p>在这段代码中 <code>half red = texture2D.sample(textureSampler, in.textureCoordinate, 2).r;</code> 我把最后一个参数设为 2 因为我认为它是纹理的索引访问。但我不知道这是什么意思。</p>

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

<p><strong>编辑 1:</strong></p>

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

<p>我的代码放在这里,</p>

<p>我的 MetalTextureArray 类进行了修改。</p>

<p>方法 append 是这样的。</p>

<pre><code>func append(_ texture: MTLTexture) -&gt; 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
}
</code></pre>

<p>我像这样添加纹理</p>

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

<p>我的着色器代码是这样的</p>

<pre><code>    multipleShader(RasterizerData in [],
                texture2d&lt;half&gt; colorTexture [[ texture(0) ]],
                texture2d_array&lt;float&gt; textureArray [],
                const device struct SliceDataSource &amp;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;
}
</code></pre>

<p>我还是黑屏。</p>

<p>方法中<code>textureArray.sample(textureSampler, in.textureCoordinate, slice);</code>第三个参数是什么。我认为它是一个索引,我给出了一些随机索引来获取随机纹理。对吗?</p>

<p><strong>编辑 2:</strong></p>

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

<p> <a href="/image/ZoarR.png" rel="noreferrer noopener nofollow"><img src="/image/ZoarR.png" alt="enter image description here"/></a> .</p>

<p>谁能推荐我。</p>

<p>谢谢。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>纹理数组和纹理数组是有区别的。在我看来,您只需要一系列纹理。在这种情况下,你不应该使用 <code>texture2d_array</code>;你应该使用 <code>array<texture2d<half>, 5> texture_array []</code>.</p>

<p>在应用程序代码中,您可以使用多次调用 <code>setFragmentTexture()</code> 将纹理分配给顺序索引,也可以使用 <code>setFragmentTextures()</code> 分配一堆一次将纹理添加到一系列索引。</p>

<p>在着色器代码中,您可以使用数组下标语法来引用数组中的各个纹理(例如 <code>texture_array</code>)。</p>

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

<p>其次,如果要替换数组纹理的特定切片(数组元素)的纹理数据,则需要将该切片索引作为参数传递给 <code>replace()</code> 方法.为此,您需要使用 <code>replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:)</code> 方法,而不是 <code>replace(region:mipmapLevel:withBytes:bytesPerRow:) </code> 就像你目前正在做的那样。您当前的代码只是一遍又一遍地替换第一个切片(假设源纹理确实与缓冲区相关联)。</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 如何在 Metal 中使用 texture2d_array 数组?,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/46094672/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/46094672/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 如何在 Metal 中使用 texture2d_array 数组?