(And I should mention again that this algorithm is intended for fast updates, not necessarily doing this faster for the entire CSG tree. Even though that would be a nice bonus)
I also mentioned a couple of things that could be done to improve performance, and that there are a lot of ways to improve performance.
Today I had a simple idea to improve performance.
By checking the bounds for each left and right branch separately at a higher level, so that we know what operation we're performing, we can handle some common situations in a more simplified, and faster, way.
Here's the updated pseudo code for the CSGBranch.Categorize method.
void CSGBranch. Categorize( categorizationNode, inputPolygons, ..., inside, touchInside, touchOutside, outside) { switch (Operator) { case CSGOperator.Addition: { // Check if the given polygons // are possibly touching the // left branch if (boundsOfPolygons .IsOutside(Left.Bounds)) { // Polygons are not touching // the left branch. // Check if the given polygons // are possibly touching the // right branch if (boundsOfPolygons .IsOutside(Right.Bounds)) { // Nope, all of them are // categorized as 'outside' outside.AddRange( inputPolygons); } else { // We only need to check // with the right branch Right. Categorize(...); } } else // Polygons are touching // the left branch. // Check if the given polygons // are possibly touching the // right branch if (boundsOfPolygons .IsOutside(Right.Bounds)) { // We only need to check // with the left branch Left. Categorize(...); } else { // Polygons are touching // both branches // same as before ... // (Left || Right) LogicalOr(categorizationNode, inputPolygons, ..., inside, touchInside, touchOutside, outside, false, false ); } break; } case CSGOperator.Common: { // Check if polygons are outside // either left or right branch if (boundsOfPolygons .IsOutside(Left.Bounds) || boundsOfPolygons .IsOutside(Right.Bounds)) { // Considering that in a // 'common' operation we need // to find the parts that are // shared with both branches, // we know that if the polygons // are outside just one branch // that they are categorized as // 'outside' outside.AddRange( inputPolygons); } else { // Polygons are touching // both branches // same as before ... // !(!Left || !Right) LogicalOr(categorizationNode, inputPolygons, ..., outside, touchOutside, touchInside, inside, true, // reverse Left true // reverse Right ); } break; } case CSGOperator.Subtraction: { // Check if the polygons are // touching the left branch if (boundsOfPolygons .IsOutside(Left.Bounds)) { // The right branch removes // and the left branch keeps // whatever is inside it. // If all the polygons are // outside the left branch // then we know they're all // categorized as 'outside' // this branch. outside.AddRange( inputPolygons); } else // Polygons are touching // the left branch. // Check if the given polygons // are possibly touching the // right branch if (boundsOfPolygons .IsOutside(Right.Bounds)) { // If we're only touching the // left branch, we don't need // to do a more complicated // operation, and just // categorize the left branch. Left. Categorize(...); } else { // Polygons are touching // both branches // same as before ... // !(!Left || Right) LogicalOr(categorizationNode, inputPolygons, ..., outside, touchOutside, touchInside, inside, true, // reverse Left false ); } break; } } }
This alone increased the speed from about 80ms to 25-30ms for the entire test scene.
I'm going to use a much bigger scene in the future,
because it really is too small to properly test for scalability.