Create RealityKit entity that simulates circular progress bar

I wanted to show a progress of a certain part of the game using an entity that looks like a "pie chart", basically cylinder with a cut-out. And as progress is changed (0-100) the entity would be fuller.

Is there a way to create this kind of model entity? I know there are ways to animated entities, warp them between meshes, but I was wondering if somebody knows how to achieve it in a simplest way possible? Maybe some kind of custom shader that would just change how the material is rendered? I do not need its physics body, just to show it.

I know how to do it in UIKit and classic 2d UI Apple frameworks but here working with model entities it gets a bit tricky for me.

Here is example of how it would look, examples are in 2d but you can imagine it being 3d cylinders with a cut-out.

Thank you!

Replies

You can use RealityViewAttachments to display any SwiftUI View as an entity. Here's a snippet that adds a ProgressView to a RealityView's content. This should point you in the right direction. For a deeper dive into RealityKit and attachments see Diorama.

struct ImmersiveView: View {
    private let attachmentId = "attachment"
    @State private var progress:Double = 0.1
    
    // RealityKit uses meters so its best to specify the size in meters
    // and let PhysicalMetric do the conversion to units appropriate for SwiftUI
    // https://developer.apple.com/documentation/swiftui/physicalmetric
    @PhysicalMetric(from: .meters)
    var progressWidth = 0.5
    
    var body: some View {
        RealityView { content, attachments in
            if let attachment = attachments.entity(for: attachmentId) {
                attachment.position = [0, 1.2, -1.5]

                content.add(attachment)
            }
        }
        attachments: {
            Attachment(id: attachmentId) {
                VStack {
                    ProgressView(value: progress)
                        .frame(width: progressWidth)
                    Spacer(minLength: 10)
                    Slider(
                        value: $progress,
                        in: 0...1
                    )
                }
            }
        }
    }
}