GeometryReader3D always reading 1280x1280x1280 in a volumetric window on VisionOS no matter what I set defaultWindowSize to
Asked Answered
C

1

2

I'm picking Swift development back up for the first time in many years to play w/ VisionOS. SwiftUI is new to me so I'm not sure if I'm missing something or if this is a bug.

The results of running the following code is:

(width: 1280.0, height: 1280.0, depth: 1280.0) (width: 1280.0, height: 1280.0, depth: 1280.0)

I get the same numbers no matter what I set the .defaultSize to. If I switch to a window instead of a volume I get different numbers as expected. Interestingly the actual size of the volume and the red/blue colors does change properly, but the GeometryReader3D doesn't seem to see it properly.

Am I missing something or is this a bug?

Btw, my actual goal is to scale up a model created programmatically using MeshDescriptor to fill the volume. I have model generation working, but I spent most of a day trying to figure out why my transformations weren't working as expected until I finally realized the info I'm getting from the GometryReader3D outside of my RealityView was giving me bad info.

import SwiftUI

@main
struct app: App {
    var body: some Scene {
        WindowGroup {
            GeometryReader3D { outer in
                ZStack {
                    GeometryReader3D { inner in
                        Color.blue.frame(maxDepth: .infinity).onAppear() {
                            print(inner.size, outer.size)
                        }
                    }
                    Color.red
                }
            }
        }
        .windowStyle(.volumetric)
        .defaultSize(width: 2000, height: 1000, depth: 1000)
    }
}

I wrote this yesterday, and then figured out that I can use .frame (like below) with a copy of the window size I set to get the behavior I expected. I still feel like it should work that way without the .frame calls so the question stands. Is it a bug or expected behavior?

import SwiftUI

let windowSize = Size3D(SIMD3(repeating: Double(500)))

@main
struct app: App {
    var body: some Scene {
        WindowGroup {
            ContentView().frame(width: windowSize.width, height: windowSize.height).frame(depth: windowSize.depth)
        }
        .windowStyle(.volumetric)
        .defaultSize(windowSize)
    }
}
Corene answered 9/2 at 20:28 Comment(0)
S
2

Use delay Task.sleep(..) when printing proxy3D.size and remember that a result is in pt.

import SwiftUI
import RealityKit

@main struct YourApp : App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .windowStyle(.volumetric)
        .defaultSize(width: 0.51, height: 0.51, depth: 0.51, in: .meters)
    }
}

struct ContentView : View {
    var body: some View {
        GeometryReader3D { proxy3D in
            RealityView { content in
                let box = ModelEntity(mesh: .generateBox(size: 0.5))
                content.add(box)
            }
            .onAppear {
                Task {
                    try await Task.sleep(nanoseconds: 900_000_000)  // delay
                    print("The size is:", proxy3D.size)
                }
            }
        }
    }
}

// Result:

// The size is: (width: 694.0, height: 694.0, depth: 694.0)

P. S.

In your case it will look like this:

Color.blue.frame(maxDepth: .infinity).onAppear() {
    Task {
        try await Task.sleep(nanoseconds: 900_000_000)
        print(inner.size, outer.size)
    }
}
Shortridge answered 9/2 at 21:38 Comment(3)
Very interesting, thanks for sharing this. I confirmed you're correct. It doesn't really answer the question of if this is a bug and doesn't solve the problem I'm actually trying to solve which is to calculate the geometry of the models in my inner RealityView, but it's very interesting to know. It seems like this is specific to the top level as GeometryReader works fine on inner stuff without the delay. If I'm going to use a workaround I prefer the one I came up with using frame to pass in the window geometry.Corene
Another thought, SwiftUI is supposed to help manage things that change, so if that geometry changes later in the lifetime of the app I'd expect that to trigger a new render if it wasn't somehow available initially. This is really smelling like a bug to me.Corene
This looks like a bug to me too.Shortridge

© 2022 - 2024 — McMap. All rights reserved.