-
Notifications
You must be signed in to change notification settings - Fork 140
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
WIP: Make collision generation dynamic #278
base: main
Are you sure you want to change the base?
Conversation
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.
Alright, good job. I think once the memory management is moved to build collision and destroy collision it will be on par or better than a single 65x65 collision shape. Worse because it has to manage 50-60 shapes, but better because it only needs to update a few smaller shapes instead of all 65x65.
We're pretty close. Make the modifications, rebase and it should be finished or very close.
Thanks!
One thing I observed is that when you change the collision_mode from full to dynamic, the collision shapes aren't freed. But I guess its not a problem since this isn't changed at runtime. And in the editor you can just reopen the scene |
I didn't evaluate all of the new code since there are things that aren't working. Let me know if you need help with anything or want to work on things together. I added a PR that renames and organizes some things. |
In dynamic editor mode, collision shapes do not have unique positions and are doubling up Though this solution is an interesting method, I feel like this is an overly complicated solution. What I proposed was using a small 65x65 collision square around the player, then on every snap, update the vertices of the shape, so 4225 vertex updates every snap, (which is based on movement, not frames). That is how my gterrain code worked, and is very short and simple. It will work fine with the static body and physics server, and does not continually allocate and deallocate memory. This solution has improves upon it by breaking down the collision shape into 17x17 vertex chunks, and only new chunks are updated. So when moving laterally, say 8 chunks are updated, or 2312 vertices updated. The cost of it though is a rather complicated chunking system that needs to track 50-64 collision shapes and move them around accurately and uniquely, without making memory non-contiguous by constant allocations and deallocations. This hasn't been achieved quite yet, so additional cost is that we need to spend more time to preallocate all of the shapes in build_collision, and identify unique positions so they don't doubling up. Then we have to maintain this code over time. And the physics server needs to calculate based on 64 shapes instead of 1. Though I started working on this PR to clean up and fix things, once I discovered the doubling up, I think the scales tipped for me in the cost/benefit analysis. I'm not sure the added overhead of us and the physics server managing all of the extra shapes, and the effort we've put in and still need to put in is worth the savings of ~2000 vertex assignments per snap. Whether it's 2000 or 4000 adjustments, both are inconsequential. I think we should revert most of these changes and go back to the simpler solution proposed in #161 and demonstrated in my gterrain code. Though the editor collision modes and settable collision shape size are good. What do you think? |
So I addressed your issue with the doubled collision shapes and its fixed now. Also I finished the non-editor collision, which was previously not really done yet. The issues I had before with missing API was resolved by finding the correct API xD I tested this a bit and for me it doesn't leak any memory and there shouldn't be any allocations as far as I can see. So I think its good to go now. |
Alright, I tested more and now it's all working well. Good job. There are a few more improvements that I made and some more I've left for you. Items I adjusted in my commits:
There are two other issues I found and have not fixed. Invalid RIDI get this error message multiple times on DYNAMIC_GAME, after running the game, moving the camera, then quitting.
This is caused by this code in destroy_collision,
This means we can't rely on the server to house the RIDs but must track them ourselves, as we do with Inefficient LoopsAt even the default values for dynamic size/distance with 50-64 shapes in existing, using
So up to 3 * 64 * 64 * 256 = 3.1 million integer comparisons just to tell if the collision shape already exists. Both the checking if it exists and the overall for loop need to be better designed. We don't need to check for all regions, for all shapes per region x & z, and we don't need to iterate through the array using has. What should happen in a chunking system is: _build_collision
_update_collision
_destroy_collision
This logic is the same for physics server shapes or instanced shapes. There's very little code difference between the two. The main difference is that we get the RID of the shape and send it to the server, or how shapes are created and destroyed. This should reduce the update time a bit, but even if not, it's a cleaner design that will help us maintain the code in the future. It won't take much modification from what's already there. But those crucial for loops need to be reworked. I can help you implement this if you like. |
I'm going to look at the design a bit more later, but here's some initial testing of functionality.
|
Note, I fixed the memory leaks for the up coming release. |
An error i found checking this pr is that when trying to make play the demo, it doesn´t start and leaves the long messages, confirming cory issue. that update coll is not initialized either way , it improves loading times( like it the main reason why a game with terrain 3d takes a lot to load. core\variant\variant_utility.cpp:1091 - Terrain3D::_update_collision: Collision not initialized, returning |
My current thinking for the foliage instancer is to generate MultiMeshes in chunks. I will build it off of the chunk infrastructure you're building here. I'll be ready to work on foliage in a week or two, so if this isn't done by then I'll get involved to move it along. |
This PR needs address #341 (comment), and make sure it works without error when running and quitting without regions. |
0efbc88
to
461241b
Compare
Rebased and consolidated down to three commits. 1st is the previously identified working commit. It works fine but has some errors on cleanup. 2nd is a first pass rewrite that also seems to work, with errors out of bounds. 3rd is a separation into separate classes, which is currently broken due to changes in the main tree not considered in this branch. Unknown if it works. Next step is to audit the new design, consolidate the new classes down to 1 or 2, and review and adjust the code. |
@TokisanGames yes, thanks for the rebase! Please give some feedback on the system design and APIs |
@lw64 I'll take over this PR and work on it for my next priority. As you requested, I'll give you feedback along the way. Some notes I have already:
Next I need to understand what changes are made in commits 2 and 3, and what is the best way to structure it. |
src/chunk_manager.cpp
Outdated
p_size++; | ||
} | ||
p_size = CLAMP(p_size, 8, 256); | ||
_chunk_size = p_size; |
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.
This is duplicate code and if it's not already available in the engine, should be put in Terrain3DUtil
We have 5 classes: 3 manager types, 2 chunk types. Each derivative class should represent a unique object we will create. So if we were going have chunks for say instances, instance collision, ground collision that might warrant 3 child classes and 1 base class for chunks. However, one manager could process all of those classes. It would be designed to work with the base chunk so it could handle all child types. I don't see the reasoning for having 3 manager types, and certainly not for having more manager types than managee types (chunks). The design pattern that would be a better fit for this might be a mixture of the composite and template patterns. Something like this, which is exactly how our ProximityManager is constructed. In this case the manager might move the baseobject, then pass the transform or other data to the object run process which could handle generating ground collision, or generating an MMI, or generating collision for objects in the area.
|
I went for the most simple approach for the start, which is each type of chunk has its own very simple manager, so simple even that they could be in the same file, and the main logic is in the base manager class. But I can see a lot of potential for optimization there, and having only one manager instance handling everything can enable quite a lot. Also something to keep in mind is doing more complex chunking for example with quadtrees later. But I think the most complicated part about having one single manager instance is that each chunk type might have different properties, gras chunks are smaller and have shorter visibility, while tree chunks should be bigger and have very far visibility. I think this is possible though, and could avoid a lot of overhead, since not every manager instance does the same work again and again. |
@TokisanGames and thanks for taking over! :D |
The overall hierarchical structure of the later commits isn't bad. I just think it is not a good match for our use case. base_chunk would be more useful if we were to have multiple class types derive from it. mesh_chunk, collision_shape_chunk, instancer_chunk, etc, each with their own unique functionality, but also enough shared code like positioning, signal responding, creation, deletion (a lot that is already handled by Node3D). chunk_manager would be useful if we were to have multiple types of managers with their own unique code, but also a lot of shared code. I think these many classes might be used more if we were making a chunked terrain. In our case a lot of work is already done by engine classes or the clipmap nature. In a chunked terrain, a chunk might contain a group of nodes with several mesh instance LODs, a physics body, and a collision shape. It may also have a subscene with the assets at that location. It's a lot of unique functionality not already present in the engine. What functionality do we need in our chunks? In the instancer, we store the transforms in a data structure, then we create MMIs and place them on the terrain in a grid. The MMIs are the objects we instance that perform a special function (rendering), hence they are the chunk. We don't need another any other functionality in the chunk beyond what the MMI and it's inherited Node3D and Object classes do, so we don't need another class to contain it. For collision, the object we want to instance and move around is a collision shape. The only functionality we need is to store the data and move it. You have the chunk molding itself to the heightmap. That functionality can easily be done by the manager. I think either is a fine design choice, but in this case, since forming the shape is the only thing it might do, we might as well have the manager do it so we can make the chunk slimmer and remove the containing class entirely. So we can get away with an instancer management class that manages its MMIs, and a single collision manager class that manages its collision shapes. Both managers creates, moves, configures, and destroys their chunks, but the amount of code to handle those isn't similar enough that it's worth abstracting into a super class. And the chunks already share abstract code in Node3D and Object, so I don't think we need to wrap them any further. This is the direction I'm going to move in. Consolidating the classes into a single manager with the collision shape as a chunk and using the first commit as a guide, since it works very well. |
Admin edit:
Should address Update debug collision on operations #106
Test Fatal error (Index p_index = 0 is out of bounds) when closing the game #341
Test Enabling collision increases memory consumption each time the scene is reloaded. #397
Test Not disabling collision first when generating from code (causes
ERROR: FATAL: Index p_index = 0 is out of bounds (shapes.size() = 0) in import_images
, disabling it beforehand makes it work.Test Show debug collision doesn't set collision layer/mask #329
Test CodeGenerated collision has extra lip #328
Fixes #161