-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Fix exaggeration of ellipsoid voxel clipping bounds #12959
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Thank you for the pull request, @jjhembd! ✅ We can confirm we have a CLA on file for you. |
| */ | ||
| this._maxClippingBoundsOld = new Cartesian3(); | ||
|
|
||
| /** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it really necessary to have 8 different pieces of state related to clipping bounds? ( (old, new) x (exaggerated, regular) )
I don't totally understand how these are consumed, but I have this feeling that they're not all necessary.
Are the old members just used for tracking dirtiness? Do we even need to store the exaggerated clipping bounds explicitly, or can we just update the regular clip bounds directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The expensive call is VoxelShape.prototype.update. This call is only necessary if modelMatrix, shape bounds, clipping bounds, or exaggeration have changed. (Unfortunately we expose setters for both the shape and clipping bounds, so we do have to check those.)
The checks happen in checkTransformAndBounds. If we want to reduce the amount of state, we could perhaps store the state of the exaggeration itself rather than exaggerated bounds. We would then have verticalExaggerationOld and verticalExaggerationRelativeHeightOld, rather than exaggerated???BoundsOld * 4. Would this make sense to you? Or is there a better way to reduce state?
I realized the current setup is state-heavy. I was sort of kicking the cleanup down the road until we resolve the API question: Do we really need to expose all these bounds setters?.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Unfortunately we expose setters for both the shape and clipping bounds, so we do have to check those.)
Not sure I understand- isn't this a good thing? In the setter, we could set some dirty flag to true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the setter, we could set some dirty flag to true.
Even if this was done in some setter like this one, there is no sensible encapsulation* for all this. The 'getter' still returns the Cartesian3, and users will do primitive.maxClippingBounds.y += 42 and expect that to have the... expected ... effect.
Nevertheless, there are indeed quite a few "bounds" here. It looks like there are things that could be "grouped". The comment at #12813 (comment) mentioned dedicated classes for the "clipping" information. Without that, it looks like there could be different groupings:
- Roughly something like
ExaggeratablePoint, to store apointandexaggeratedPoint, used forminRender, maxRender: ExaggeratablePointandminClip, maxClip: ExaggeratablePoint - Roughly something like an
ExaggeratableRangewithmin/max/exaggereatedMin/exaggeratedMax(encapsulating the exaggeration functionality), used forrenderRange: ExaggeratableRangeandclippingRange: ExaggeratableRange - (In both cases, these
Exaggeratable...Things...could store (and hide!) theold...properties for the dirty checks where necessary)
This is just from browsing over the code in the GitHub view - I'll have to check this more closely in a dev environment to see which of these (or similar "groupings") could make sense....
* This encapsulation would require a ReadonlyCartesian3. Maybe, in the future... (TODO: Insert "I would be so happy" meme here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jjhembd Yes I do think we should be storing the state of the exaggeration rather than the state of everything that depends on it. Then, in updateVerticalExaggeration, just compare to the old state and set a dirty flag if needed.
(To be honest, there should really be an event that one could listen to for vertical exaggeration changes... instead, every class that cares is storing the old exaggeration value... but that's a topic for another day)
| primitive._exaggeratedMinClippingBounds, | ||
| primitive._exaggeratedMaxClippingBounds, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the VoxelShape interface, I don't see any update method that has 5 arguments. Looks like it's a special case for ellipsoid shaped voxels... I don't love that :D It degrades the benefits of using polymorphism.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is VoxelPrimitive.update called every frame? If not, could we just calculate the exaggerated clipping bounds on the fly here rather than storing it as a member? (Honestly, even if it is called every frame, it's extremely cheap to calculate the exaggeration)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VoxelPrimitive.update is called every frame (we should probably shortcut out of it earlier). The reason for storing the bounds was to avoid calls to VoxelShape.update -- see my previous comment above.
|
@mzschwartz5 thanks for the feedback! I think I addressed it all except for the question about how much (or which) state we should store. See my comment above for one possible resolution--let me know if there's a cleaner way to do it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per comment, only change I'd still like to see is storing the exaggeration and dirtying based on that, instead of storing old fields for everything that depends on exaggeration
Description
This PR fixes exaggeration of ellipsoid voxels, by exaggerating the clipping bounds along with the shape bounds.
A
VoxelPrimitiveimplements vertical exaggeration differently depending on the shape type:VoxelShapeType.BOXandVoxelShapeType.CYLINDERapply the exaggeration as a transform, which is multiplied with themodelMatrix. This approach assumes the exaggeration is along the same axis for every point in the voxel (e.g.,Zfor cylinders). This is a reasonable approximation for datasets only covering a small area of the Earth, with some assumptions (!) about the shape orientation.VoxelShapeType.ELLIPSOIDis often used for datasets covering a large portion of the globe, so the exaggeration must be along the local ellipsoid normal, which varies across the dataset. This is implemented via scaling/shifting of the shape's height bounds.The missing element for ellipsoids, highlighted in #12811, was that clipping bounds were not exaggerated. Data near the clipping bound could therefore be clipped off when the shape was exaggerated. This PR corrects that by exaggerating the clipping bounds along with the shape bounds.
Issue number and link
Fixes #12811
Testing plan
Load the test local Sandcastle and verify that the entire dataset is exaggerated without being truncated.
Author checklist
CONTRIBUTORS.mdCHANGES.mdwith a short summary of my change