I’m importing external models from Blender into Godot, and creating a HeightMapShape3D for the “landscape”. I want to still be able to detect which material my objects (in this case a vehicle) are on top of, but can’t use collisions, because HeightMapShape3D is one contiguous object, and I have grass, road, dirt, etc. in my landscape.
The way I’ve chosen to resolve this is to use python scripting in Blender to create 2D polygons that describe the outlines of the different materials in my landscape. I then have a function that takes a Vector3 and converts that to a Vector2 and then checks which of my polygons the point falls within using Geometry2D.is_point_in_polygon. Based on that I can say “we’re on a road” or “we’re on grass”.
Does this seem like a terrible idea, performance-wise? I would imagine Geometry2D.is_point_in_polygon is quite quick, but I’m new-ish to Godot and don’t know too much about to how confirm this.
The other approach I’ve seen in https://youtu.be/WhMfocT9l-o?si=2gRXIvvX0D7GvCMZ seems a bit complicated and limited to a certain number of materials (create a camera and render vertex painting).
If anyone’s interested I can provide more detail in terms of either the script to extract polygons from Blender or the Godot side of things. One optimisation I’m planning it to store the “last” polygon we were on, and always check that first so we don’t iterate through them all each time.
I’d like to back you up and ask, “How come?” What problem are you trying to solve by being able to know what type of terrain your vehicle is on?
My thought is since this is something you have in Blender, I would use Blender to make a solution. Specifically, I would separate out your different terrains as different objects. You would still export it as one overall object with pieces. Just like if you created a character model and exported the various pieces so you could animate it.
In this case, you create a different “piece” for each type of terrain. They will all interlock and make one object. However when you import on the Advanced Import tab you can control how the collisions are handled, and you can assign physics materials to each piece.
This goes back to my original question. If you just want different physics for these terrain types, having different physics materials you can apply to each piece should solve your problem.
What you’re suggesting is certainly possible, but only if I decide not to use HeightMapShape3D to define the collision object for the landscape. My model is pretty large (the portion that I care about is approx 1500 x 1500), and I assumed that HeightMapShape3D was the most efficient way of defining a collision object for such a large area.
I am still defining other collisions objects for buildings, etc. on top of my landscape, but I assumed if I just tried to use other collision primitives for a landscape I’d run into performance issues.
How come? You can use one HeightMapShape3D for each piece.
As far as performance, the docs say:
Performance:HeightMapShape3D is faster to check collisions against than ConcavePolygonShape3D, but it is significantly slower than primitive shapes like BoxShape3D.
Hmm, maybe I’m misunderstanding how HeightMapShape3D works. My understanding is that it’s a grid of fixed size (defined by map_depth and map_width), so I don’t see how you could assign that to different meshes that might interlock in complex ways.
It might take some tweaking, but basically it’d just be flat for the missing parts.
However another solution would just be to put some Area3Ds over roads, etc and when the player is in them, apply the terrain modifications for that area. It would be more performant than using the HeightMapShape3D info to determine that.
I don’t think this would work. The map_data is evenly spaced at 1m intervals, so you wouldn’t have a way to be precise about which part is flat/not part of “this” HeightMapShape3D.
Another option would be to have a RayCast3D pointing down from the car, but you’d have to have some way to take the collision data and convert it to a physics map somehow.