Open ElsAr4e opened 1 year ago
A high-level feature such as this one can currently be done already by editing pixels of the heightmap (which can be obtained with terrain.data.get_image(HTerrainData.CHANNEL_HEIGHT)
, and then calling notify_region_changed
to upload the changes.
Something more challenging however is updating the collider. The plugin uses Godot's heightmap collider which does not allow to modify specific areas without recreating the entire collider, which is not viable. But given the nature of heightmaps, this should be possible to implement easily. But it has to be added to Godot Engine.
@MGilleronFJ So I should actually mention this feature request here: https://github.com/godotengine/godot-proposals?
The plugin uses Godot's heightmap collider which does not allow to modify specific areas without recreating the entire collider, which is not viable.
Can't several smaller heightmap colliders be used in a grid pattern?
@Calinou maybe, but I would really not like to fallback on this and call it done, because it's so stupidly simple (and faster) to update pixels that it's gotta be possible to have xD Perhaps both can be done, even though partial collider update makes chunking irrelevant
Hi, just wanted to point out that currently in HTerrainCollider.create_from_terrain_data
, even for the largest 4097^2 maps, the call to PhysicsServer3D.shape_set_data
takes ~13ms on my PC (Ryzen 5600x level). The largest time consumption by far is due to the fetching of the heights from the heightmap itself (~5s). Maybe a local cache of the heights inside HTerrainCollider might also do the job until it is possible to partially-update the heightmap on the PhysicsServer3D
?
Note: my data comes from a diverged baeaba83345e1a5017587dd235749df5a528ef66. I am expecting commit e49ac9a8e6a9cf41667c6722d663cd6370026df5 to have sped up the fetching of the heights, but the point is the same: PhysicsServer3D.shape_set_data
is almost as good as not to bother about partial updates
Now that the heightmap image is RF, caching heights makes no sense. Or rather, is a terrible waste of space... because it doesn't need any transformations anymore, and can be used directly for both rendering and physics.
Partially updating the heightmap collider is also a tragedy... because in theory the same piece of memory could be shared between the collider and the image (at least Bullet allowed this in Godot 3), which is an incredibly simple solution. But because of Godot's encapsulation, CoW and safety measures, it's just impossible. Instead, the entire data has to be reallocated and copied around on every change (at least until it can be done partially).
I broke down how long HTerrainCollider.create_from_terrain_data
takes on my machine (Ryzen 5) with a 4097^2 terrain:
terrain_data.get_aabb
took 20.628 ms, which can be cached on startup but the gain would be very small compared to the rest of the loading. Runtime edits require to compute it again (it doesnt use all pixels, instead it does the min/max of chunks). We could decide to cache the tallest it's ever been, at the expense of suboptimal height with unused space. It might not be much of a problem in practice, unless the terrain gets modified so much that a full update is needed again to cleanup unused space;terrain_data.get_all_heights
took 8.899 ms (which is a shame because all it does is get the image data as floats, which it ALREADY IS but Godot forces us to reallocate it all). Passing the Image
instead is possible, but then shape_set_data
does the same conversion again internally.PhysicsServer3D.shape_set_data
took 15.463 ms, which still indicates it does non-negligeable amounts of workI ran it again after adding code to get the total time as well, around 44.558 milliseconds. It's a small hitch so it can still be a problem to update that frequently, but it is very far from the 5 seconds you mentioned, so this is quite surprising, unless you are still running a version that isn't using RF yet maybe.
Unrelated: I also noticed Godot slows down to a crawl after resizing a terrain to 4097. No idea what causes this. Turns out closing the scene and reopening it eventually gets rid of the issue and the terrain runs smoothly.
I would like to have the option that some materials and/or specific area(s) of the terrain can be destroyed.
You should be able to exclude specific area(s) or materials - For example rock texture can't be "destroyed", concrete texture just a bit.
Ideally you should be able to set the texture of the destroyed material so that a grass texture will be replaced for example by a burned soil. And maybe you can set the maximum high that can be removed - for example if you create a FPS-Shooter even if you use a grenade launcher only 2 meters of the terrain can be removed - not more?
Example: https://www.youtube.com/watch?v=j9gDDVc9128&t=91s