CesiumGS / cesium-unreal-vr-tutorial

Unreal Engine project, assets, and code used in the Cesium for Unreal VR Tutorial Series
Apache License 2.0
32 stars 5 forks source link

Add dynamic UI and line tracing for metadata #39

Closed xuelongmu closed 1 year ago

xuelongmu commented 1 year ago

Summary

Adds in dynamic UI (BP_DynamicWidget) that auto-resizes according to player distance and rotates to face the player at all times. Also adds a new actor component that performs line traces out into the world to query and display metadata.

Author checklist

Testing plan

Open up DynamicUI and Main level. On Main, you will have to navigate to a city with OSM buildings first. Hold down trigger and point at a building. Verify that metadata shows up, If not pointed at a building, a placeholder message should still show.

Reminders for reviewers

Thank you for taking the time to review this PR. By approving a PR you are taking as much responsibility for these changes as the author. Please keep these points in mind throughout the review process:

CesiumBen commented 1 year ago

@xuelongmu Everything looks great! I just had a few comments below.

  1. While the metadata might not be visible from Earth view, would it be concievable that in the BP_DynamicWidget's GetScalingFactor function the "WorldToMeters" should be incorporated instead of a static multiplication of 0.01?

scale


  1. The Left and Right hand meta data trace component doesn't work with the line trace renderer at all, rather it relies on the teleport component rendering it because it just so happens that the teleport trace and the metadata trace are controlled the same way through the pawn's implementation.

It wouldn't be much to pass in the line trace renderer into the setup of the MetadataTraceComponent and on tick tell the linetracerenderer to render if there is a valid metadata point. See the setup of the VRTeleportComponents in the pawn's begin play.

This would allow for:

xuelongmu commented 1 year ago

Thanks for the feedback!

  1. would it be concievable that in the BP_DynamicWidget's GetScalingFactor function the "WorldToMeters" should be incorporated instead of a static multiplication of 0.01?

In this case we're really just talking about UE units to UE meters, so there's not really a tie to real-world units. If the user is in Earth view mode, they're still going to be really far away from the widget and it'll be visible (theoretically)

It wouldn't be much to pass in the line trace renderer into the setup of the MetadataTraceComponent and on tick tell the linetracerenderer to render if there is a valid metadata point

That makes a lot of sense. I wonder what should happen when the two collide - for example, what should it look like if a point is both valid for teleportation and metadata?

Just a note about the comments everywhere, most of your fonts are set to 18 where 14 is used more widely. If you think 18 is more legible we can move towards that. It looks like blueprint UI flattens the font size so it's only for unreal blueprint legibility.

Sounds good, I'll update to 14.

CesiumBen commented 1 year ago

@xuelongmu Thanks for the updates, this looks good.

In this case we're really just talking about UE units to UE meters, so there's not really a tie to real-world units. If the user is in Earth view mode, they're still going to be really far away from the widget and it'll be visible (theoretically)

That makes sense, I'd assume in any setup with a different sized user, we'd want a different treatment of dynamic widgets. Even if the distance is larger with a higher world to meters scale, it seemed conceivable to make adjust the scale for world to meters as well so that under those circumstances you'd still be able to use the DMM approach.

That makes a lot of sense. I wonder what should happen when the two collide - for example, what should it look like if a point is both valid for teleportation and metadata?

When calling "ShowLineTrace" the shortest hit result takes priority and any corresponding color passed in at the same time is also applied. We can examine other edge cases to see if this functionality scales appropriately later down the line.

xuelongmu commented 1 year ago

@CesiumBen I'm actually not using the DMM (distance independent millimeter) approach here, as I thought it would add extra overhead and it works best when the user is incorporating Figma/Sketch/etc. into their UI design pipeline, and I wouldn't expect the majority of potential users here to be doing so.

There's another reason I'm not using the DMM approach here - the Quest 2's pixels are actually more dense than 1mm would be at a distance of 1 meter.

At a distance of 1 meter, a width of 1 mm would be equal to asin(0.001) = 0.057 degrees. If we take 1/0.057, that gives us about 17 millimeters per degree. Because the Quest 2 has a resolution of 21 pixels per degree (about 23% more), the perceived width of a pixel is less than a millimeter at the 1 meter distance, so we're actually losing some visual fidelity by scaling our UIs to DMMs.

So what's actually happening is that UIs are scaled down a bit from what they would be in DMM in order to ensure that 1 UMG pixel is the size of 1 Quest 2 display pixel. You lose a little bit of the scalability and convenience of DMMs on big projects, but I don't think most people will benefit from a DMM-based approach as opposed to just designing something, seeing it in VR, and tweaking it.

Even if the distance is larger with a higher world to meters scale, it seemed conceivable to make adjust the scale for world to meters as well

I might be missing something, but I don't think adjusting for world to meters is needed. Regardless of whether the user's at 500x scale or 1x scale, a widget 1km away will still be the same apparent size, even if at 500x scale it seems closer due to your headset's movements being amplified. The camera doesn't render things bigger/smaller based on its scale. For example, in our internal projects, we do not account for the world to meters scale when resizing dynamic UI (we do account for it in static UI though).

When calling "ShowLineTrace" the shortest hit result takes priority and any corresponding color passed in at the same time is also applied.

In the scenario I proposed, the hit results would be the same distance so it's not obvious to me which color would / should render. I also hadn't yet integrated the line trace component functionality as I was waiting to figure out how we would handle that conflict, but I can create a new PR once we do know.