Zylann/godot_heightmap_plugin

mesh export is not same collide with the hterrain

Closed this issue · 13 comments

I use export mesh lod 16 for server program check the collide.
run the full hterrain node on the client

and I use move_and_collide for move

but it occur different result, if far away from center. more diff between the two program.

I'm confused about what you did exactly. Why do you need to export a mesh for collision? Why can't you use the terrain itself, which generatres a heightmap collider already, which would perfectly match?

Anyways, if you're trying to use the mesh generated by the "generate mesh" tool, keep in mind that mesh was originally meant to be used for creating navigation. It's also not using exactly the same triangle topology as the collider, which might be noticeable if you scaled your terrain so much that triangles become huge or if you use very small bodies (see #439).
Finally, using lod 16 will give you a mesh that is extremely different from the full-resolution terrain, because it's being decimated 16 times, so obviously you will not get a perfect match compared to the normal terrain collider.

In order to improve the running efficiency of the server, the server does not need to render details, it only needs collisions. Therefore, I want to obtain the heightmap from it and use it as collisions for the server.

When using StaticBody with CollideShape, setting the mapdata of HeightMapShape3D to 2049 x 2049 or 2048 x 2048 is incorrect.
image

image
func BuildMap()-> void:
var heightmap_image: Image = ResourceLoader.load("res://world/maps/data/nature_map/normal.png").get_image()

heightmap_image.convert(Image.FORMAT_RF)

#var heightmap_image: Image = ResourceLoader.load("res://world/maps/data/nature_map/height.res")
#this is same, work incorrectly

var height_min: float = 0
var height_max: float = 400

heightmap_shape.get_shape().update_map_data_from_image(heightmap_image, height_min, height_max)

image

in server program ,I need a best performce for collide, without other code use cpu.
and run on a headless mode

if I use mesh, only lod1 collide same with the client, but the verticles and triangles is too much

and I dont use other on server, because the play room may close and server program will never exit.so I want keep it simple.

can you provide a headless option for these case?only use the collide with the hterrain, no detail, no color.
and there is no camera

In order to improve the running efficiency of the server, the server does not need to render details, it only needs collisions.

can you provide a headless option for these case?only use the collide with the hterrain, no detail, no color.
and there is no camera

You can already do all that, just not with a single checkbox I guess (or almost).
It's already possible to use Godot in headless mode, where the renderer will just do nothing. You can also remove detail layers eventually, or even turn off terrain processing in Node settings since all it does is generally some chunk management which is probably not needed either. With that, what will mostly remain is the collider, which is created when the terrain is loaded.

When using StaticBody with CollideShape, setting the mapdata of HeightMapShape3D to 2049 x 2049 or 2048 x 2048 is incorrect.

Not sure what you did there, I assume you tried to load the .res containing heights into a HeighMap shape?
If you want to do the heightmap collider manually, that would be another way of going about it, since that .res is just an Image resource with 32-bit float format (it should already be in the RF format). No idea what you mean by "incorrect". But if you do that you need to account for scaling, transforming and centering yourself, because HeightMapShape does automatic centering that the plugin has to adjust for.
The plugin sets the transform like this:

var trans := Transform3D(Basis(), 0.5 * Vector3(width - 1, 0, depth - 1))
# And then apply the terrain transform
trans = _terrain_transform * trans
PhysicsServer3D.body_set_state(_body_rid, PhysicsServer3D.BODY_STATE_TRANSFORM, trans)

And calculates terrain_transform like this:
func get_internal_transform() -> Transform3D:
var gt := global_transform
var it := Transform3D(gt.basis * Basis().scaled(map_scale), gt.origin)
if centered and _data != null:
var half_size := 0.5 * (_data.get_resolution() - 1.0)
it.origin += it.basis * (-Vector3(half_size, 0, half_size))
return it

Min and max heights are also calculated from the actual min and max heights of the heightmap, not hardcoded values.

var heightmap_image: Image = ResourceLoader.load("res://world/maps/data/nature_map/normal.png").get_image()

Also that code is wrong, normal.png is a normalmap, not a heightmap. You need to load height.res.

Well for sure there are more steps which you probably got wrong but I can tell you this should work if you do the same as the plugin does.

But did you read #451 (comment)? You can already configure the plugin to turn off most of its CPU usage, and GPU usage can be removed completely by running Godot in headless mode.

If you're having these problems it looks like you simply have bad hardware for the task... 2049x2049 isn't that big to run on nowadays computers, or you'd have to use an even lower resolution. And with CPU features turned off, it's super weird that you still somehow get framerate issues, because at this point the terrain does nothing during the main loop.

is there a way to set the hterrain in the game to use a certain LOD as the minimum LOD to display fixedly?

No. Also I don't see any relation between that and what you described earlier... that's going to increase resource usage, because if you're raising the minimum LOD, lower LODs won't ever display, so more chunks will have to render, which means more polygons.
If you meant the opposite, i.e never render the highest LOD for example, then you also can't do that. Instead you should just use a terrain with smaller resolution and scale it up.