Page MenuHome

Fix T90808: Undo curve selection recalculates boundbox based on curve data
ClosedPublic

Authored by Germano Cavalcante (mano-wii) on Aug 20 2021, 8:55 PM.

Details

Summary

It's strange that selection undo triggers the actual boundbox
calculation.

But that aside, the problem is that there are two functions that
recalculate the boundbox of an object.

  • One that considers the evaluated mesh and the displist
  • Another that only considers the object's data.

Most of the time, the bound box is calculated on the final object
(with modifiers), so it doesn't seem right to just rely on ob->data
to recalculate the ob->runtime.bb.

So join the functions that calculate boundbox into one and use the
functions that only only consider ob->data as a fallback.

Diff Detail

Repository
rB Blender
Branch
master
Build Status
Buildable 16541
Build 16541: arc lint + arc unit

Event Timeline

Germano Cavalcante (mano-wii) requested review of this revision.Aug 20 2021, 8:55 PM
Germano Cavalcante (mano-wii) created this revision.

It seems like the proper way to differentiate between these functions would be calling them BKE_object_boundbox_original and BKE_object_boundbox_evaluated

Neither of them are correct though, I don't think, for a few reasons:

  • An evaluated object can evaluated to more than one type of data, with the result stored in geometry_set_eval
  • The displist result for curve and text objects isn't so relevant anymore:
    • The evaluated mesh is the proper place to look for any curve that has a surface when evalauted
    • When the curve does not have a surface (i.e. no curve bevel), the proper place to look is in the CurveEval output, since that takes into account data from geometry nodes.
  • Then there are instances, which an evaluated object might also have-- if those aren't considered it should at least be in a comment.
  • Should the "evaluated" version really look at the original data as a backup? That seems wrong, since what if the data type or size of the evaluated result has changed.
  • BKE_object_boundbox_get now doesn't consider other types like point clouds, volumes, or grease pencil.

Besides that, I think the best way to avoid recalculating bound boxes for instances is moving their cache to object data rather than objects. That's outside the scope of this patch, just wanted to mention it.

  • The displist result for curve and text objects isn't so relevant anymore

I see the point, but I don't see why we should prevent displist from still being used as a second alternative (as a security measure).
The evaluated mesh is still the priority.

  • BKE_object_boundbox_get now doesn't consider other types like point clouds, volumes, or grease pencil.

How so? Do these objects generate an evaluated dummy mesh that prevents the BKE_object_data_boundbox_get from being called at the end?
(I need to investigate...)

  • Remove unrelated changes
  • Rename BKE_object_data_boundbox_get to BKE_object_boundbox_original
  • BKE_object_boundbox_get now doesn't consider other types like point clouds, volumes, or grease pencil.

Ah, I get the point now!
It refers to the nomenclature. In fact the BKE_object_boundbox_original still reads the evaluated date for those objects types.
I'll see how I can make it more conventional...

  • Don't split the function. The name of the new BKE_object_boundbox_original could be misleading.
Bastien Montagne (mont29) requested changes to this revision.EditedOct 22 2021, 3:17 PM

I don't think this patch is acceptable in current state.

Good:

  • Getting rid of boundbox_displist_object.

Bad:

  • Adding that whole block of 'generalist' code at the start of BKE_object_boundbox_get.

What I would suggest (but would also like input from @Sergey Sharybin (sergey) or @Sybren A. Stüvel (sybren) here): move content of boundbox_displist_object into BKE_curve_boundbox_get, keeping bbox computation from actual curve data (BKE_curve_minmax) as last fallback. that would give that order of bbox generation from given curve object:

  1. Evaluated mesh (if it had some modifiers applied)
  2. Evaluated curve (the displist).
  3. Original curve defining points (only option available on an original, never evaluated curve object).

AFAICT, this would match the behavior of the other BKE_XXX_boundbox_get functions: Compute from evaluated data if available, fallback to original geometry otherwise.

This revision now requires changes to proceed.Oct 22 2021, 3:17 PM

I agree with what Bastien said, but the evaluated curve is CurveEval, rather than the displist. Since that is implemented in C++, curve.c could be moved to C++ too, or a wrapper BKE_curve_eval_bounds_min_max could be added.

Germano Cavalcante (mano-wii) planned changes to this revision.EditedOct 22 2021, 7:09 PM

Looking again I noticed that BKE_object_boundbox_get becomes thread-unsafe with this patch. What can be a problem during evaluation.
I'm not sure how to use CurveEval. This appears to store spline data (without tris?)
Does this mean that displists should now only be used for metaballs?

I'm not sure how to use CurveEval. This appears to store spline data (without tris?)

Exactly, and that's the nice simplification-- curve data is only the splines, and if it has a surface (triangles, etc.) than the data is a mesh.
But keep in mind that any object can evaluate to both a mesh and a curve, or even a point cloud and a volume too. All of that data should be in geometry_set_eval.

Does this mean that displists should now only be used for metaballs?

Yes (and it would even be nice to change that!)

In a more ideal world I would imaging the bounding box to be calculated as part of dependency graph update and not being lazily calculated. It is possible to copy evaluated bounding box to the original object for ease of access (if needed) in the similar way how we do it for animation system.

From this point of view I'd expect BKE_object_boundbox_get to be a simple return statement, and things like BKE_displist_minmax and BKE_mesh_wrapper_minmax will happen in a more localized places after the mesh/curve modifier stack is evaluated.

Generally the direction should be in building more of a black-boxed proper API, so that, for example, adding new object type does not require of finding all places where modifications are to be made.

  • Move object.c to C++
  • implement BKE_object_boundbox_calc_from_geometry_set_eval and BKE_object_boundbox_calc_from_displist
  • Use BKE_object_boundbox_calc_from_geometry_set_eval and BKE_object_boundbox_calc_from_displist in object_sync_boundbox_to_original

As seen in object_sync_boundbox_to_original, it calculates the BoundBox of the evaluated object and copies it into the original.
So new ways to calculate the BoundBox have been added there.

(A somewhat blind solution, but it worked in my tests).

  • Avoid recalculating the BoundBox
Hans Goudey (HooglyBoogly) requested changes to this revision.Oct 29 2021, 12:24 AM

Thanks for moving the file to C++, that will be nice for other situations too. I think it should be committed separately though.

source/blender/blenkernel/intern/object.c
3898–3899

Maybe others have a different opinion, but I think these two are redundant arguments, since you wouldn't want to call this with a geometry set not owned by the object.

3907–3919

"DM-BoundBox" I think that stands for derived mesh? Usually __func__ is much simpler IMO.

source/blender/blenkernel/intern/object_update.c
286–291 ↗(On Diff #44088)

I would recommend reversing the order of these checks-- this means that if the object evaluates to both a mesh and a point cloud for example, the point cloud won't be considered in the bounding box.

This revision now requires changes to proceed.Oct 29 2021, 12:24 AM
  • Merge new functions into a single BKE_object_boundbox_calc_from_evaluated_geometry thus removing redundant arguments
Germano Cavalcante (mano-wii) marked 3 inline comments as done.Oct 29 2021, 3:22 AM
  • Rebase on master
  • Remove unused function
  • Cleanup: comments

One thing that is unclear to me with this patch is, is it applicable to 3.0 and 2.93 (and ideally 2.83)? T90808 is a regression that also needs to be fixed in the LTS releases (as much as possible), and mandatory fix for 3.0 release.

One thing that is unclear to me with this patch is, is it applicable to 3.0 and 2.93 (and ideally 2.83)? T90808 is a regression that also needs to be fixed in the LTS releases (as much as possible), and mandatory fix for 3.0 release.

Although the existing code is not ideal. The problem was only evident after rBb9febb54a492: Geometry Nodes: Support modifier on curve objects (committed in 3.0).
So even though it might be somewhat reproducible in 2.93, it's not a major issue as it has apparently never been reported for that version.

Since the code needs to work with C++ in object.c, it's a little tricky to replicate the same solution in the 2.93.

My remaining question is-- why does BKE_object_boundbox_calc_from_mesh still exist? I would think that object_sync_boundbox_to_original and BKE_object_boundbox_calc_from_evaluated_geometry would handle all object types now.

Other than that, the code looks good.

source/blender/blenkernel/intern/object.cc
3997 ↗(On Diff #44387)

The variable can be declared directly in the if statement:
else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) {

3998 ↗(On Diff #44387)

There is no need for these (float *)& casts, because float3 has a operator float * method.

Germano Cavalcante (mano-wii) marked 2 inline comments as done.
  • update based on feedback

Okay, the changes here look good now. But my questions about BKE_object_boundbox_calc_from_mesh still remains-- that still seems incorrect to me, at least relative to this change.

Oops, I missed the question.
The question is a bit complex.
BKE_object_boundbox_calc_from_mesh cannot be simply replaced since its usage is quite specific (computing a BoundBox for the object based on the mesh that is passed as a parameter).
This function is called at the end of the modifier evaluation function and works for any type of object.
In fact, its existence somewhat complicates the answer to the question "what does the BoundBox encompass?".

I'm not sure if it can be removed as its call tree has branches outside the depsgraph evaluation which may end up leaving the BoundBox uncalculated (and the BoundBox based on ob->data can be used instead of the evaluated geometry).
Removing/replacing it, although it would make the code easier to understand (imho), seems to be an issue for another patch.

Okay, I guess I'm fine with that, since this patch is an improvement even if it doesn't take on that problem.

It seems to me that now the bounding box means one thing for mesh objects (bounds of evaluated mesh) and another thing for all other object types (bounds of evaluated geometry set).

But you're right, it's complicated by the fact that evaluating modifiers for an object in edit mode places the result in a different place than non-edit mode (which feels like a problem in my opinion).

This revision is now accepted and ready to land.Nov 24 2021, 6:29 PM