gpt4 book ai didi

swift - 如何以编程方式移动 ARAnchor?

转载 作者:IT王子 更新时间:2023-10-29 05:25:02 28 4
gpt4 key购买 nike

我正在尝试使用新的 ARKit 来替换我拥有的另一个类似的解决方案。真是太棒了!但我似乎无法弄清楚如何以编程方式移动 ARAnchor。我想慢慢地将 anchor 移动到用户的左侧。

在用户前方 2 米处创建 anchor :

        var translation = matrix_identity_float4x4
translation.columns.3.z = -2.0
let transform = simd_mul(currentFrame.camera.transform, translation)

let anchor = ARAnchor(transform: transform)
sceneView.session.add(anchor: anchor)

稍后,将对象移动到用户的左侧/右侧(x 轴)...
anchor.transform.columns.3.x = anchor.transform.columns.3.x + 0.1

每 50 毫秒(或其他)重复一次。

上面的方法不起作用,因为 transform 是一个 get-only 属性。

我需要一种方法来改变 AR 对象在空间中相对于用户的位置,以保持 AR 体验完好无损 - 这意味着,如果您移动设备,AR 对象将移动但也不会“卡住” ”对相机来说就像它只是简单地画在上面一样,但是移动就像你在走过时看到一个人在移动一样 - 他们在移动,你也在移动,看起来很自然。

请注意,此问题的范围仅与如何在空间中相对于用户 (ARAnchor) 移动对象有关,与平面 (ARPlaneAnchor) 或另一个检测到的表面 (ARHitTestResult) 无关。

谢谢!

最佳答案

您不需要移动 anchor 。 (挥手)那不是你要找的API...

添加 ARAnchor session 的对象实际上是关于在现实世界空间中“标记”一个点,以便您以后可以引用它。点(1,1,1) (例如)始终是点 (1,1,1) — 你不能把它移到别的地方,因为那不是重点 (1,1,1)了。

做一个 2D 类比: anchor 是引用点,有点像 View 的边界。系统(或您的另一段代码)告诉 View 它的边界在哪里,并且 View 相对于这些边界绘制其内容。 AR 中的 anchor 为您提供了可用于绘制 3D 内容的引用点。

您要问的实际上是关于在两点之间移动(和动画移动)虚拟内容。而且 ARKit 本身真的不是关于显示或动画虚拟内容——那里有很多很棒的图形引擎,所以 ARKit 不需要重新发明那个轮子。 ARKit 所做的是提供一个真实世界的引用框架,让您使用现有的图形技术(如 SceneKit 或 SpriteKit(或 Unity 或 Unreal,或使用 Metal 或 GL 构建的自定义引擎)来显示或动画内容。

既然你提到尝试用 SpriteKit 做到这一点......当心,它会变得一团糟。 SpriteKit 是一个 2D 引擎,而 ARSKView提供了一些在那里硬塞第三维的方法,这些方法有其局限性。
ARSKView自动更新 xScale , yScale , 和 zRotationARAnchor 相关联的每个 Sprite ,提供3D透视的错觉。但这仅适用于连接到 anchor 的节点,并且如上所述, anchor 是静态的。

但是,您可以向场景中添加其他节点,并使用这些相同的属性使这些节点与 ARSKView 匹配。 - 管理节点。下面是一些您可以在 ARKit/SpriteKit Xcode 模板项目中添加/替换的代码来做到这一点。我们将从一些基本逻辑开始,在第三次点击时运行弹跳动画(在使用前两次点击放置 anchor 之后)。

var anchors: [ARAnchor] = []
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

// Start bouncing on touch after placing 2 anchors (don't allow more)
if anchors.count > 1 {
startBouncing(time: 1)
return
}
// Create anchor using the camera's current position
guard let sceneView = self.view as? ARSKView else { return }
if let currentFrame = sceneView.session.currentFrame {

// Create a transform with a translation of 30 cm in front of the camera
var translation = matrix_identity_float4x4
translation.columns.3.z = -0.3
let transform = simd_mul(currentFrame.camera.transform, translation)

// Add a new anchor to the session
let anchor = ARAnchor(transform: transform)
sceneView.session.add(anchor: anchor)
anchors.append(anchor)
}
}

然后,一些 SpriteKit 有趣的动画发生:
var ballNode: SKLabelNode = {
let labelNode = SKLabelNode(text: "🏀")
labelNode.horizontalAlignmentMode = .center
labelNode.verticalAlignmentMode = .center
return labelNode
}()
func startBouncing(time: TimeInterval) {
guard
let sceneView = self.view as? ARSKView,
let first = anchors.first, let start = sceneView.node(for: first),
let last = anchors.last, let end = sceneView.node(for: last)
else { return }

if ballNode.parent == nil {
addChild(ballNode)
}
ballNode.setScale(start.xScale)
ballNode.zRotation = start.zRotation
ballNode.position = start.position

let scale = SKAction.scale(to: end.xScale, duration: time)
let rotate = SKAction.rotate(toAngle: end.zRotation, duration: time)
let move = SKAction.move(to: end.position, duration: time)

let scaleBack = SKAction.scale(to: start.xScale, duration: time)
let rotateBack = SKAction.rotate(toAngle: start.zRotation, duration: time)
let moveBack = SKAction.move(to: start.position, duration: time)

let action = SKAction.repeatForever(.sequence([
.group([scale, rotate, move]),
.group([scaleBack, rotateBack, moveBack])
]))
ballNode.removeAllActions()
ballNode.run(action)
}

Here's a video所以你可以看到这个代码在运行。您会注意到这种错觉只有在您不移动相机时才有效——对于 AR 来说不是那么好。使用时 SKAction ,我们无法在制作动画时调整动画的开始/结束状态,因此球会不断在其原始(屏幕空间)位置/旋转/缩放之间来回弹跳。

您可以通过直接为球设置动画来做得更好,但这需要大量工作。您需要在每一帧(或每个 view(_:didUpdate:for:) 委托(delegate)回调)上:
  • 在动画的每一端保存基于 anchor 的节点的更新位置、旋转和缩放值。您需要每 didUpdate 执行两次此操作回调,因为每个节点都会得到一个回调。
  • 通过基于当前时间在两个端点值之间进行插值,计算出动画节点的位置、旋转和缩放值。
  • 在节点上设置新属性。 (或者可能在很短的时间内为这些属性设置动画,这样它在一帧内不会跳跃太多?)

  • 将假的 3D 幻觉硬塞进 2D 图形工具包需要大量的工作——因此我对 SpriteKit 的评论并不是进入 ARKit 的第一步。

    如果您想要为 AR 叠加层设置 3D 定位和动画,使用 3D 图形工具包会容易得多。这是上一个示例的重复,但使用 SceneKit 代替。从 ARKit/SceneKit Xcode 模板开始,取出飞船,粘贴相同的 touchesBegan函数从上面进入 ViewController . (也将 as ARSKView 转换为 as ARSCNView 。)

    然后,一些用于放置 2D 广告牌 Sprite 的快速代码,通过 SceneKit 匹配 ARKit/SpriteKit 模板的行为:
    // in global scope
    func makeBillboardNode(image: UIImage) -> SCNNode {
    let plane = SCNPlane(width: 0.1, height: 0.1)
    plane.firstMaterial!.diffuse.contents = image
    let node = SCNNode(geometry: plane)
    node.constraints = [SCNBillboardConstraint()]
    return node
    }

    // inside ViewController
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    // emoji to image based on https://stackoverflow.com/a/41021662/957768
    let billboard = makeBillboardNode(image: "⛹️".image())
    node.addChildNode(billboard)
    }

    最后,为弹跳球添加动画:
    let ballNode = makeBillboardNode(image: "🏀".image())
    func startBouncing(time: TimeInterval) {
    guard
    let sceneView = self.view as? ARSCNView,
    let first = anchors.first, let start = sceneView.node(for: first),
    let last = anchors.last, let end = sceneView.node(for: last)
    else { return }

    if ballNode.parent == nil {
    sceneView.scene.rootNode.addChildNode(ballNode)
    }

    let animation = CABasicAnimation(keyPath: #keyPath(SCNNode.transform))
    animation.fromValue = start.transform
    animation.toValue = end.transform
    animation.duration = time
    animation.autoreverses = true
    animation.repeatCount = .infinity
    ballNode.removeAllAnimations()
    ballNode.addAnimation(animation, forKey: nil)
    }

    这次动画代码比 SpriteKit 版本短很多。
    Here's how it looks in action.

    因为我们一开始是在 3D 中工作,所以我们实际上是在两个 3D 位置之间制作动画——与 SpriteKit 版本不同,动画停留在它应该的位置。 (并且没有直接插入和动画属性的额外工作。)

    关于swift - 如何以编程方式移动 ARAnchor?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44401173/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com