Spatial SwiftUI: Volume Ornaments

Ornaments on Volumes work much like Ornaments on Windows. Volumes have more anchors and a feature to reorient them when them when a user moves around the volume.

Overview

Volumes have the same anchor points that we saw on windows. Volumes also have anchors for the front and back.

It helps to think of these as three collections of anchors on three planes.

  1. Front: TopLeadingFront, TopFront, TopTrailingFront and so on…
  2. Standard / window: Leading, Center, Trailing, and so on…
  3. Back: BackLeadingFront, BackFront, BackTrailingFront and so on…

The back anchors are particularly useful. We can design our volumes with controls and information at the back while our 3D content takes center stage.

When a user moves around a volume any ornaments will re-orient and reposition based on the users viewpoint. This means the ornaments will always appear in the same formation relative to each other, instead of relative to the content. We’ll look at a way to customize this behavior in the future.

Full Example Code

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

            // Load a scene from the bundle
            if let scene = try? await Entity(named: "GestureLabs", in: realityKitContentBundle) {

                content.add(scene)
                scene.position.y = -0.4

            }

        }
        .ornament(attachmentAnchor: .scene(.bottom)) {
            Example043Label(title: "Bottom")
        }
        .ornament(attachmentAnchor: .scene(.bottomBack)) {
            Example043Label(title: "BottomBack")
        }
        .ornament(attachmentAnchor: .scene(.bottomFront)) {
            Example043Label(title: "BottomFront")
        }
        .ornament(attachmentAnchor: .scene(.bottomLeading)) {
            Example043Label(title: "BottomLeading")
        }
        .ornament(attachmentAnchor: .scene(.bottomTrailing)) {
            Example043Label(title: "BottomTrailing")
        }
        .ornament(attachmentAnchor: .scene(.bottomFront)) {
            Example043Label(title: "BottomFront")
        }
        .ornament(attachmentAnchor: .scene(.bottomLeadingBack)) {
            Example043Label(title: "BottomLeadingBack")
        }
        .ornament(attachmentAnchor: .scene(.bottomLeadingFront)) {
            Example043Label(title: "BottomLeadingFront")
        }
        .ornament(attachmentAnchor: .scene(.bottomTrailingBack)) {
            Example043Label(title: "BottomTrailingBack")
        }
        .ornament(attachmentAnchor: .scene(.bottomTrailingFront)) {
            Example043Label(title: "BottomTrailingFront")
        }
        .ornament(attachmentAnchor: .scene(.top)) {
            Example043Label(title: "Top")
        }
        .ornament(attachmentAnchor: .scene(.topBack)) {
            Example043Label(title: "TopBack")
        }
        .ornament(attachmentAnchor: .scene(.topFront)) {
            Example043Label(title: "TopFront")
        }
        .ornament(attachmentAnchor: .scene(.topLeading)) {
            Example043Label(title: "TopLeading")
        }
        .ornament(attachmentAnchor: .scene(.topTrailing)) {
            Example043Label(title: "TopTrailing")
        }
        .ornament(attachmentAnchor: .scene(.topFront)) {
            Example043Label(title: "TopFront")
        }
        .ornament(attachmentAnchor: .scene(.topLeadingBack)) {
            Example043Label(title: "TopLeadingBack")
        }
        .ornament(attachmentAnchor: .scene(.topLeadingFront)) {
            Example043Label(title: "TopLeadingFront")
        }
        .ornament(attachmentAnchor: .scene(.topTrailingBack)) {
            Example043Label(title: "TopTrailingBack")
        }
        .ornament(attachmentAnchor: .scene(.topTrailingFront)) {
            Example043Label(title: "TopTrailingFront")
        }
        .ornament(attachmentAnchor: .scene(.center)) {
            Example043Label(title: "Center")
        }
        .ornament(attachmentAnchor: .scene(.front)) {
            Example043Label(title: "Front")
        }
        .ornament(attachmentAnchor: .scene(.back)) {
            Example043Label(title: "Back")
        }
        .ornament(attachmentAnchor: .scene(.leading)) {
            Example043Label(title: "Leading")
        }
        .ornament(attachmentAnchor: .scene(.trailing)) {
            Example043Label(title: "Trailing")
        }
        .ornament(attachmentAnchor: .scene(.leadingBack)) {
            Example043Label(title: "LeadingBack")
        }
        .ornament(attachmentAnchor: .scene(.trailingBack)) {
            Example043Label(title: "TrailingBack")
        }
        .ornament(attachmentAnchor: .scene(.leadingFront)) {
            Example043Label(title: "LeadingFront")
        }
        .ornament(attachmentAnchor: .scene(.trailingFront)) {
            Example043Label(title: "TrailingFront")
        }
    }
}

fileprivate struct Example043Label: View {
    var title = ""
    var body: some View {
        Text(title)
            .font(.title)
            .padding()
            .glassBackgroundEffect()
    }
}

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?