tommy0607
tommy0607

Reputation: 13

visionOS Portal not show when is child of AnchorEntity

I just follow the WWDC sessions about realitykit(session url), and make a portal to a seperate world, which is child of a AnchorEntity finding for a vertical wall. But the portal Entity not shows, and the sun Entity shows, do my code has some mistakes? The code is as follows:

struct ImmersiveView: View {
    var addToAnchor = true
    var body: some View {
        RealityView { content in
            let world = makeWorld()
            let portal = makePortal(world)
            content.add(world)
            let anchor = AnchorEntity(.plane(.vertical, classification: .wall,
                                             minimumBounds: [1, 1]))
            content.add(anchor)
            content.subscribe(to: SceneEvents.AnchoredStateChanged.self, on: anchor, componentType: nil) { event in
                print("AnchoredStateChanged")
            }
            // the portal not shows
            anchor.addChild(portal)
            let sun = try! await Entity(named: "Sun", in: realityKitContentBundle)
            // the sun shows
            anchor.addChild(sun)
        }
    }
    
    @MainActor
    func makeWorld() -> Entity {
        let world = Entity()
        world.components[WorldComponent.self] = .init()
        let earth = try! Entity.load(named: "Earth", in: realityKitContentBundle)
        let sun = try! Entity.load(named: "Sun", in: realityKitContentBundle)
        earth.position = .init(x: -0.5, y: 1.5, z: -2)
        sun.position = .init(x: 0.5, y: 1.5, z: -2)
        world.addChild(earth)
        world.addChild(sun)
        
        let resource = try! TextureResource.load(named: "Starfield")
        var material = UnlitMaterial()
        material.color = .init(texture: .init(resource))
        // Attach the material to a large sphere.
        let background = Entity()
        background.components.set(ModelComponent(
            mesh: .generateSphere(radius: 1000),
            materials: [material]
        ))
        // Ensure the texture image points inward at the viewer.
        background.scale *= .init(x: -1, y: 1, z: 1)
        //world.addChild(background)
        return world
    }
    
    @MainActor
    func makePortal(_ world: Entity) -> Entity {
        let portal = Entity()
        portal.components[ModelComponent.self] = .init(mesh: .generatePlane(width: 1, 
                                                                            height: 1, 
                                                                            cornerRadius: 0.5),
                                                       materials: [PortalMaterial()])
        portal.components[PortalComponent.self] = .init(target: world)
        return portal
    }
}

I also tried to put the portal directly in space, and it shows perfectly: Picture

Upvotes: 1

Views: 568

Answers (1)

Andy Jazz
Andy Jazz

Reputation: 58553

It's not an anchoring problem. Your code works fine. All you have to do is to rotate the portal 90 degrees clockwise around the X-axis, because the portal faces down: that's why you didn't see it on the screen (in RealityKit materials are single-sided, rather than double-sided as in SceneKit). Besides, I slightly fixed your code, so that all objects were clearly visible. Alternatively, if you don't want to rotate your portal, use the .generatePlane(width:depth:) method instead.

(rkcb is realityKitContentBundle here)

enter image description here

When a vertical plane is detected, an anchor with the positive Z-axis pointing down is placed in the scene (imagine that the entity is rotated around the X-axis by 90 degrees CCW). Anchor's parental transform is passed to the portal entity. The width (X) and height (Y) of the generated portal plane fully correspond to XY-plane of the anchor on the wall. To compensate for the portal's orientation, a 90-degree clockwise X-rotation is required.

import SwiftUI
import RealityKit
import RealityKitContent

struct ImmersiveView : View {
    var body: some View {
        RealityView { content in
            let world = makeWorld()
            let portal = makePortal(world)
            let anchor = AnchorEntity(.plane(.vertical,
                              classification: .wall,
                               minimumBounds: [1, 1]))
            anchor.addChild(portal)
            content.add(world)
            content.add(anchor)
            let _ = content.subscribe(to: SceneEvents.AnchoredStateChanged.self, 
                                      on: anchor) { event in
                print("Anchored State Changed")
            }
        }
    }

    @MainActor func makePortal(_ world: Entity) -> Entity {
        let portal = Entity()

        portal.orientation = simd_quatf(angle: -.pi/2, axis: [1,0,0]) // rotate CW

        portal.components[ModelComponent.self] = .init(mesh: .generatePlane(
                                                       width: 3, 
                                                      height: 3, 
                                                cornerRadius: 1.5),
                                                  materials: [PortalMaterial()])
        portal.components[PortalComponent.self] = .init(target: world)
        return portal
    }
    
    @MainActor func makeWorld() -> Entity {
        let world = Entity()
        world.components[WorldComponent.self] = .init()
        let earth = try! Entity.load(named: "Earth", in: rkcb)
        let sun = try! Entity.load(named: "Sun", in: rkcb)
        earth.scale *= 3
        sun.scale *= 3
        earth.position = .init(x: -0.5, y: 1.5, z: -3)
        sun.position = .init(x: 0.5, y: 1.5, z: -3)
        world.addChild(earth)
        world.addChild(sun)
        
        let resource = try! TextureResource.load(named: "Starfield")
        var material = UnlitMaterial()
        material.color = .init(texture: .init(resource))
        let background = Entity()
        background.components.set(ModelComponent(
                                            mesh: .generateSphere(radius: 1000),
                                       materials: [material]))
        background.scale.x *= -1
        world.addChild(background)
        return world
    }
}

To see anchor's orientation, turn on Anchoring in Debug Visualizations menu:

enter image description here

enter image description here

Upvotes: 0

Related Questions