Zylann / godot_heightmap_plugin

HeightMap terrain for Godot implemented in GDScript
Other
1.67k stars 156 forks source link

[Feature request] Destructible Terrain #361

Open ElsAr4e opened 1 year ago

ElsAr4e commented 1 year ago

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

MGilleronFJ commented 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.

ElsAr4e commented 1 year ago

@MGilleronFJ So I should actually mention this feature request here: https://github.com/godotengine/godot-proposals?

Calinou commented 1 year ago

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?

MGilleronFJ commented 1 year ago

@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

1998marcom commented 12 months ago

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

Zylann commented 12 months ago

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:

I 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.