Как использовать 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)
Надеюсь, это направит вас в правильном направлении...
К вашему сведению, здесь есть хорошее руководство от Рэя Вендерлиха, которое также будет вам полезно...