Как мне сослаться на произвольный идентификатор <MTLTexture>для использования в SCNTechnique? - PullRequest
5 голосов
/ 23 апреля 2019

TL; DR:

Как можно сослаться на символ sampler2D «не на диске» и передать его в SCNTechnique? Моя методика работает, если я ссылаюсь на изображение из моего комплекта, но если нет, я не могу найти способ передать существующий id<MTLTexture> символу сэмплера, который настроил мой метод.

Long:

У меня есть действующий рабочий SCNTechnique, который использует пользовательский символ sampler2D в качестве входных данных для моего прохода металлического фрагмента. Я пытаюсь передать внешний (не из Scenekit) id<MTLTexture>, который я получаю от аппаратного датчика в качестве входных данных для прохода после обработки.

После документов SCNShadable, в которых указано id<MTLTexture>, можно передать как шейдерный ввод через SCNMaterialProperty, для которого установлено правильное содержимое. Это 100% работает в проходе модификатора шейдера - но не работает для SCNTecnique!

let texture = CVMetalTextureGetTexture(textureRef!)

if self.material == nil
{
    self.material = SCNMaterialProperty(contents:texture)
}
else
{
    self.material?.contents = texture
}

self.currentTechnique?.setObject(self.material, forKeyedSubscript: "myTextureSamplerSymbol" as NSCopying)

Для SCNTechnique я получаю журналы ошибок, указывающие «Нет хранилища для текстуры», а захват кадра металлического GPU указывает, что для сэмплера установлена ​​стандартная белая текстура 4x4 пикселя (предположительно из SCNTecnique?). Тем не менее, я смог проверить, что мой пользовательский id<MTLTexture> является допустимым и имеет содержимое в отладчике - его формат, ширина, высота и содержимое все соответствуют ожиданиям, я просто не могу ссылаться на произвольную текстуру в Техника комплекта сцены проходит правильно.

Если я объявлю свой символ в файле SCNTechnique plist для ссылки на изображение, например, так:

<dict>
    <key>type</key>
    <string>sampler2D</string>
    <key>image</key>
    <string>star.png</string>
</dict>

И мои входные данные пропускаются так:

<dict>
    <key>colorSampler</key>
    <string>COLOR</string>
    <key>depthSampler</key>
    <string>DEPTH</string>
    <key> myTextureSampler</key>
    <dict>
        <key>target</key>
        <string> myTextureSamplerSymbol </string>
    </dict>
</dict>

Тогда мой проход работает и ссылка на текстуру star.png.

Кто-нибудь заставил что-то подобное работать?

Спасибо.

1 Ответ

1 голос
/ 26 апреля 2019

Совершенно уверен, что у меня это работает.

Свифт-код для установки MTLTexture и установки его в SCNTechnique.

let tech:SCNTechnique = getTechnique()

let textureLoader = MTKTextureLoader(device: MTLCreateSystemDefaultDevice()!)
let filePath = Bundle.main.url(forResource: "gradient", withExtension: "png")!

do {
    let gradTexture: MTLTexture = try textureLoader.newTexture(URL: filePath, options: nil)
    let matPropTexture = SCNMaterialProperty(contents: gradTexture)
    tech.setObject(matPropTexture, forKeyedSubscript: "myTexture" as NSCopying)
} catch {
    print("Unexpected error: \(error).")
}

scnView.technique = tech

gradient.png - 256 x 1pxцветовой градиент (синий -> зеленый -> красный) изображение, которое я использую для отображения одного значения в псевдоцвет.(например; enter image description here)

Вот полное определение прохода техники из проходов, заданных в моем списке.

<key>mix_outline</key>
<dict>
    <key>draw</key>
    <string>DRAW_QUAD</string>
    <key>metalVertexShader</key>
    <string>pass_through_vertex</string>
    <key>metalFragmentShader</key>
    <string>mix_outline_fragment</string>
    <key>inputs</key>
    <dict>
        <key>colorSampler</key>
        <string>color_scene</string>
        <key>depthSampler</key>
        <string>depth_outline</string>
        <key>myTextureSampler</key>
        <string>myTexture</string>
    </dict>
    <key>outputs</key>
    <dict>
        <key>color</key>
        <string>COLOR</string>
    </dict>
</dict>

myTexture необходимо определить враздел символов в технике plist также.

<key>symbols</key>
<dict>
    <key>myTexture</key>
    <dict>
        <key>type</key>
        <string>sampler2D</string>
    </dict>
</dict>

Я также видел сообщение об ошибке «У прохода нет памяти для ввода myTextureSampler», когда этот блок символов не был включен. Это может быть вашей проблемой?

И, наконец, определение фрагментного шейдера.

fragment half4 mix_outline_fragment(out_vertex_t vert [[stage_in]],
                                    texture2d<float, access::sample> colorSampler [[texture(0)]],
                                    texture2d<float, access::sample> depthSampler [[texture(1)]],
                                    texture2d<float, access::sample> myTextureSampler [[texture(2)]])
{
    float4 myTextureColor = myTextureSampler.read(uint2(55, 0));
    float4 outline = depthSampler.sample( s, vert.uv);
    float4 scene_color = colorSampler.sample( s, vert.uv);
    // float4 fragment_color = mix(scene_color, float4(0.0, 0.0, 0.0, 0.0), outline.r);
    float4 fragment_color = mix(scene_color, myTextureColor, outline.r);
    return half4(fragment_color);
}

Есть несколько других проходов, связанных с этой техникой, которые я не включил;просто чтобы дать некоторый контекст, он визуализирует сцену за один проход и использует буфер глубины вывода на другом проходе с оператором Собеля для генерации краев в текстуру depthSampler.Вышеуказанный шейдер pass + фрагмент рисует эти края поверх оригинального рендеринга сцены.Я использовал сплошной черный цвет для краев, но, посмотрев на это, кажется, что смог прочитать цвет из MTLTexture, который я предоставляю SCNTechnique, и использовать его для краев.

...