定位ARKIT模型
Positioning ARKIT model
我在屏幕上定位模型时遇到一些问题。模型出现了,但它出现在我上方而不是在我面前。理想情况下,我希望模型出现在它被点击的地方。请帮忙!
此函数成功从 AWS 下载模型:
private func dowloadModel(){
let url = URL(string: "url_string")!
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error{
print(error.localizedDescription)
return
}
if let data = data{
print(data)
let documentDirectories = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let documentDirectory = documentDirectories.first{
let fileURL = documentDirectory.appendingPathComponent("Food.scn")
let dataNS : NSData? = data as NSData
try! dataNS?.write(to: fileURL, options: .atomic)
print("Saved!")
}
}
}.resume()
}
这里我将模型渲染到屏幕上:
private func registerGestureRecogniser(){
print("Tapped")
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
self.sceneView.addGestureRecognizer(tapGestureRecognizer)
}
这里是点击函数:
@objc func handleTap(gesture: UITapGestureRecognizer) {
let documentDirectories = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let documentDirectory = documentDirectories.first{
let fileURL = documentDirectory.appendingPathComponent("Food.scn")
do{
let scene = try SCNScene(url: fileURL, options: nil)
let node = scene.rootNode.childNode(withName: "Burger", recursively: true)!
node.position = SCNVector3Make(0, 0, 0);
self.sceneView.scene.rootNode.addChildNode(node)
}
catch{
print(error)
}
}
}
我也收到错误:
Error: Failed to load <C3DImage
当你
node.position = SCNVector3Make(0, 0, 0);
self.sceneView.scene.rootNode.addChildNode(node)
您正在将模型节点定位在场景的根节点上,其位置在场景启动时由 ARKit 确定。
如果你想让模型出现在摄像头前面,那么你需要抓取摄像头变换(session.currentFrame?.camera.transform
),修改-z
组件,并将其设置为节点的位置.或者,如果您想将模型放置在表面上,请进行光线投射并使用 raycastResult
simdWorldPosition
作为节点的 simdWorldPosition
.
周围肯定有raycast
的例子,但简而言之,你首先需要定义一个查询:
let bounds = sceneView.bounds
let screenCenter = CGPoint(x: bounds.midX, y: bounds.midY)
let query = sceneView.raycastQuery(from: screenCenter, allowing: .estimatedPlane, alignment: .horizontal)
以上定义了从屏幕中心延伸并仅找到水平表面的光线投射。请浏览 docs 以获取有关 allowing
和 alignment
选项的更多信息。
然后您可以使用 session
投射光线:
session.raycast(query)
这将 return 一个 ARRaycastResult
的数组。您可以检查它们并根据需要进行选择,但我通常只选择 .first
个(注意:它可以为空)。
然后您可能想要获取 raycastResult
转换的翻译组件并将其分配为节点的 simdWorldPosition
。请注意,您可以将整个变换分配给节点 simdWorldTransform
但这也会改变节点的方向,您可能想要也可能不想这样做。
if let raycastResult = session.raycast(query).first {
node.simdWorldPosition = raycastResult.worldTransform.translation
}
哦,另外,我发现这个小扩展很方便:
extension float4x4 {
/**
Treats matrix as a (right-hand column-major convention) transform matrix
and factors out the translation component of the transform.
*/
var translation: SIMD3<Float> {
let translation = columns.3
return SIMD3<Float>(translation.x, translation.y, translation.z)
}
}
它允许您在上面的代码中执行 worldTransform.translation
。
我在屏幕上定位模型时遇到一些问题。模型出现了,但它出现在我上方而不是在我面前。理想情况下,我希望模型出现在它被点击的地方。请帮忙!
此函数成功从 AWS 下载模型:
private func dowloadModel(){
let url = URL(string: "url_string")!
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error{
print(error.localizedDescription)
return
}
if let data = data{
print(data)
let documentDirectories = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let documentDirectory = documentDirectories.first{
let fileURL = documentDirectory.appendingPathComponent("Food.scn")
let dataNS : NSData? = data as NSData
try! dataNS?.write(to: fileURL, options: .atomic)
print("Saved!")
}
}
}.resume()
}
这里我将模型渲染到屏幕上:
private func registerGestureRecogniser(){
print("Tapped")
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
self.sceneView.addGestureRecognizer(tapGestureRecognizer)
}
这里是点击函数:
@objc func handleTap(gesture: UITapGestureRecognizer) {
let documentDirectories = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let documentDirectory = documentDirectories.first{
let fileURL = documentDirectory.appendingPathComponent("Food.scn")
do{
let scene = try SCNScene(url: fileURL, options: nil)
let node = scene.rootNode.childNode(withName: "Burger", recursively: true)!
node.position = SCNVector3Make(0, 0, 0);
self.sceneView.scene.rootNode.addChildNode(node)
}
catch{
print(error)
}
}
}
我也收到错误:
Error: Failed to load <C3DImage
当你
node.position = SCNVector3Make(0, 0, 0);
self.sceneView.scene.rootNode.addChildNode(node)
您正在将模型节点定位在场景的根节点上,其位置在场景启动时由 ARKit 确定。
如果你想让模型出现在摄像头前面,那么你需要抓取摄像头变换(session.currentFrame?.camera.transform
),修改-z
组件,并将其设置为节点的位置.或者,如果您想将模型放置在表面上,请进行光线投射并使用 raycastResult
simdWorldPosition
作为节点的 simdWorldPosition
.
周围肯定有raycast
的例子,但简而言之,你首先需要定义一个查询:
let bounds = sceneView.bounds
let screenCenter = CGPoint(x: bounds.midX, y: bounds.midY)
let query = sceneView.raycastQuery(from: screenCenter, allowing: .estimatedPlane, alignment: .horizontal)
以上定义了从屏幕中心延伸并仅找到水平表面的光线投射。请浏览 docs 以获取有关 allowing
和 alignment
选项的更多信息。
然后您可以使用 session
投射光线:
session.raycast(query)
这将 return 一个 ARRaycastResult
的数组。您可以检查它们并根据需要进行选择,但我通常只选择 .first
个(注意:它可以为空)。
然后您可能想要获取 raycastResult
转换的翻译组件并将其分配为节点的 simdWorldPosition
。请注意,您可以将整个变换分配给节点 simdWorldTransform
但这也会改变节点的方向,您可能想要也可能不想这样做。
if let raycastResult = session.raycast(query).first {
node.simdWorldPosition = raycastResult.worldTransform.translation
}
哦,另外,我发现这个小扩展很方便:
extension float4x4 {
/**
Treats matrix as a (right-hand column-major convention) transform matrix
and factors out the translation component of the transform.
*/
var translation: SIMD3<Float> {
let translation = columns.3
return SIMD3<Float>(translation.x, translation.y, translation.z)
}
}
它允许您在上面的代码中执行 worldTransform.translation
。