Я использую MTKTextureLoader для загрузки предоставленных пользователем изображений в текстуры для рендеринга. Я отрисовываю эти предоставленные текстуры в промежуточную текстуру, а затем отрисовываю промежуточную текстуру для рисования MTKView. И промежуточная текстура, и нарисованный объект имеют одинаковый цветовой формат.
Я столкнулся с некоторыми проблемами с определенными изображениями. Все изображения являются файлами PNG, но кажется, что я могу получить различные базовые данные из MTKTextureLoader.
Первый выпуск:
Я загружаю PNG с альфой и без альфы. Это, кажется, фактор, но это не ясно на 100%. Оба свойства текстуры выглядят одинаково.
PNG с альфа:
Texture: <BronzeMtlTexture: 0x1015484b0>
label = 512x512.png
textureType = MTLTextureType2D
pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB
width = 512
height = 512
depth = 1
arrayLength = 1
mipmapLevelCount = 10
sampleCount = 1
cpuCacheMode = MTLCPUCacheModeDefaultCache
storageMode = MTLStorageModeManaged
resourceOptions = MTLResourceCPUCacheModeDefaultCache MTLResourceStorageModeManaged
usage = MTLTextureUsageShaderRead
framebufferOnly = 0
purgeableState = MTLPurgeableStateNonVolatile
parentTexture = <null>
parentRelativeLevel = 0
parentRelativeSlice = 0
buffer = <null>
bufferOffset = 0
bufferBytesPerRow = 0
iosurface = 0x0
iosurfacePlane = 0
label = 512x512.png
PNG без альфа:
Texture: <BronzeMtlTexture: 0x10164a9b0>
label = 016 - jKsgTpt.png
textureType = MTLTextureType2D
pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB
width = 1685
height = 815
depth = 1
arrayLength = 1
mipmapLevelCount = 11
sampleCount = 1
cpuCacheMode = MTLCPUCacheModeDefaultCache
storageMode = MTLStorageModeManaged
resourceOptions = MTLResourceCPUCacheModeDefaultCache MTLResourceStorageModeManaged
usage = MTLTextureUsageShaderRead
framebufferOnly = 0
purgeableState = MTLPurgeableStateNonVolatile
parentTexture = <null>
parentRelativeLevel = 0
parentRelativeSlice = 0
buffer = <null>
bufferOffset = 0
bufferBytesPerRow = 0
iosurface = 0x0
iosurfacePlane = 0
label = 016 - jKsgTpt.png
В приведенном выше случае PNG с альфа-каналом загружается с заменой его компонентов R & B. Есть ли способ обнаружить это, чтобы я мог правильно настроить шейдер по мере необходимости?
Второй выпуск:
Один из PNG, который я тестировал с завершенной загрузкой как MTLPixelFormatRGBA16Unorm
. Моя промежуточная текстура и рисование MTKView обычно MTLPixelFormatBGRA8Unorm
. Это можно обнаружить, но как мне правильно отрендерить эту текстуру до промежуточной текстуры? В этом случае я получаю очень расплывчатую картинку.
Мне кажется, что мне не хватает некоторых нюансов MTKTextureLoader или что, возможно, это не было предназначено для использования так, как я хочу.
Обновление 1
Я не делаю ничего особенного с загрузчиком текстур. Там не так много для настройки:
let textureLoader = MTKTextureLoader(device: metalDevice)
let options: [MTKTextureLoader.Option:Any] = [
.generateMipmaps : true,
.SRGB: true
]
textureLoader.newTexture(URL: url, options: options) { (texture, error) in
// Store the texture here
}
Как показано в первом выпуске, я получу две разные текстуры, которые помечены как BGRA8, но, как правило, пиксели с прозрачностью имеют свои пиксели в порядке RGBA. Во втором выпуске у меня есть один конкретный PNG, который загружается в RGBA16.
Обновление 2
Настройка трубопровода:
let pipelineDescriptor = MTLRenderPipelineDescriptor()
pipelineDescriptor.vertexFunction = self.library.makeFunction(name: "instance_vertex")
pipelineDescriptor.fragmentFunction = self.library.makeFunction(name: "instance_fragment")
pipelineDescriptor.colorAttachments[0].pixelFormat = newTexture.pixelFormat
pipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = .add
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = .add
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
newTexture
в этом случае текстура загружается из MTKTextureLoader.
Настройка рендера:
let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].texture = canvasTexture
renderPassDescriptor.colorAttachments[0].loadAction = .clear
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(
red: Double(red),
green: Double(green),
blue: Double(blue),
alpha: Double(alpha)
)
renderPassDescriptor.colorAttachments[0].storeAction = .store
let encoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
canvasTexture
было сделано с тем же типом текстуры, что и MTKView. Я пробовал BGRA8 и BGRA8 SRGB, в зависимости от того, какой флаг загрузчика для SRGB был установлен выше в загрузчике.
Визуализация:
encoder.setRenderPipelineState(pipelineState)
encoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
encoder.setVertexBuffer(uniformBuffer, offset: memorySize * offset, index: 1)
encoder.setFragmentTexture(newTexture, index: 0)
encoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4)
Фрагмент шейдера:
fragment half4 face_instance_fragment(VertexOut v [[stage_in]], texture2d<float, access::sample> texture [[ texture(0) ]])
{
constexpr sampler textureSampler(mag_filter::linear,
min_filter::linear,
s_address::clamp_to_edge,
t_address::clamp_to_edge,
r_address::clamp_to_edge);
return (half4)texture.sample(textureSampler, v.texturePosition);
}
Добавление .zyxw
к сэмплеру выше исправит цвета одной текстуры, но нарушит другую, как я знаю, цвета правильные, просто в неправильном порядке.