简体   繁体   English

如何让实体不断查看 RealityKit 中的相机,类似于 SceneKit 中的 Billboard Constraint

[英]How can I get an entity to constantly look at the camera in RealityKit similar to Billboard Constraint from SceneKit

I have an app that I am trying to update from SceneKit to RealityKit, and one of the features that I am having a hard time replicating in RealityKit is making an entity constantly look at the camera.我有一个应用程序,我正在尝试从 SceneKit 更新到 RealityKit,而我在 RealityKit 中难以复制的功能之一是让实体不断地看着相机。 In SceneKit, this was accomplished by adding the following billboard constraints to the node:在 SceneKit 中,这是通过向节点添加以下广告牌约束来实现的:

let billboardConstraint = SCNBillboardConstraint()

billboardConstraint.freeAxes = [.X, .Y]
startLabelNode.constraints = [billboardConstraint]

Which would allow the startLabelNode to freely rotate so that it was constantly facing the camera without the startLabelNode changing its position.这将允许 startLabelNode 自由旋转,使其始终面向相机,而 startLabelNode 不会改变其 position。

However, I can't seem to figure out a way to do this with RealityKit.但是,我似乎无法找到使用 RealityKit 执行此操作的方法。 I have tried the "lookat" method, which doesn't seem to offer the ability to constantly face the camera.我已经尝试过“lookat”方法,它似乎无法提供不断面对镜头的能力。 Here is a short sample app where I have tried to implement a version of this in RealityKit, but it doesn't offer the ability to have the entity constantly face the camera like it did in SceneKit:这是一个简短的示例应用程序,我尝试在 RealityKit 中实现它的一个版本,但它不提供让实体像在 SceneKit 中那样不断面对相机的能力:

import UIKit
import RealityKit
import ARKit

class ViewController: UIViewController, ARSessionDelegate {
    @IBOutlet weak var arView: ARView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        arView.session.delegate = self
        arView.environment.sceneUnderstanding.options = []
        arView.debugOptions.insert(.showSceneUnderstanding) // Display a debug visualization of the mesh.
        arView.renderOptions = [.disablePersonOcclusion, .disableDepthOfField, .disableMotionBlur] // For performance, disable render options that are not required for this app.
        arView.automaticallyConfigureSession = false
        let configuration = ARWorldTrackingConfiguration()
        if ARWorldTrackingConfiguration.supportsSceneReconstruction(.mesh) {
            configuration.sceneReconstruction = .mesh
        } else {
            print("Mesh Classification not available on this device")
            configuration.worldAlignment = .gravity
            configuration.planeDetection = [.horizontal, .vertical]
        }
        configuration.environmentTexturing = .automatic
        arView.session.run(configuration)
        
        UIApplication.shared.isIdleTimerDisabled = true // Prevent the screen from being dimmed to avoid interrupting the AR experience.
    }

    @IBAction func buttonPressed(_ sender: Any) {
        let screenWidth = arView.bounds.width
        let screenHeight = arView.bounds.height
        let centerOfScreen = CGPoint(x: (screenWidth / 2), y: (screenHeight / 2))
        
        if let raycastResult = arView.raycast(from: centerOfScreen, allowing: .estimatedPlane, alignment: .any).first
        {
            addStartLabel(at: raycastResult.worldTransform)
        }
    }
    
    func addStartLabel(at result: simd_float4x4) {
        let resultAnchor = AnchorEntity(world: result)
        resultAnchor.addChild(clickToStartLabel())
        arView.scene.addAnchor(resultAnchor)
    }
    
    func clickToStartLabel() -> ModelEntity {
        let text = "Click to Start Here"
        let textMesh = MeshResource.generateText(text, extrusionDepth: 0.001, font: UIFont.boldSystemFont(ofSize: 0.01))
        let textMaterial = UnlitMaterial(color: .black)
        let textModelEntity = ModelEntity(mesh: textMesh, materials: [textMaterial])
        textModelEntity.generateCollisionShapes(recursive: true)
        textModelEntity.position.x -= textMesh.width / 2
        textModelEntity.position.y -= textMesh.height / 2
        
        let planeMesh = MeshResource.generatePlane(width: (textMesh.width + 0.01), height: (textMesh.height + 0.01))
        let planeMaterial = UnlitMaterial(color: .white)
        let planeModelEntity = ModelEntity(mesh: planeMesh, materials: [planeMaterial])
        planeModelEntity.generateCollisionShapes(recursive:true)
        // move the plane up to make it sit on the anchor instead of in the middle of the anchor
        planeModelEntity.position.y += planeMesh.height / 2
        planeModelEntity.addChild(textModelEntity)
        
        // This does not always keep the planeModelEntity facing the camera
        planeModelEntity.look(at: arView.cameraTransform.translation, from: planeModelEntity.position, relativeTo: nil)
                
        return planeModelEntity
    }
}

extension MeshResource {
    var width: Float
    {
        return (bounds.max.x - bounds.min.x)
    }

    var height: Float
    {
        return (bounds.max.y - bounds.min.y)
    }
}

Is the lookat function the best way to get the missing feature working in RealityKit or is there a better way to have a Entity constantly face the camera?查看 function 是让缺失功能在 RealityKit 中工作的最佳方法,还是有更好的方法让实体不断面对相机?

k - I haven't messed with RK much, but assuming entity is a scenekit node? k - 我对 RK 没有太多了解,但假设实体是一个场景包节点? - then set constraints on it and it will be forced to face 'targetNode' at all times. - 然后对其设置约束,它将被迫始终面对'targetNode'。 Provide that works the way you want it to, then you may have to experiment with how the node is initially created IE what direction it is facing.如果它以您想要的方式工作,那么您可能必须尝试最初创建节点的方式,即它面向的方向。

func setTarget()
    {
        node.constraints = []
        let vConstraint = SCNLookAtConstraint(target: targetNode)
        vConstraint.isGimbalLockEnabled = true
        node.constraints = [vConstraint]
    }

I was able to figure out an answer to my question.我能够找到我的问题的答案。 Adding the following block of code allowed the entity to constantly look at the camera:添加以下代码块允许实体不断地看着相机:

func session(_ session: ARSession, didUpdate frame: ARFrame) {
    planeModelEntity.look(at: arView.cameraTransform.translation, from: planeModelEntity.position(relativeTo: nil), relativeTo: nil)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM