透明 SCNFloor 上的 SceneKit 阴影()

2023-11-23

我有一个floor node,我需要在其上投射阴影directional light。该节点需要是透明的(用于AR环境)。 当我使用时这效果很好ARKit,但使用相同的设置SceneKit没有显示任何阴影或反射。我怎样才能投下阴影SceneKit像这样? SceneKit 的问题是由我设置的事实引起的sceneView.backgroundColor = .clear- 但我需要这个应用程序中的这种行为。这可以通过某种方式避免吗?

演示此问题的示例代码(仅适用于设备,不适用于模拟器):

@IBOutlet weak var sceneView: SCNView! {
    didSet {

        sceneView.scene = SCNScene()

        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        sceneView.pointOfView = cameraNode

        let testNode = SCNNode(geometry: SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0))
        testNode.position = SCNVector3(x: 0, y: 0, z: -5)
        sceneView.scene!.rootNode.addChildNode(testNode)

        let animation = SCNAction.rotateBy(x: 0, y: .pi, z: 0, duration: 3.0)
        testNode.runAction(SCNAction.repeatForever(animation), completionHandler: nil)

        let floor = SCNFloor()
        floor.firstMaterial!.colorBufferWriteMask = []
        floor.firstMaterial!.readsFromDepthBuffer = true
        floor.firstMaterial!.writesToDepthBuffer = true
        floor.firstMaterial!.lightingModel = .constant
        let floorNode = SCNNode(geometry: floor)
        floorNode.position = SCNVector3(x: 0, y: -2, z: 0)
        sceneView.scene!.rootNode.addChildNode(floorNode)

        let light = SCNLight()
        light.type = .directional
        light.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
        light.color = UIColor.white
        light.castsShadow = true
        light.automaticallyAdjustsShadowProjection = true
        light.shadowMode = .deferred
        let sunLightNode = SCNNode()
        sunLightNode.position = SCNVector3(x: 1_000, y: 1_000, z: 0)
        sunLightNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: .pi * 1.5)
        sunLightNode.light = light
        sceneView.scene!.rootNode.addChildNode(sunLightNode)

        let omniLightNode: SCNNode = {
            let omniLightNode = SCNNode()
            let light: SCNLight = {
                let light = SCNLight()
                light.type = .omni
                return light
            }()
            omniLightNode.light = light
            return omniLightNode
        }()
        sceneView.scene!.rootNode.addChildNode(omniLightNode)
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    let tapGR = UITapGestureRecognizer(target: self, action: #selector(toggleTransparent))
    view.addGestureRecognizer(tapGR)
}

@objc func toggleTransparent() {
    transparent = !transparent
}

var transparent = false {
    didSet {
        sceneView.backgroundColor = transparent ? .clear : .white
    }
}

以下是 macOS 的相同示例,构建在 SceneKit 游戏项目之上:

import SceneKit
import QuartzCore

class GameViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // create a new scene
        let scene = SCNScene(named: "art.scnassets/ship.scn")!

        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)

        // place the camera
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

        let testNode = SCNNode(geometry: SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0))
        testNode.position = SCNVector3(x: 0, y: 0, z: -5)
        scene.rootNode.addChildNode(testNode)

        let animation = SCNAction.rotateBy(x: 0, y: .pi, z: 0, duration: 3.0)
        testNode.runAction(SCNAction.repeatForever(animation), completionHandler: nil)

        let floor = SCNFloor()
        floor.firstMaterial!.colorBufferWriteMask = []
        floor.firstMaterial!.readsFromDepthBuffer = true
        floor.firstMaterial!.writesToDepthBuffer = true
        floor.firstMaterial!.lightingModel = .constant
        let floorNode = SCNNode(geometry: floor)
        floorNode.position = SCNVector3(x: 0, y: -2, z: 0)
        scene.rootNode.addChildNode(floorNode)

        let light = SCNLight()
        light.type = .directional
        light.shadowColor = NSColor(red: 0, green: 0, blue: 0, alpha: 0.5)
        light.color = NSColor.white
        light.castsShadow = true
        light.automaticallyAdjustsShadowProjection = true
        light.shadowMode = .deferred
        let sunLightNode = SCNNode()
        sunLightNode.position = SCNVector3(x: 1_000, y: 1_000, z: 0)
        sunLightNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: .pi * 1.5)
        sunLightNode.light = light
        scene.rootNode.addChildNode(sunLightNode)

        let omniLightNode: SCNNode = {
            let omniLightNode = SCNNode()
            let light: SCNLight = {
                let light = SCNLight()
                light.type = .omni
                return light
            }()
            omniLightNode.light = light
            return omniLightNode
        }()
        scene.rootNode.addChildNode(omniLightNode)

        // retrieve the SCNView
        let scnView = self.view as! SCNView

        // set the scene to the view
        scnView.scene = scene

        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true

        // configure the view
        scnView.backgroundColor = .clear
//        scnView.backgroundColor = .white // shadow works in this mode, but I need it to be clear
    }
}

示例项目:

MacOS: https://www.dropbox.com/s/1o50mbgzg4gc0fg/Test_macOS.zip?dl=1

iOS: https://www.dropbox.com/s/fk71oay1sopc1vp/Test.zip?dl=1

在 macOS 中,您可以更改 ViewController 最后一行的背景颜色 - 我需要它清晰,这样我就可以在其下显示相机预览。

在下面的图片中,您可以看到 sceneView.backgroundColor 为白色时的样子,而下面的图片为透明。清晰版本没有阴影。

Here you can see this effect with white background color of sceneView - shadow is visible

And this if version with sceneView.backgroundColor == .clear. There is UIImageView under this view. I need to use this version, but there is no shadow visible


获得透明阴影有两个步骤:

First:您需要将其连接为node to the scene,不作为geometry type.

let floor = SCNNode()
floor.geometry = SCNFloor()
floor.geometry?.firstMaterial!.colorBufferWriteMask = []
floor.geometry?.firstMaterial!.readsFromDepthBuffer = true
floor.geometry?.firstMaterial!.writesToDepthBuffer = true
floor.geometry?.firstMaterial!.lightingModel = .constant
scene.rootNode.addChildNode(floor)

Shadow on invisible SCNFloor(): enter image description here

Shadow on visible SCNPlane() and our camera is under SCNFloor(): enter image description here

为了得到一个transparent shadow你需要设置一个shadow color,不是object's transparency itself.

Second : A shadow color对于 macOS 必须这样设置:

lightNode.light!.shadowColor = NSColor(calibratedRed: 0,
                                               green: 0, 
                                                blue: 0, 
                                               alpha: 0.5)

...对于 iOS 来说,它看起来像这样:

lightNode.light!.shadowColor = UIColor(white: 0, alpha: 0.5)

这里的 Alpha 分量(alpha: 0.5) is an opacity阴影和 RGB 分量(white: 0) 是阴影的黑色。

enter image description here

enter image description here

P.S.

sceneView.backgroundColor之间切换.clear颜色和.white colour.

在这种特殊情况下,我无法捕捉到强大的阴影sceneView.backgroundColor = .clear,因为你需要在之间切换RGBA=1,1,1,1 (白色模式:白色,alpha=1) 和RGBA=0,0,0,0 (清除模式:黑色,alpha=0)。

为了看到背景上的半透明阴影,组件应该是RGB=1,1,1 and A=0.5,但由于 SceneKit 的内部合成机制,这些值会使图像变白。但是当我设置RGB=1,1,1 and A=0.02影子非常微弱。

目前这是一个可以忍受的解决方法(在“解决方案”部分中查找下面的解决方案):

@objc func toggleTransparent() {
    transparent = !transparent
}  
var transparent = false {
    didSet {
        // this shadow is very FEEBLE and it's whitening BG image a little bit
        sceneView.backgroundColor = 
                        transparent ? UIColor(white: 1, alpha: 0.02) : .white
    }
}

let light = SCNLight()
light.type = .directional

if transparent == false {
    light.shadowColor = UIColor(white: 0, alpha: 0.9)
}

如果我设置light.shadowColor = UIColor(white: 0, alpha: 1)我去拿满意的影子在 BG 图像上但是纯黑色阴影在白色。

enter image description here

SOLUTION:

您应该抓取 3D 对象的渲染,以使用其有用的 Alpha 通道预乘 RGBA 图像。之后就可以复合了rgba image of cube and its shadow over image of nature使用经典的OVER在另一个View中进行合成操作。

这是一个公式OVER手术 :

(RGB1 * A1) + (RGB2 * (1 – A1))

enter image description here

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

透明 SCNFloor 上的 SceneKit 阴影() 的相关文章

随机推荐

  • 如何从wordpress数据库获取产品属性

    编写自定义代码以使用 WordPress 数据库创建产品详细信息页面 我已经显示了产品标题 描述 价格 库存等 并且对产品属性感到困惑 在数据库中 product attributes以序列化方式存储在数据库的wp postmeta表中 而
  • 如何使用参数屏蔽除 Java 中最后 4 个字符之外的所有字符串字符?

    我想知道如何屏蔽除最后 4 个字符串之外的任意数量的字符串字符 我想使用 X 屏蔽所有字符串 例如 Number S1234567B Result Number XXXXX567B 感谢你们 解决方案1 您可以使用正则表达式来完成 这是sh
  • TreeSet迭代的时间复杂度是多少?

    在我的代码中 JavaTreeSet迭代是主要的时间因素 在观察这个系统时 我相信它的复杂度是 O n 任何人都可以验证这一点吗 我认为通过提供从子节点到父节点的向后链接我可以提高性能 TreeSet迭代当然是 O n 正如任何合理的树遍历
  • ASP.NET Core 中的会话变量值变为 null

    我在一种方法中设置会话变量 并尝试从控制器中的另一种方法获取会话变量值 但它总是为空 这是我的代码 public class HomeController Controller public IActionResult Index Http
  • 将 R 向量转换为 1 个元素的字符串向量 [重复]

    这个问题在这里已经有答案了 我现在使用 R 编程语言 我有一个向量 a lt c aa bb cc 我想将它们粘贴到系统命令中 我现在正在尝试这种方式 args lt paste a sep system paste command arg
  • CGImageCreateWithMask 效果很好,但在我的结果图像中,遮罩区域是黑色的,如何将其设置为白色?

    我这样掩盖了我的形象 CGImageRef maskRef UIImage imageNamed testMask2 png CGImage CGImageRef mask CGImageMaskCreate CGImageGetWidth
  • Tensorflow 中的计划采样

    关于 seq2seq 模型的最新 Tensorflow api 已包含计划采样 https www tensorflow org api docs python tf contrib seq2seq ScheduledEmbeddingTr
  • 当我的应用程序收到内存警告时该怎么办?

    当我的应用程序收到内存警告时我应该做什么 这完全取决于您的应用程序 通常除了遵循 Apple 推荐的做法之外 您无需执行任何特殊操作 目前不可见的 ViewController 将获得didReceiveMemoryWarning信息 默认
  • H264 NAL 单元前缀

    我需要对 H264 NAL 单位分隔符前缀进行一些澄清 00 00 00 01 and 00 00 01 我正在使用 Intel Media SDK 生成 H264 并将其打包到 RTP 中 问题是到目前为止我只是在寻找00 00 00 0
  • 在循环内部或外部声明变量

    为什么以下工作正常 String str while condition str calculateStr 但这据说是危险 不正确的 while condition String str calculateStr 是否需要在循环外声明变量
  • AngularJS 指令中自定义 HTML 标签的后果

    假设我写了一个自定义gravatarAngularJS 中的指令绑定到email范围上的属性 该指令将替换此 HTML
  • 如何扩展谷歌分析来跟踪 AJAX 等(根据 H5BP 文档)

    我正在尝试安装google analytics augments中确定的extend mdH5BP 文件 https github com h5bp html5 boilerplate blob v4 3 0 doc extend md 它
  • p:ajax 事件用于惰性 p:dataTable 分页

    当我的列表在延迟加载数据表期间更新时 我无法找到将执行我的 javascript 的 ajax 事件 该 JavaScript 负责根据我的列表更新图像封面流 该列表在初始数据表加载期间 进行分页以及更改页面上的记录数时重新填充 非常感谢您
  • 创建 NULL 数据库表最佳实践

    不确定处理问题的最佳实践是什么NULL当我有一个表时的值 其中两个字段有时只填充创建很多NULL行中的值 是否应该将这两个字段移动到一个单独的表中 创建两个没有任何字段的表NULL values 这两个表之间的联接只会返回一个与我的原始表相
  • 如何在android中运行openCV相关应用程序,而不使用OpenCV管理器

    在我的 Android 应用程序中 我使用 OpenCV 库的静态加载 IE OpenCVLoader initDebug 在模拟器上运行时它将返回 true 但是返回错误在 移动 设备上运行时 如果我使用 OpenCVLoader ini
  • 使用 JMH 控制方法的顺序

    我在我的项目中使用 JMH 基准测试 我用 Benchmark注释了方法1和方法2 我希望顺序是 method1 method2 mehod1 method2 等等 这意味着 我希望方法 2 会立即遵循方法 1 有没有办法这样做 谢谢你 J
  • 如何让 Materialise 选择下拉列表与 React 一起使用?

    添加以下模板代码由物化提供不能立即在 React 组件中工作 div class input field col s12 div
  • 如何在AdvancedCustomDrawItem期间绘制TTreeView的样式选择矩形?

    我是做定制的TTreeView使用从头开始绘制OnAdvancedCustomDrawItem事件 我想知道如何在我的所有者绘制项目的背景中正确渲染这些选择和热矩形 它们是 Vista 7 风格的 所以我不能简单地用纯色填充背景 我尝试在以
  • 生成唯一的 6 位数代码

    我正在根据以下字符生成 6 位代码 这些将用于在贴纸上盖印 它们将以 10k 或更少的批次生成 在打印之前 我预计总数不会超过 1 200 万 可能要少得多 生成批量代码后 我将检查现有代码的 MySQL 数据库以确保没有重复 exclud
  • 透明 SCNFloor 上的 SceneKit 阴影()

    我有一个floor node 我需要在其上投射阴影directional light 该节点需要是透明的 用于AR环境 当我使用时这效果很好ARKit 但使用相同的设置SceneKit没有显示任何阴影或反射 我怎样才能投下阴影SceneKi