如何使用SCNTechnique在SceneKit / ARKit中创建“遮罩”门户效果?

3
我正在尝试理解如何在Scenekit中使用SCNTechnique。
我想要创建的效果可以通过在两个材质上添加自定义着色器来轻松实现,使具有“过滤”着色器的对象仅在通过其他着色器(门户)看到时才可见。我已经按照这个教程在Unity中创建了这个效果:https://www.youtube.com/watch?v=b9xUO0zHNXw 我正在尝试在SceneKit中实现相同的效果,但我不确定如何应用这些传递。我正在查看SCNTechnique,因为它具有stencilStates选项,但我不确定这是否有效。
关于SCNTechnique的资源和教程非常少。

你必须使用SCNTechnique吗?基本上你所问的是,在看门时遮挡某些部分,除了门以外? - BlackMirrorz
@BlackMirrorz,我想遮蔽它,但当你走进门户时,它会切换,周围的一切都是可见的。似乎有一种使用遮罩层的方法,但它不会给你同样的效果,因为你可以穿过被遮蔽的墙壁。 - mikehobi
1
在Unity中使用模板测试完成相同的操作后,我认为您需要考虑在ARCamera和SceneKit相机之间切换。不幸的是我不知道怎么用Swift实现 :( 不过我很想知道如何实现。如果您想要一个只使用标准遮挡的基本示例,我可以给您展示一个快速的示例。 - BlackMirrorz
@BlackMirrorz,我很想看一个例子,谢谢! - mikehobi
你最终使用了SCNTechnique吗,@mikehobi?我也想用它。 - masaldana2
1个回答

1
正如上面的评论所提到的,我不确定如何使用模板测试实现遮挡效果,我们知道在Unity中这样做相当容易(我用这个词非常宽松)。

话虽如此,在Swift中我们可以使用透明度渲染顺序来实现类似的效果。

渲染顺序简单地指:

节点内容相对于其他节点绘制的顺序。

其中具有较大渲染顺序的SCNNodes最后呈现,反之亦然。

为了使物体在肉眼下几乎无法看见,我们需要将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)

我希望这能指引你正确的方向...
FYI,这里有一个很好的教程来自Ray Wenderlich,对你也会有用...

谢谢您提供这个例子。不幸的是,这并不能完全满足我的需求。我希望能够拥有一个除了立方体之外的门户,特别是带有无限天空盒。我认为我需要更深入地研究着色器才能实现我想要的效果。谢谢! - mikehobi
没问题 :) 很有趣看看你的进展 :) - BlackMirrorz
有没有可能在不编写代码的情况下,使用SceneKit 3D编辑器实现相同的效果?我想下载一个房间的模型,并通过门户效果使其可访问。 - Claus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接