ryguy8806
ryguy8806

Reputation: 125

Detecting and Using 2 Different Vertical Planes

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

Answers (0)

Related Questions