Darken/Lighten ARKit 摄像头在物体后面馈送

Darken/Lighten ARKit camera feed behind objects

我目前正在做一个 ARKit 项目,我想在这个项目中使实际的摄像头画面变暗,以便 3D 场景中的对象更加突出。

目前我找到的 2 个解决方案:

A) 手动将 CIFilter 应用于相机帧并将其设置为 SceneKit 场景的背景图像,如 this SO post 中的回答 这里的问题是 fps 显着降低。

B) 像这样设置背景颜色:

sceneView.scene.background.contents = UIColor(white: 0.0, alpha: 0.2)

遗憾的是,alpha <1 的颜色仍然是不透明的,所以无论我设置什么 alpha,我都看不到任何相机画面。

谁能想出一个不同的技巧来使相机画面变暗?

你的选项 B 不成立有两个原因:

  1. 场景视图是不透明的,所以它后面没有任何东西可以混合部分透明的背景颜色。
  2. sceneView.scene.background 是实际显示相机图像的颜色,因此如果您将其设置为某种颜色,您将不再显示相机图像。

您可能会考虑的其他一些选项(大部分未经测试):

  • 根据您链接的答案,使用 SCNTechnique 设置 multipass 渲染。在第一遍中,使用 excludeCategoryMask(和您的场景内容)渲染整个场景设置为只渲染背景,使用使所有像素变暗(或模糊或其他)的着色器。在第二遍中,仅渲染您想要在没有该着色器的情况下出现的节点(使用简单的直通着色器)。

  • 保留选项 B,但使场景视图不透明。将视图的 backgroundColor(不是场景的background)设置为纯色,并将场景backgroundtransparency设置为淡出该颜色的相机画面。

  • 使用几何为您的场景创建 "physical" 背景 — 例如一个 SCNPlane 大尺寸,作为相机的子级放置在比任何其他场景内容远得多的固定距离处。设置飞机的背景颜色和透明度。

  • 使用多个视图 — ARSCNView,不透明且背景清晰,另一个(不一定是 SceneKit 视图)只显示相机画面。扰乱其他视图(或放入其他有趣的东西,如 UIVisualEffectView)以遮挡相机画面。

  • File a bug with Apple 关于 sceneView.background 没有获得节点和材质获得的全套着色自定义选项(过滤器、着色器修改器、完整着色器程序)等,没有这些自定义背景比自定义场景的其他方面要困难得多。

对于那些想要实施 rickster 选项的人"Use geometry to create a "这里是我的代码(它的平面和透明度在 .scnassets 中制作)"Use geometry to create a "物理“场景背景”

    guard let backgroundPlane = sceneView.scene.rootNode.childNode(withName: "background", recursively: false) else { return }
    backgroundPlane.removeFromParentNode()
    backgroundPlane.position = SCNVector3Make(0, 0, -2)
    sceneView.pointOfView?.addChildNode(backgroundPlane)

我通过使用 SCNSphere 几何体创建 SCNNode 并使用 ARSCNView.pointOfView.

将其连接到相机来实现此效果

override func viewDidLoad() {
    super.viewDidLoad()

    let sphereFogNode = makeSphereNode()
    arView.pointOfView!.addChildNode(sphereFogNode)

    view.addSubview(arView)
}

private static func makeSphereGeom() -> SCNSphere {
    let sphere = SCNSphere(radius: 5)
    let material = SCNMaterial()

    material.diffuse.contents = UIColor(white: 1.0, alpha: 0.7)
    material.isDoubleSided = true

    sphere.materials = [material]
    return sphere
}

private static func makeSphereNode() -> SCNNode {
    SCNNode(geometry: makeSphereGeom())
}

剪裁外球体

这会使相机和球体边界外的任何东西变暗。命中测试 (ARFrame.hitTest) 不考虑球体边界。您可以从球体外部接收结果。

通过球体的不透明度可以看到球体之外的事物。好像不透明的东西在球体外面也会变得透明

白色部分是球体内部的平面,灰色部分是球体外部的平面。该平面是纯白色且不透明的。我尝试使用 SCNScene.fog* 将 SceneKit 图形剪裁到球体之外,但似乎雾并没有遮挡渲染的内容,只是影响了它的外观。 SCNCamera.zFar 也不起作用,因为它根据 Z 距离进行剪辑,而不是根据相机和目标之间的直线距离进行剪辑。

只要让你的球体足够大,一切都会很好。