-
Notifications
You must be signed in to change notification settings - Fork 125
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
src/terrain_3d.cpp
Outdated
PhysicsServer3D::get_singleton()->body_set_collision_priority(_static_body, _collision_priority); | ||
} else { | ||
CollisionShape3D *debug_col_shape; | ||
debug_col_shape = memnew(CollisionShape3D); |
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.
If you play this and watch your process monitor, the game continually consumes more and more memory as the player moves around. All memory allocation needs to be moved to _build_collision
and all freeing moved to _destroy_collision
.
Though the memory allocation for debug collision was here, it was only created at scene start and wasn't a problem until the repeated creation and destruction. Now debug collision allocation can also be moved to build_collision.
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.
I couldn't move the memory allocation fully to _build_collision
, as it is not defined at build time, how many collision shapes need to be allocated. the distance
is variable, and for example for 64.0
the shape count varies between 48 and 52 in my experience, depending on the camera position.
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.
I made it now allocate new ones on demand, but that should only happen during the first _update_collision
call.
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!
src/terrain_3d.cpp
Outdated
if (!_show_debug_collision) { | ||
col_shape = _unused_collision_shapes.pop_back(); | ||
Dictionary shape_data = PhysicsServer3D::get_singleton()->shape_get_data(col_shape); | ||
map_data = shape_data["heights"]; |
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.
I am not entirely sure this avoids allocations. But I also don't see another method. the map_data gets assigned back later again.
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 allocations and deallocations we want to avoid in update_collision are memnew
and memfree
. Creating a PackedFloat32Array here is fine. This gets created on the stack which is designed for frequent, rapid creation/destruction. The other two allocate memory on the heap, which should not be as frequent.
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.
Which other two? Dictionary
?
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.
By other two, I mean the general usage of memnew and memfree. Not referring to lines specifically.
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. |
…a checking out of update_collision. Track collision update time in usec instead of msec
src/terrain_3d.cpp
Outdated
} | ||
// Set heights on local map, or adjacent maps if on the last row/col | ||
if (shape_global_x < region_size && shape_global_z < region_size) { | ||
map_data[index] = (Util::is_hole(cmap->get_pixel(shape_global_x, shape_global_z).r)) ? hole_const : map->get_pixel(shape_global_x, shape_global_z).r; |
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.
As soon as I switched to Dynamic / Editor running the demo crashes on this line. The camera is outside of the terrain. The reason is:
get_pixel
is called with (896, 464)
, however cmap, cmap_x, cmap_xz, cmap_z are all null
Region is currently -1, which means no region. So if region == -1 after line 427, you can skip all of the code down to L558 probably. Though you may want to disable that shape.
That should allow shapes to be generated on the terrain if the player is near the sculpted regions, just not in the areas outside of that.
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.
Adding this in L428 is sufficient to have it work. However I haven't looked yet to see if this properly disables the shapes or if it needs to do more.
if (region < 0) {
continue;
}
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. |
Admin edit:
Fixes #161