Reputation: 125
I am trying to make an interior scene with RealityKit/ARKit. I have a window, which cycles through different scenes, and a fireplace, with crackling fire in it.
I need them to fall on different walls, but when the scene initializes, the anchors both attach to the same wall.
I need to know if this is possible, and what the best way possible to do this is.
import SwiftUI
import RealityKit
import RealityKitContent
struct MeditationView: View {
//Objects in Space
@State private var window = Entity()
@State private var button = Entity()
@State private var fireplace = Entity()
//Window View objects
@State private var world1 = Entity()
@State private var world2 = Entity()
@State private var world3 = Entity()
@State private var world4 = Entity()
@State private var anchor1 = Entity()
@State private var anchor2 = Entity()
@State private var anchor3 = Entity()
@State private var anchor4 = Entity()
@State private var windowView:Int = 1
var body: some View {
RealityView { content in
let wallAnchor1 = AnchorEntity(.plane(.vertical, classification: .wall, minimumBounds: [0.7, 0.5]), trackingMode: .once)
content.add(wallAnchor1)
let wallAnchor2 = AnchorEntity(.plane(.vertical, classification: .wall, minimumBounds: [0.7, 0.5]), trackingMode: .once)
content.add(wallAnchor2)
let floorAnchor = AnchorEntity(.plane(.horizontal, classification: .floor, minimumBounds: [0.5, 0.5]))
content.add(floorAnchor)
if let windowScene = try? await Entity(named: "WindowScene", in: realityKitContentBundle) {
content.add(windowScene)
guard let window = windowScene.findEntity(named: "Window") else {
fatalError()
}
guard let windowButton = windowScene.findEntity(named: "WindowButton") else {
fatalError()
}
guard let fireplace = windowScene.findEntity(named: "Fireplace") else {
fatalError()
}
self.fireplace = fireplace
wallAnchor2.addChild(fireplace, preservingWorldTransform: false)
fireplace.transform.rotation = simd_quatf(angle: -.pi/2, axis: [1, 0, 0])
fireplace.position.y = floorAnchor.position.x - 0.15
fireplace.position.x = -0.2
guard let audioResource = try? AudioFileResource.load(
named: "/Root/Fireplace/Ambiance_Firecamp_Small_Loop_Mono_wav",
from: "WindowScene.usda",
in: realityKitContentBundle) else {
print("Unable to find fire audio file.")
return
}
fireplace.playAudio(audioResource)
self.button = windowButton
floorAnchor.addChild(windowButton)
self.window = window
wallAnchor1.addChild(window, preservingWorldTransform: false)
window.transform.scale = [2, 2, 2]
window.position = wallAnchor1.position
window.position.y = floorAnchor.position.x + 0.25
window.transform.rotation = simd_quatf(angle: -.pi/2, axis: [1, 0, 0])
let worlds = await createWorlds()
content.add(worlds)
let portals = createPortals()
content.add(portals)
await addContentToWorlds()
guard let button = windowButton.findEntity(named: "Button") else {
fatalError()
}
self.button = button
}
}.gesture(SpatialTapGesture().targetedToEntity(button).onEnded({value in
changeWindowView(number: windowView)
}))
}
func createWorlds() async -> Entity {
let worlds = Entity()
//Make world 1
world1 = Entity()
world1.components.set(WorldComponent())
let skybox1 = await createSkyboxEntity(texture: "skybox1")
world1.addChild(skybox1)
worlds.addChild(world1)
//Make world 2
world2 = Entity()
world2.components.set(WorldComponent())
let skybox2 = await createSkyboxEntity(texture: "skybox2")
world2.addChild(skybox2)
worlds.addChild(world2)
//Make world 3
world3 = Entity()
world3.components.set(WorldComponent())
let skybox3 = await createSkyboxEntity(texture: "skybox3")
world3.addChild(skybox3)
worlds.addChild(world3)
//Make world 4
world4 = Entity()
world4.components.set(WorldComponent())
let skybox4 = await createSkyboxEntity(texture: "skybox4")
world4.addChild(skybox4)
worlds.addChild(world4)
return worlds
}
func createPortals() -> Entity {
/// Create 4 portals
let portals = Entity()
let world1Portal = createPortal(target: world1)
portals.addChild(world1Portal)
guard let anchorPortal1 = window.findEntity(named: "Anchor1") else {
fatalError("Cannot find portal anchor")
}
anchorPortal1.addChild(world1Portal)
self.anchor1 = anchorPortal1
anchorPortal1.transform.scale = [2, 1, 1]
world1Portal.transform.rotation = simd_quatf(angle: .pi/2, axis: [1, 0, 0])
let world2Portal = createPortal(target: world2)
portals.addChild(world2Portal)
guard let anchorPortal2 = window.findEntity(named: "Anchor2") else {
fatalError("Cannot find portal anchor")
}
self.anchor2 = anchorPortal2
anchorPortal2.addChild(world2Portal)
anchorPortal2.transform.scale = [2, 1, 1]
world2Portal.transform.rotation = simd_quatf(angle: .pi/2, axis: [1, 0, 0])
let world3Portal = createPortal(target: world3)
portals.addChild(world3Portal)
guard let anchorPortal3 = window.findEntity(named: "Anchor3") else {
fatalError("Cannot find portal anchor")
}
self.anchor3 = anchorPortal3
anchorPortal3.addChild(world3Portal)
anchorPortal3.transform.scale = [2, 1, 1]
world3Portal.transform.rotation = simd_quatf(angle: .pi/2, axis: [1, 0, 0])
let world4Portal = createPortal(target: world4)
portals.addChild(world4Portal)
guard let anchorPortal4 = window.findEntity(named: "Anchor4") else {
fatalError("Cannot find portal anchor")
}
self.anchor4 = anchorPortal4
anchorPortal4.addChild(world4Portal)
anchorPortal4.transform.scale = [2, 1, 1]
world4Portal.transform.rotation = simd_quatf(angle: .pi/2, axis: [1, 0, 0])
return portals
}
func addContentToWorlds() async {
// Add more content to the worlds
if let world1Scene = try? await Entity(named: "World1Scene", in: realityKitContentBundle) {
world1Scene.position = [0, 3, 0]
world1.addChild(world1Scene)
}
if let world2Scene = try? await Entity(named: "World2Scene", in: realityKitContentBundle) {
world2Scene.position = [0, 3, 0]
world2.addChild(world2Scene)
}
if let world3Scene = try? await Entity(named: "World3Scene", in: realityKitContentBundle) {
world3Scene.position = [0, 3, 0]
world3.addChild(world3Scene)
}
if let world4Scene = try? await Entity(named: "World4Scene", in: realityKitContentBundle) {
world4Scene.position = [0, 3, 0]
world4.addChild(world4Scene)
}
}
func createSkyboxEntity(texture: String) async -> Entity {
guard let resource = try? await TextureResource(named: texture) else {
fatalError("Unable to load skybox image")
}
var material = UnlitMaterial()
material.color = .init(texture: .init(resource))
let entity = Entity()
entity.components.set(ModelComponent(mesh: .generateSphere(radius: 1000), materials: [material]))
entity.scale *= .init(x: -1, y: 1, z: 1)
return entity
}
func createPortal(target: Entity) -> Entity {
let portalMesh = MeshResource.generatePlane(width: 1, depth: 1)
let portal = ModelEntity(mesh: portalMesh, materials: [PortalMaterial()])
portal.components.set(PortalComponent(target: target))
return portal
}
func changeWindowView(number: Int) {
anchor1.isEnabled = false
anchor2.isEnabled = false
anchor3.isEnabled = false
anchor4.isEnabled = false
switch number {
case 1:
anchor1.isEnabled = true
windowView = 2
return
case 2:
anchor2.isEnabled = true
windowView = 3
return
case 3:
anchor3.isEnabled = true
windowView = 4
return
case 4:
anchor4.isEnabled = true
windowView = 1
return
default:
return
}
}
}
My window works just fine, I just need to know how I can make the fireplace and the window appear on different walls, and not overlap each other.
Thank you in advance!
Upvotes: 0
Views: 27