Как использовать SCNTechnique для создания "замаскированного" портального эффекта в SceneKit / ARKit?

Я пытаюсь понять, как использовать SCNTechnique со Scenekit.

Эффект, который я пытаюсь создать, может быть легко достигнут в Unity путем добавления пользовательского шейдера к двум материалам, делая объекты с "фильтрованным" шейдером видимыми только тогда, когда они видны через другой шейдер (портал). Я следовал этому руководству, чтобы создать его в Unity: https://www.youtube.com/watch?v=b9xUO0zHNXw

Я пытаюсь добиться того же эффекта в SceneKit, но я не уверен, как применить проходы. Я смотрю на SCNTechnique, потому что у него есть варианты для stencilStates, но я не уверен, будет ли это работать.

Есть очень мало ресурсов и учебных пособий по SCNTechnique

1 ответ

Как уже упоминалось в комментариях выше, я не уверен, как добиться occlusion эффект с помощью Stencil Tests которые, как мы знаем, довольно (и я использую этот термин очень свободно) легко сделать в Unity,

Сказав это, мы можем достичь аналогичного эффекта в Swift используя т ransparency, а также rendering order,

Rendering Order просто относится к:

Порядок отображения содержимого узла относительно порядка других узлов.

согласно которому SCNNodes с большим порядком рендеринга рендерится последним и наоборот.

Чтобы сделать объект практически невидимым невооруженным глазом, нам нужно установить transparency значение SCNMaterial до значения, такого как 0.0000001,

Так как бы мы пошли об этом?

В этом очень простом примере, который является просто дверью портала и двумя стенами, мы можем сделать что-то вроде этого (что достаточно легко приспособить к чему-то более существенному и эстетически приятному):

Пример полностью прокомментирован, поэтому должно быть легко понять, что мы делаем.

/// Generates A Portal Door And Walls Which Can Only Be Seen From Behind e.g. When Walking Through The Portsal
///
/// - Returns: SCNNode
func portalNode() -> SCNNode{

    //1. Create An SCNNode To Hold Our Portal
    let portal = SCNNode()

    //2. Create The Portal Door
    let doorFrame = SCNNode()

    //a. Create The Top Of The Door Frame
    let doorFrameTop = SCNNode()
    let doorFrameTopGeometry = SCNPlane(width: 0.55, height: 0.1)
    doorFrameTopGeometry.firstMaterial?.diffuse.contents = UIColor.black
    doorFrameTopGeometry.firstMaterial?.isDoubleSided = true
    doorFrameTop.geometry = doorFrameTopGeometry
    doorFrame.addChildNode(doorFrameTop)
    doorFrameTop.position = SCNVector3(0, 0.45, 0)

    //b. Create The Left Side Of The Door Frame
    let doorFrameLeft = SCNNode()
    let doorFrameLeftGeometry = SCNPlane(width: 0.1, height: 1)
    doorFrameLeftGeometry.firstMaterial?.diffuse.contents = UIColor.black
    doorFrameLeftGeometry.firstMaterial?.isDoubleSided = true
    doorFrameLeft.geometry = doorFrameLeftGeometry
    doorFrame.addChildNode(doorFrameLeft)
    doorFrameLeft.position = SCNVector3(-0.25, 0, 0)

    //c. Create The Right Side Of The Door Frame
    let doorFrameRight = SCNNode()
    let doorFrameRightGeometry = SCNPlane(width: 0.1, height: 1)
    doorFrameRightGeometry.firstMaterial?.diffuse.contents = UIColor.black
    doorFrameRightGeometry.firstMaterial?.isDoubleSided = true
    doorFrameRight.geometry = doorFrameRightGeometry
    doorFrame.addChildNode(doorFrameRight)
    doorFrameRight.position = SCNVector3(0.25, 0, 0)

    //d. Add The Portal Door To The Portal And Set Its Rendering Order To 200 Meaning It Will Be Rendered After Our Masks
    portal.addChildNode(doorFrame)
    doorFrame.renderingOrder = 200
    doorFrame.position = SCNVector3(0, 0, -1)

    //3. Create The Left Wall Enclosure To Hold Our Wall And The Occlusion Node
    let leftWallEnclosure = SCNNode()

    //a. Create The Left Wall And Set Its Rendering Order To 200 Meaning It Will Be Rendered After Our Masks
    let leftWallNode = SCNNode()
    let leftWallMainGeometry = SCNPlane(width: 0.5, height: 1)
    leftWallNode.geometry = leftWallMainGeometry
    leftWallMainGeometry.firstMaterial?.diffuse.contents = UIColor.red
    leftWallMainGeometry.firstMaterial?.isDoubleSided = true
    leftWallNode.renderingOrder = 200

    //b. Create The Left Wall Mask And Set Its Rendering Order To 10 Meaning It Will Be Rendered Before Our Walls
    let leftWallMaskNode = SCNNode()
    let leftWallMaskGeometry = SCNPlane(width: 0.5, height: 1)
    leftWallMaskNode.geometry = leftWallMaskGeometry
    leftWallMaskGeometry.firstMaterial?.diffuse.contents = UIColor.blue
    leftWallMaskGeometry.firstMaterial?.isDoubleSided = true
    leftWallMaskGeometry.firstMaterial?.transparency = 0.0000001
    leftWallMaskNode.renderingOrder = 10
    leftWallMaskNode.position = SCNVector3(0, 0, 0.001)

    //c. Add Our Wall And Mask To The Wall Enclosure
    leftWallEnclosure.addChildNode(leftWallMaskNode)
    leftWallEnclosure.addChildNode(leftWallNode)

    //4. Add The Left Wall Enclosure To Our Portal
    portal.addChildNode(leftWallEnclosure)
    leftWallEnclosure.position = SCNVector3(-0.55, 0, -1)

    //5. Create The Left Wall Enclosure
    let rightWallEnclosure = SCNNode()

    //a. Create The Right Wall And Set Its Rendering Order To 200 Meaning It Will Be Rendered After Our Masks
    let rightWallNode = SCNNode()
    let rightWallMainGeometry = SCNPlane(width: 0.5, height: 1)
    rightWallNode.geometry = rightWallMainGeometry
    rightWallMainGeometry.firstMaterial?.diffuse.contents = UIColor.red
    rightWallMainGeometry.firstMaterial?.isDoubleSided = true
    rightWallNode.renderingOrder = 200

    //b. Create The Right Wall Mask And Set Its Rendering Order To 10 Meaning It Will Be Rendered Before Our Walls
    let rightWallMaskNode = SCNNode()
    let rightWallMaskGeometry = SCNPlane(width: 0.5, height: 1)
    rightWallMaskNode.geometry = rightWallMaskGeometry
    rightWallMaskGeometry.firstMaterial?.diffuse.contents = UIColor.blue
    rightWallMaskGeometry.firstMaterial?.isDoubleSided = true
    rightWallMaskGeometry.firstMaterial?.transparency = 0.0000001
    rightWallMaskNode.renderingOrder = 10
    rightWallMaskNode.position = SCNVector3(0, 0, 0.001)

    //c. Add Our Wall And Mask To The Wall Enclosure
    rightWallEnclosure.addChildNode(rightWallMaskNode)
    rightWallEnclosure.addChildNode(rightWallNode)

    //6. Add The Left Wall Enclosure To Our Portal
    portal.addChildNode(rightWallEnclosure)
    rightWallEnclosure.position = SCNVector3(0.55, 0, -1)

    return portal
}

Который может быть проверен так:

 let portal = portalNode()
 portal.position = SCNVector3(0, 0, -1.5)
 self.sceneView.scene.rootNode.addChildNode(portal)

Надеюсь, это направит вас в правильном направлении...

К вашему сведению, здесь есть хорошее руководство от Рэя Вендерлиха, которое также будет вам полезно...

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