如何将我自己的 Reality Composer 场景加载到 RealityKit 中?
How do I load my own Reality Composer scene into RealityKit?
我在 Experience.rcproject
文件中创建了 3 个“场景”,它们是在您使用 xcode 开始新的增强现实项目时创建的。
经常为 3D 工作,我会说这些是场景中的 3 个对象,但在 Experience.rcproject
中我添加了 3 个“场景”。每一个内部都有相同的 3D 模型。第一个附加到水平面,第二个附加到垂直面,第三个附加到图像。
我是第一次使用 Reality Kit 并一路学习。
我这样做的想法是,当我想将它附加到水平、垂直或图像时加载正确的对象。
我就是这样完成的。
我修改了 Apple 提供的 Experience.swift
文件以接受场景名称,如下所示:
public static func loadBox(namedFile:String) throws -> Experience.Box {
guard let realityFileURL = Foundation.Bundle(for: Experience.Box.self).url(forResource: "Experience", withExtension: "reality") else {
throw Experience.LoadRealityFileError.fileNotFound("Experience.reality")
}
let realityFileSceneURL = realityFileURL.appendingPathComponent(namedFile, isDirectory: false)
let anchorEntity = try Experience.Box.loadAnchor(contentsOf: realityFileSceneURL)
return createBox(from: anchorEntity)
}
我称这条线为
let entity = try! Experience.loadBox(namedFile:sceneName)
任何我想要的,但我必须使用这个代码:
// I have to keep a reference to the entity so I can remove it from its parent and nil
currentEntity?.removeFromParent()
currentEntity = nil
// I have to load the entity again, now with another name
let entity = try! Experience.loadBox(namedFile:sceneName)
// store a reference to it, so I can remove it in the future
currentEntity = entity
// remove the old one from the scene
arView.scene.anchors.removeAll()
// add the new one
arView.scene.anchors.append(entity)
这段代码很愚蠢,我相信有更好的方法。
有什么想法吗?
RealityKit/Reality Composer 中的层次结构
我认为这是一个“理论”问题而不是实际问题。首先,我应该说编辑 Experience
包含带有锚点和实体的场景的文件不是个好主意。
在 RealityKit 和 Reality Composer 中,如果您在默认场景中创建单个对象,则有非常明确的层次结构:
Scene –> AnchorEntity -> ModelEntity
|
Physics
|
Animation
|
Audio
如果您将两个 3D 模型放在一个场景中,它们共享同一个锚点:
Scene –> AnchorEntity – – – -> – – – – – – – – ->
| |
ModelEntity01 ModelEntity02
| |
Physics Physics
| |
Animation Animation
| |
Audio Audio
RealityKit 中的 AnchorEntity
定义当前 ARSession
中 World Tracking
配置的哪些属性 运行:horizontal
/vertical
平面检测 and/or image detection
, and/or body detection
, 等等
让我们看看那些参数:
AnchorEntity(.plane(.horizontal, classification: .floor, minimumBounds: [1, 1]))
AnchorEntity(.plane(.vertical, classification: .wall, minimumBounds: [0.5, 0.5]))
AnchorEntity(.image(group: "Group", name: "model"))
在这里您可以阅读 Entity-Component-System 范式。
合并来自 Reality Composer 的两个场景
为此 post 我在 Reality Composer 中准备了两个场景 - 第一个场景 (ConeAndBox
) 具有水平面检测,第二个场景 (Sphere
) 具有垂直面检测平面检测。如果您将 RealityKit 中的这些场景组合成一个更大的场景,您将获得两种类型的平面检测——水平和垂直。
在此场景中,两个圆锥体和盒子固定到一个锚点。
在 RealityKit 中,我可以将这些场景组合成一个场景。
// Plane Detection with a Horizontal anchor
let coneAndBoxAnchor = try! Experience.loadConeAndBox()
coneAndBoxAnchor.children[0].anchor?.scale = [7, 7, 7]
coneAndBoxAnchor.goldenCone!.position.y = -0.1 //.children[0].children[0].children[0]
arView.scene.anchors.append(coneAndBoxAnchor)
coneAndBoxAnchor.name = "mySCENE"
coneAndBoxAnchor.children[0].name = "myANCHOR"
coneAndBoxAnchor.children[0].children[0].name = "myENTITIES"
print(coneAndBoxAnchor)
// Plane Detection with a Vertical anchor
let sphereAnchor = try! Experience.loadSphere()
sphereAnchor.steelSphere!.scale = [7, 7, 7]
arView.scene.anchors.append(sphereAnchor)
print(sphereAnchor)
在 Xcode 的控制台中,您可以看到 ConeAndBox
场景层次结构,其名称在 RealityKit 中给出:
您可以看到 Sphere
没有给出名称的场景层次结构:
请务必注意,我们的组合场景现在在一个数组中包含两个场景。使用以下命令打印此数组:
print(arView.scene.anchors)
它打印:
[ 'mySCENE' : ConeAndBox, '' : Sphere ]
您可以通过 AnchoringComponent
重新分配一种跟踪类型(您可以分配图像检测而不是平面检测):
coneAndBoxAnchor.children[0].anchor!.anchoring = AnchoringComponent(.image(group: "AR Resources",
name: "planets"))
正在检索实体并将它们连接到新的 AnchorEntity
对于 decomposing/reassembling 场景的层次结构,您需要检索所有实体并将它们固定到单个锚点。考虑到 - 跟踪一个锚点的任务强度低于跟踪多个锚点。并且一个 anchor 比例如 20 个 anchor 更稳定——就场景模型的相对位置而言。
let coneEntity = coneAndBoxAnchor.goldenCone!
coneEntity.position.x = -0.2
let boxEntity = coneAndBoxAnchor.plasticBox!
boxEntity.position.x = 0.01
let sphereEntity = sphereAnchor.steelSphere!
sphereEntity.position.x = 0.2
let anchor = AnchorEntity(.image(group: "AR Resources", name: "planets")
anchor.addChild(coneEntity)
anchor.addChild(boxEntity)
anchor.addChild(sphereEntity)
arView.scene.anchors.append(anchor)
有用的链接
现在您对如何构建场景并从这些场景中检索实体有了更深入的了解。如果您需要其他示例,请查看 THIS POST and .
P.S.
显示如何从 ExperienceX.rcproject
上传场景的附加代码:
import ARKit
import RealityKit
class ViewController: UIViewController {
@IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
// RC generated "loadGround()" method automatically
let groundArrowAnchor = try! ExperienceX.loadGround()
groundArrowAnchor.arrowFloor!.scale = [2,2,2]
arView.scene.anchors.append(groundArrowAnchor)
print(groundArrowAnchor)
}
}
我在 Experience.rcproject
文件中创建了 3 个“场景”,它们是在您使用 xcode 开始新的增强现实项目时创建的。
经常为 3D 工作,我会说这些是场景中的 3 个对象,但在 Experience.rcproject
中我添加了 3 个“场景”。每一个内部都有相同的 3D 模型。第一个附加到水平面,第二个附加到垂直面,第三个附加到图像。
我是第一次使用 Reality Kit 并一路学习。
我这样做的想法是,当我想将它附加到水平、垂直或图像时加载正确的对象。
我就是这样完成的。
我修改了 Apple 提供的 Experience.swift
文件以接受场景名称,如下所示:
public static func loadBox(namedFile:String) throws -> Experience.Box {
guard let realityFileURL = Foundation.Bundle(for: Experience.Box.self).url(forResource: "Experience", withExtension: "reality") else {
throw Experience.LoadRealityFileError.fileNotFound("Experience.reality")
}
let realityFileSceneURL = realityFileURL.appendingPathComponent(namedFile, isDirectory: false)
let anchorEntity = try Experience.Box.loadAnchor(contentsOf: realityFileSceneURL)
return createBox(from: anchorEntity)
}
我称这条线为
let entity = try! Experience.loadBox(namedFile:sceneName)
任何我想要的,但我必须使用这个代码:
// I have to keep a reference to the entity so I can remove it from its parent and nil
currentEntity?.removeFromParent()
currentEntity = nil
// I have to load the entity again, now with another name
let entity = try! Experience.loadBox(namedFile:sceneName)
// store a reference to it, so I can remove it in the future
currentEntity = entity
// remove the old one from the scene
arView.scene.anchors.removeAll()
// add the new one
arView.scene.anchors.append(entity)
这段代码很愚蠢,我相信有更好的方法。
有什么想法吗?
RealityKit/Reality Composer 中的层次结构
我认为这是一个“理论”问题而不是实际问题。首先,我应该说编辑 Experience
包含带有锚点和实体的场景的文件不是个好主意。
在 RealityKit 和 Reality Composer 中,如果您在默认场景中创建单个对象,则有非常明确的层次结构:
Scene –> AnchorEntity -> ModelEntity
|
Physics
|
Animation
|
Audio
如果您将两个 3D 模型放在一个场景中,它们共享同一个锚点:
Scene –> AnchorEntity – – – -> – – – – – – – – ->
| |
ModelEntity01 ModelEntity02
| |
Physics Physics
| |
Animation Animation
| |
Audio Audio
RealityKit 中的 AnchorEntity
定义当前 ARSession
中 World Tracking
配置的哪些属性 运行:horizontal
/vertical
平面检测 and/or image detection
, and/or body detection
, 等等
让我们看看那些参数:
AnchorEntity(.plane(.horizontal, classification: .floor, minimumBounds: [1, 1]))
AnchorEntity(.plane(.vertical, classification: .wall, minimumBounds: [0.5, 0.5]))
AnchorEntity(.image(group: "Group", name: "model"))
在这里您可以阅读 Entity-Component-System 范式。
合并来自 Reality Composer 的两个场景
为此 post 我在 Reality Composer 中准备了两个场景 - 第一个场景 (ConeAndBox
) 具有水平面检测,第二个场景 (Sphere
) 具有垂直面检测平面检测。如果您将 RealityKit 中的这些场景组合成一个更大的场景,您将获得两种类型的平面检测——水平和垂直。
在此场景中,两个圆锥体和盒子固定到一个锚点。
在 RealityKit 中,我可以将这些场景组合成一个场景。
// Plane Detection with a Horizontal anchor
let coneAndBoxAnchor = try! Experience.loadConeAndBox()
coneAndBoxAnchor.children[0].anchor?.scale = [7, 7, 7]
coneAndBoxAnchor.goldenCone!.position.y = -0.1 //.children[0].children[0].children[0]
arView.scene.anchors.append(coneAndBoxAnchor)
coneAndBoxAnchor.name = "mySCENE"
coneAndBoxAnchor.children[0].name = "myANCHOR"
coneAndBoxAnchor.children[0].children[0].name = "myENTITIES"
print(coneAndBoxAnchor)
// Plane Detection with a Vertical anchor
let sphereAnchor = try! Experience.loadSphere()
sphereAnchor.steelSphere!.scale = [7, 7, 7]
arView.scene.anchors.append(sphereAnchor)
print(sphereAnchor)
在 Xcode 的控制台中,您可以看到 ConeAndBox
场景层次结构,其名称在 RealityKit 中给出:
您可以看到 Sphere
没有给出名称的场景层次结构:
请务必注意,我们的组合场景现在在一个数组中包含两个场景。使用以下命令打印此数组:
print(arView.scene.anchors)
它打印:
[ 'mySCENE' : ConeAndBox, '' : Sphere ]
您可以通过 AnchoringComponent
重新分配一种跟踪类型(您可以分配图像检测而不是平面检测):
coneAndBoxAnchor.children[0].anchor!.anchoring = AnchoringComponent(.image(group: "AR Resources",
name: "planets"))
正在检索实体并将它们连接到新的 AnchorEntity
对于 decomposing/reassembling 场景的层次结构,您需要检索所有实体并将它们固定到单个锚点。考虑到 - 跟踪一个锚点的任务强度低于跟踪多个锚点。并且一个 anchor 比例如 20 个 anchor 更稳定——就场景模型的相对位置而言。
let coneEntity = coneAndBoxAnchor.goldenCone!
coneEntity.position.x = -0.2
let boxEntity = coneAndBoxAnchor.plasticBox!
boxEntity.position.x = 0.01
let sphereEntity = sphereAnchor.steelSphere!
sphereEntity.position.x = 0.2
let anchor = AnchorEntity(.image(group: "AR Resources", name: "planets")
anchor.addChild(coneEntity)
anchor.addChild(boxEntity)
anchor.addChild(sphereEntity)
arView.scene.anchors.append(anchor)
有用的链接
现在您对如何构建场景并从这些场景中检索实体有了更深入的了解。如果您需要其他示例,请查看 THIS POST and
P.S.
显示如何从 ExperienceX.rcproject
上传场景的附加代码:
import ARKit
import RealityKit
class ViewController: UIViewController {
@IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
// RC generated "loadGround()" method automatically
let groundArrowAnchor = try! ExperienceX.loadGround()
groundArrowAnchor.arrowFloor!.scale = [2,2,2]
arView.scene.anchors.append(groundArrowAnchor)
print(groundArrowAnchor)
}
}