Как использовать SCNBufferBindingBlock в SceneKit? - PullRequest
0 голосов
/ 17 мая 2018

Я смотрю на метод привязки дескриптора SceneKit с обратным вызовом SCNBufferBindingBlock, как описано здесь:

https://developer.apple.com/documentation/scenekit/scnbufferbindingblock

У кого-нибудь есть пример того, как это работает?

    let program = SCNProgram()
    program.handleBinding(ofBufferNamed: "", frequency: .perFrame) { (steam, theNode, theShadable, theRenderer) in

    }

Для меня это звучит так, будто я могу использовать * .metal шейдер на узле SCNNode без необходимости проходить через SCNTechniques .... кто-нибудь из участников?

Ответы [ 2 ]

0 голосов
/ 02 мая 2019

Просто публикуем это на тот случай, если кто-то еще пришел сюда в поисках краткого примераВот как метод SCNProgram handleBinding() может использоваться с Металл :

Сначала определите структуру данных в файле .metal шейдера:

struct MyShaderUniforms {
    float myFloatParam;
    float2 myFloat2Param;
};

Затем передайте это в качестве аргумента функции шейдера:

fragment half4 myFragmentFunction(MyVertex vertexIn [[stage_in]], 
                                  constant MyShaderUniforms& shaderUniforms [[buffer(0)]]) {
    ...
}

Затем определите ту же структуру данных в вашем Swift файле:

struct MyShaderUniforms {
    var myFloatParam: Float = 1.0
    var myFloat2Param = simd_float2()
}

Теперь создайтеэкземпляр этой структуры данных, изменяет ее значения и определяет SCNBufferBindingBlock:

var myUniforms = MyShaderUniforms()
myUniforms.myFloatParam = 3.0

...

program.handleBinding(ofBufferNamed: "shaderUniforms", frequency: .perFrame) { (bufferStream, node, shadable, renderer) in
    bufferStream.writeBytes(&myUniforms, count: MemoryLayout<MyShaderUniforms>.stride)
}

Здесь строка, переданная в ofBufferNamed:, соответствует имени аргумента в функции фрагмента.Свойство блока bufferStream содержит определенный пользователем тип данных MyShaderUniforms, в который затем можно записать обновленные значения.

0 голосов
/ 24 мая 2018

Метод .handleBinding(ofBufferNamed:frequency:handler:) регистрирует блок для вызова SceneKit во время рендеринга для привязки металлического буфера к шейдерной программе. Этот метод может использоваться только с программами на основе языка затенения Metal или OpenGL. SCNProgram объект помогает выполнить этот пользовательский рендеринг. Программный объект содержит вершинный шейдер и фрагментный шейдер. Использование программного объекта полностью заменяет рендеринг SceneKit. Ваши шейдеры получают информацию от SceneKit и отвечают за все эффекты преобразования, освещения и затенения, которые вы хотите создать. Используйте метод .handleBinding(), чтобы связать блок с программой Metal shader для обработки настройки буфера, используемого в этом шейдере.

Вот ссылка на Документация разработчика в классе SCNProgram.

Также вам нужен метод экземпляра writeBytes(_:count:), который копирует все необходимые байты данных в базовый буфер Metal для использования шейдером.

SCNTechnique класс, специально созданный для пост-обработки рендеринга сцены SceneKit с использованием дополнительных проходов рисования с помощью пользовательских шейдеров Metal или OpenGL. Используя SCNTechnique, вы можете создавать такие эффекты, как градация цвета или смещение, размытие движения и визуализация окклюзии окружающей среды, а также другие проходы рендеринга.

Вот первая выдержка из кода, как правильно использовать метод .handleBinding ():

func useTheseAPIs(shadable: SCNShadable,
                  bufferStream: SCNBufferStream
                  voidPtr: UnsafeMutableRawPointer,
                  bindingBlock: @escaping SCNBindingBlock, 
                  bufferFrequency: SCNBufferFrequency,
                  bufferBindingBlock: @escaping SCNBufferBindingBlock,
                  program: SCNProgram) {

    bufferStream.writeBytes(voidPtr, count: 4) 

    shadable.handleBinding!(ofSymbol: "symbol", handler: bindingBlock)
    shadable.handleUnbinding!(ofSymbol: "symbol", handler: bindingBlock)

    program.handleBinding(ofBufferNamed: "pass", 
                          frequency: bufferFrequency,
                          handler: bufferBindingBlock)
}

А вот вторая выдержка из кода:

let program = SCNProgram()
program.delegate = self as? SCNProgramDelegate
program.vertexShader = NextLevelGLContextYUVVertexShader
program.fragmentShader = NextLevelGLContextYUVFragmentShader

program.setSemantic(
    SCNGeometrySource.Semantic.vertex.rawValue, 
    forSymbol: NextLevelGLContextAttributeVertex, 
    options: nil)

program.setSemantic(
    SCNGeometrySource.Semantic.texcoord.rawValue, 
    forSymbol: NextLevelGLContextAttributeTextureCoord, 
    options: nil)

if let material = self._material {
    material.program = program

    material.handleBinding(ofSymbol: NextLevelGLContextUniformTextureSamplerY, handler: { 
        (programId: UInt32, location: UInt32, node: SCNNode?, renderer: SCNRenderer) in
            glUniform1i(GLint(location), 0);
    }) 
    material.handleBinding(ofSymbol: NextLevelGLContextUniformTextureSamplerUV, handler: { 
        (programId: UInt32, location: UInt32, node: SCNNode?, renderer: SCNRenderer) in
            glUniform1i(GLint(location), 1);
    })
}

Также посмотрите на Имитация рефракции в SceneKit. ТАК сообщение.

...