如何在金属中使用 texture2d_array 数组?
How to use texture2d_array array in metal?
我一直在尝试使用 texture2d_array 来应用金属中的实时滤波器。但是我没有得到正确的结果。
我是这样创建纹理数组的,
代码: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 中,
代码:
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,
代码:
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
。
编辑 1:
按照建议我使用了blitcommandEncoder来复制纹理,但仍然没有结果。
我的代码在这里,
我的 MetalTextureArray class 已经修改了。
方法追加是这样的。
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);
第三个参数是什么。我把它当作一个索引,我给了一些随机索引来获取随机纹理。正确吗?
编辑 2:
我终于能够实施该建议,在实施另一个编码器之前,我通过使用 endEncoding
方法得到了结果,我得到了以下带有 ACV
负过滤器的屏幕。
.
有人可以推荐我吗。
谢谢。
纹理数组和数组纹理之间存在差异。在我看来,您只需要一组纹理。在那种情况下,你不应该使用 texture2d_array
;你应该使用 array<texture2d<half>, 5> texture_array [[texture(1)]]
.
在应用程序代码中,您可以多次调用 setFragmentTexture()
将纹理分配给顺序索引,也可以使用 setFragmentTextures()
将一堆纹理分配给一系列索引一次。
在着色器代码中,您将使用数组下标语法来引用数组中的各个纹理(例如 texture_array[2]
)。
如果您真的想使用阵列纹理,那么您可能需要更改您的 append()
方法。首先,如果 texture
参数不是用 MTLBuffer
的 makeTexture(descriptor:offset:bytesPerRow:)
方法创建的,那么 texture.buffer
将永远是 nil
。也就是说,如果纹理最初是从缓冲区创建的,则它们只有关联的缓冲区。要从一个纹理复制到另一个纹理,您应该使用 blit 命令编码器及其 copy(from:sourceSlice:sourceLevel:sourceOrigin:sourceSize:to:destinationSlice:destinationLevel:destinationOrigin:)
方法。
其次,如果要替换数组纹理的特定切片(数组元素)的纹理数据,则需要将该切片索引作为参数传递给 replace()
方法。为此,您需要使用 replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:)
方法,而不是您当前正在使用的 replace(region:mipmapLevel:withBytes:bytesPerRow:)
方法。您当前的代码只是一遍又一遍地替换第一个切片(假设源纹理确实与缓冲区相关联)。
我一直在尝试使用 texture2d_array 来应用金属中的实时滤波器。但是我没有得到正确的结果。
我是这样创建纹理数组的,
代码: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 中,
代码:
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,
代码:
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
。
编辑 1:
按照建议我使用了blitcommandEncoder来复制纹理,但仍然没有结果。
我的代码在这里,
我的 MetalTextureArray class 已经修改了。
方法追加是这样的。
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);
第三个参数是什么。我把它当作一个索引,我给了一些随机索引来获取随机纹理。正确吗?
编辑 2:
我终于能够实施该建议,在实施另一个编码器之前,我通过使用 endEncoding
方法得到了结果,我得到了以下带有 ACV
负过滤器的屏幕。
有人可以推荐我吗。
谢谢。
纹理数组和数组纹理之间存在差异。在我看来,您只需要一组纹理。在那种情况下,你不应该使用 texture2d_array
;你应该使用 array<texture2d<half>, 5> texture_array [[texture(1)]]
.
在应用程序代码中,您可以多次调用 setFragmentTexture()
将纹理分配给顺序索引,也可以使用 setFragmentTextures()
将一堆纹理分配给一系列索引一次。
在着色器代码中,您将使用数组下标语法来引用数组中的各个纹理(例如 texture_array[2]
)。
如果您真的想使用阵列纹理,那么您可能需要更改您的 append()
方法。首先,如果 texture
参数不是用 MTLBuffer
的 makeTexture(descriptor:offset:bytesPerRow:)
方法创建的,那么 texture.buffer
将永远是 nil
。也就是说,如果纹理最初是从缓冲区创建的,则它们只有关联的缓冲区。要从一个纹理复制到另一个纹理,您应该使用 blit 命令编码器及其 copy(from:sourceSlice:sourceLevel:sourceOrigin:sourceSize:to:destinationSlice:destinationLevel:destinationOrigin:)
方法。
其次,如果要替换数组纹理的特定切片(数组元素)的纹理数据,则需要将该切片索引作为参数传递给 replace()
方法。为此,您需要使用 replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:)
方法,而不是您当前正在使用的 replace(region:mipmapLevel:withBytes:bytesPerRow:)
方法。您当前的代码只是一遍又一遍地替换第一个切片(假设源纹理确实与缓冲区相关联)。