我目前正在开发一个 ARKit 项目,我想使实际的相机输入变暗,以便 3D 场景中的对象更加突出。
到目前为止我找到的2个解决方案:
A) 手动将 CIFilter 应用于相机帧并将其设置为 SceneKit 场景的背景图像,如 this SO post 中的回答 这里的问题是 fps 显着下降。
B) 设置背景颜色,如下所示:
sceneView.scene.background.contents = UIColor(white: 0.0, alpha: 0.2)
可悲的是,颜色带有 alpha <1 are still opaque, so no matter what alpha I set I can't see anything of the camera feed.
有人能想出一种不同的技巧来使相机画面变暗吗?
您的选项 B 不起作用有两个原因:
sceneView.scene.background
是实际显示相机图像的内容,因此如果将其设置为某种颜色,则根本不再显示相机图像。您可能会考虑的一些其他选项(大部分未经测试):
正如您链接的答案中所引用的,使用
SCNTechnique
设置multipass渲染。在第一遍中,使用 excludeCategoryMask
(和场景内容)渲染整个场景,设置为仅渲染背景,使用使所有像素变暗(或模糊或其他)的着色器。在第二遍中,仅渲染您想要在没有该着色器的情况下出现的节点(使用简单的直通着色器)。保留选项 B,但使场景视图不透明。将 视图的
backgroundColor
(不是场景的 background
)设置为纯色,并设置场景 transparency
的 background
以根据该颜色淡出相机源。使用几何图形为您的场景创建“物理”背景 - 例如一个大尺寸的
SCNPlane
,作为相机的子元素放置在某个固定距离处,该距离比任何其他场景内容都远得多。设置平面的背景颜色和透明度。使用多个视图 -
ARSCNView
,变得不透明且具有清晰的背景,另一个(不一定是 SceneKit 视图)仅显示相机源。扰乱其他视图(或添加其他有趣的东西,如 UIVisualEffectView
)来遮挡相机画面。向 Apple 提交有关
sceneView.background
的错误,无法获得节点和材质获得的全套着色自定义选项(滤镜、着色器修改器、完整着色器程序)等,没有这些选项,自定义背景比自定义要困难得多场景的其他方面。 我通过创建具有
SCNNode
几何形状的 SCNSphere
并使用 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 距离进行剪辑,而不是根据相机和目标之间的直线距离进行剪辑。
只要让你的球体足够大,一切看起来都会很好。
对于那些想要实现 rickster 选项“使用几何体为场景创建“物理”背景”的人,这是我的代码(在 .scnassets 中制作的平面和透明度)
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)
我找到了另一个解决方案:您可以使用场景背景上的
intensity
属性来调暗相机源。
例如。这将以 30% 的亮度渲染背景:
sceneView.scene.background.intensity = 0.3