iOS Metal API рисует 3d текстуру внутри объема

Итак, я пытаюсь визуализировать куб с 3D-текстурой. Текстура содержит 3 ломтика 3 разных цветов, красный, зеленый и синий. Каждый срез состоит из 4 пикселей одного цвета. Работает отлично. https://imgur.com/a/a5oXi

private func makeTexture() {
    let width = 2
    let height = 2
    let depth = 3
    let byteSize = 4
    let bytesPerRow = byteSize * width
    let bytesPerImage = bytesPerRow * height
    let blue: UInt32 = 0x000000FF
    let green: UInt32 = 0xFF00FF00
    let red: UInt32 = 0x00FF0000

    let textureDescriptor = MTLTextureDescriptor()
    textureDescriptor.pixelFormat = .bgra8Unorm
    textureDescriptor.width = width
    textureDescriptor.height = height
    textureDescriptor.depth = depth
    textureDescriptor.textureType = .type3D

    let image = UnsafeMutableRawPointer.allocate(bytes: width*height*depth*byteSize, alignedTo: 1)
    image.storeBytes(of: red, toByteOffset: 0, as: UInt32.self) 
    image.storeBytes(of: red, toByteOffset: 4, as: UInt32.self)
    image.storeBytes(of: red, toByteOffset: 8, as: UInt32.self)
    image.storeBytes(of: red, toByteOffset: 12, as: UInt32.self)

    image.storeBytes(of: green, toByteOffset: 16, as: UInt32.self)
    image.storeBytes(of: green, toByteOffset: 20, as: UInt32.self)
    image.storeBytes(of: green, toByteOffset: 24, as: UInt32.self)
    image.storeBytes(of: green, toByteOffset: 28, as: UInt32.self)

    image.storeBytes(of: blue, toByteOffset: 32, as: UInt32.self)
    image.storeBytes(of: blue, toByteOffset: 36, as: UInt32.self)
    image.storeBytes(of: blue, toByteOffset: 40, as: UInt32.self)
    image.storeBytes(of: blue, toByteOffset: 44, as: UInt32.self)

    texture = device?.makeTexture(descriptor: textureDescriptor)

    let region = MTLRegionMake3D(0, 0, 0, width, height, depth)
    texture?.replace(region: region,
                     mipmapLevel: 0,
                     slice: 0,
                     withBytes: image,
                     bytesPerRow: bytesPerRow,
                     bytesPerImage: bytesPerImage)
}

код фрагмента шейдера:

struct VertexOut{
float4 position [[position]];
float3 textureCoordinate;
};

fragment half4 basic_fragment(VertexOut in [[stage_in]],
                          texture3d<half> colorTexture [[ texture(0) ]]) {

    constexpr sampler textureSampler (mag_filter::nearest,
                                  min_filter::nearest);

    // Sample the texture to obtain a color
    const half4 colorSample = colorTexture.sample(textureSampler, in.textureCoordinate);

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

Затем я хочу сделать красные и синие ломтики прозрачными, поэтому я устанавливаю альфа равным 0

 let blue: UInt32 = 0x000000FF
 let green: UInt32 = 0xFF00FF00
 let red: UInt32 = 0x00FF0000

фрагментный шейдер теперь содержит

const half4 colorSample = colorTexture.sample(textureSampler, in.textureCoordinate);
if (colorSample.a <= 0)
   discard_fragment();

и ожидаю увидеть срез зеленого цвета, но я вижу только зеленые края https://imgur.com/a/yGQdQ.

Внутри куба ничего нет, и я даже не вижу задних кромок, потому что cullMode установлен в.front.

Могу ли я нарисовать и увидеть текстуру внутри объекта, чтобы я мог видеть его внутренности? Я не нашел путь до сих пор. Разве это не когда я устанавливаю тип текстуры на 3d, он должен рассчитывать цвет для каждого пикселя 3D-объекта? не только края? Может, да, но не отображается?

1 ответ

Нет, 3D текстуры не дают вам этого.

3D-объекта нет, есть только треугольники (которые вы предоставляете). Это 2D-объекты, хотя они расположены в 3D-пространстве. Металл не пытается выяснить, какой твердый объект вы пытаетесь нарисовать, экстраполируя из треугольников, которые вы велите ему нарисовать. Ни один обычный API для 3D-рисования не делает этого. Это вообще не возможно. Кроме всего прочего, имейте в виду, что вам даже не нужно отдавать все треугольники металлу вместе; они могут быть разделены на вызовы.

Насколько известно Металлу, "внутри" нет ни одного объекта, только точки, линии и треугольники. Если вы хотите визуализировать внутреннюю часть объекта, вы должны смоделировать это. Для кусочка куба вы должны вычислить новые поверхности "внутри" и передать треугольники Металлу, чтобы нарисовать это.

3D-текстура - это просто текстура, которую вы можете сэмплировать с помощью 3D-координаты. Обратите внимание, что решение о том, какие фрагменты рисовать, уже было принято до того, как был вызван ваш фрагментный шейдер, и Metal даже не знает, что вы будете использовать 3D-текстуру во время принятия этих решений.

Другие вопросы по тегам