Placing an entity on a wall using Anchoring Component

We can use Anchoring Component to describe anchors that RealityKit should track.

Overview

RealityKit has AnchoringComponent which we can add like any other component. Unlike ARKit PlaneAnchor, these anchors do not contain information about the real world object they are attached to. For example, in ARKit, a PlaneAnchor contains the transform relative to the scene in world space, classification, alignment, and geometry. We won’t get any of that information from this component. Instead, RealityKit offers this simple alternative ARKit.

We start by describing the type of real world object to target. Create an instance of the component with the target, then add it to an entity.

let anchorTarget = AnchoringComponent.Target.plane(.vertical, classification: .wall, minimumBounds: [1, 1])
let anchoringComponent = AnchoringComponent(anchorTarget)
entity.components.set(anchoringComponent)

The anchor above is targeting any surface that

  • has a vertical orientation
  • is classified as a plane
  • is at least 1×1 units in size

An entity with this component is disabled and hidden until a matching anchor is detected. When a wall that matches our characteristics is found, the anchor is added to the scene. RealityKit will enable the entity and place it on a point somewhere† on the wall.

Aside from simplicity, another benefit of this approach is that we don’t need to prompt for permission to use spatial tracking/ARKit. If all we need is to place something on a wall, floor, desk, etc. then this component is an option. If we need to access the transform of the anchor, or add the anchor content to our physics system, then we’ll need to use Spatial Tracking Session. More on that later.

Personally, I haven’t come across many use cases when these anchors are sufficient. Most of the time, the requirements for my projects demand more precise placement and control. Still, it’s nice to have the option.

Video Demo

Example Code

struct Example076: View {
    var body: some View {
        RealityView { content in

            // Load the asset that we'll use to render the portal
            guard let scene = try? await Entity(named: "PortalFrame", in: realityKitContentBundle) else { return }
            content.add(scene)

            // Load the scene that will serve as the content for the portal
            guard let portalContent = try? await Entity(named: "PortalFrameContent", in: realityKitContentBundle) else { return }
            portalContent.components.set(WorldComponent())
            scene.addChild(portalContent)

            // Get the frame entity
            guard let frame = scene.findEntity(named: "picture_frame_02") else { return }

            // Create an anchor target and AnchoringComponent. Add the component to the frame entity
            let anchorTarget = AnchoringComponent.Target.plane(.vertical, classification: .wall, minimumBounds: [1, 1])
            let anchoringComponent = AnchoringComponent(anchorTarget)
            frame.components.set(anchoringComponent)

            // Rotate the frame to align with the wall
            frame.setOrientation(.init(angle: .pi / 2, axis: [-1, 0, 0]), relativeTo: nil)

            // Set up the portal
            guard let portalEntity = scene.findEntity(named: "portal_entity") else { return }
            portalEntity.components[ModelComponent.self]?.materials[0] = PortalMaterial()
            portalEntity.components.set(PortalComponent(target: portalContent))

        }
    }
}

† note on placement: We do not get to control where on a given plane this entity is placed. Instead, RealityKit seems to make a “best guess” based on the size and shape of the anchor, and the users head orientation at the moment the anchor is placed.

Support our work so we can continue to bring you new examples and articles.

Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Questions or feedback?