我使用ARKit
来显示3D对象。我设法将节点放在用户面前的真实世界(也就是相机)。但是,当我放下相机时,我无法让它们面对相机。
let tap_point=CGPoint(x: x, y: y)
let results=arscn_view.hitTest(tap_point, types: .estimatedHorizontalPlane)
guard results.count>0 else{
return
}
guard let r=results.first else{
return
}
let hit_tf=SCNMatrix4(r.worldTransform)
let new_pos=SCNVector3Make(hit_tf.m41, hit_tf.m42+Float(0.2), hit_tf.m43)
guard let scene=SCNScene(named: file_name) else{
return
}
guard let node=scene.rootNode.childNode(withName: "Mesh", recursively: true) else{
return
}
node.position=new_pos
arscn_view.scene.rootNode.addChildNode(node)
节点位于相机前面的平面上。但他们都朝着同一个方向前进。我想我应该旋转 SCNNode
,但我没有设法做到这一点。
答案 0 :(得分:6)
首先,获取相机的旋转矩阵:
this.dataSource.data.push(m as any);
然后,结合矩阵:
let rotate = simd_float4x4(SCNMatrix4MakeRotation(sceneView.session.currentFrame!.camera.eulerAngles.y, 0, 1, 0))
最后,将转换应用于您的节点,转换为SCNMatrix4:
let rotateTransform = simd_mul(r.worldTransform, rotate)
希望有所帮助
修改强>
这里是如何从simd_float4x4
创建SCNMatrix4的node.transform = SCNMatrix4(rotateTransform)
答案 1 :(得分:2)
这是我面向镜头的SCNNode的代码。希望对某人有所帮助
let location = touches.first!.location(in: sceneView)
var hitTestOptions = [SCNHitTestOption: Any]()
hitTestOptions[SCNHitTestOption.boundingBoxOnly] = true
let hitResultsFeaturePoints: [ARHitTestResult] = sceneView.hitTest(location, types: .featurePoint)
let hitTestResults = sceneView.hitTest(location)
guard let node = hitTestResults.first?.node else {
if let hit = hitResultsFeaturePoints.first {
let rotate = simd_float4x4(SCNMatrix4MakeRotation(sceneView.session.currentFrame!.camera.eulerAngles.y, 0, 1, 0))
let finalTransform = simd_mul(hit.worldTransform, rotate)
sceneView.session.add(anchor: ARAnchor(transform: finalTransform))
}
return
}
答案 2 :(得分:1)
即使相机移动,您是否希望节点始终面向相机?这就是SceneKit constraints的用途。 SCNLookAtConstraint
或SCNBillboardConstraint
可以使节点始终指向相机。
您是否希望节点在放置时面向相机,但保持静止(这样您可以移动相机并查看其背面)?有几种方法可以做到这一点。有些涉及有趣的数学,但处理它的一种更简单的方法可能就是设计3D资产,使“前”总是在正Z轴方向。根据相机变换设置放置对象的变换,其初始方向将与相机匹配。
答案 3 :(得分:1)
这是我的做法:
func faceCamera() {
guard constraints?.isEmpty ?? true else {
return
}
SCNTransaction.begin()
SCNTransaction.animationDuration = 5
SCNTransaction.completionBlock = { [weak self] in
self?.constraints = []
}
constraints = [billboardConstraint]
SCNTransaction.commit()
}
private lazy var billboardConstraint: SCNBillboardConstraint = {
let constraint = SCNBillboardConstraint()
constraint.freeAxes = [.Y]
return constraint
}()
如前所述,SCNBillboardConstraint
将使节点始终看着摄像机。我正在对其进行动画处理,因此节点不仅会立即卡入到位,这是可选的。在SCNTransaction.completionBlock
中,我删除了约束,它也是可选的。
我还设置了SCNBillboardConstraint
的{{1}},它自定义节点跟随摄像机的轴线,这也是可选的。
答案 4 :(得分:0)
我希望节点在放置时面向镜头,然后将其保留在此处(并能够移动)。 – Marie Dm 引用
您可以使用以下方法将物体面向相机:
if let rotate = sceneView.session.currentFrame?.camera.transform {
node.simdTransform = rotate
}
此代码将使您免于gimbal lock和其他麻烦。
四分量旋转矢量在前三个分量中指定旋转轴的方向,在第四个分量中指定旋转角(以弧度为单位)。默认旋转为零向量,不指定旋转。相对于节点的simdPivot属性应用旋转。
simdRotation,simdEulerAngles和simdOrientation属性都会影响节点simdTransform属性的旋转角度。这些属性之一的任何更改都会反映在其他属性中。
https://developer.apple.com/documentation/scenekit/scnnode/2881845-simdrotation https://developer.apple.com/documentation/scenekit/scnnode/2881843-simdtransform
答案 5 :(得分:0)
guard let frame = self.sceneView.session.currentFrame else {
return
}
node.eulerAngles.y = frame.camera.eulerAngles.y