# How do I make a collision shape from a heightmap!?

Attention Topic was automatically imported from the old Question2Answer platform.

I’m a beginner with Godot and have never tried coding a 3d game before.

I’m sure that there must be a simple way to convert a heightmap to a collisionshape. I’ve tried making a collision shape and setting option “shape” to HeightMapShape. But it seems that I have to insert all the height values by hand! How can i use an heightmap image I’ve created as the heightmap?

You don’t have to set them all “by hand”. A heightmap can come from various sources, but the most common one is an image, and there is a way to pass image data to the shape.

To work with this shape, your image must be in the `FORMAT_RF` format (32-bit float precision, single channel). If your image is 8-bit, this won’t work well, because colors can only have 255 values are are quantified between 0 and 1, while heights can be somewhere between -500 to 500 for example.

I think there isn’t a built-in tool yet to set it up in the editor (only plugins), but here is a script example:

``````var heightmap = Image.new()

# Load EXR file, one of the formats Godot can handle.

# so you should make sure to convert it
heightmap.convert(Image.FORMAT_RF)

# Create the shape (if you don't have one already)
var shape = HeightMapShape.new()

# Assign size first, otherwise it won't work
shape.map_width = heightmap.get_width()
shape.map_height = heightmap.get_height()

# Assign the heights using the image's raw data.
# Because the format matches, this is straightforward
shape.map_data = heightmap.get_data()

# Now all is left to do is to assign the shape to your collision node.
``````

This still needs to be improved, both in usability and efficiency (setting width and height allocates a whole heightmap for no reason since it gets set from the image anyways).

It had just a little typo where map_height should be map_depth. I also think that you shouldn’t declare shape as a variable because it’s already a property of the CollisionShape.

My code looks like this:

``````extends CollisionShape

var heightmap = Image.new()

# Load EXR file, one of the formats Godot can handle.

# so you should make sure to convert it
heightmap.convert(Image.FORMAT_RF)

# Create the shape (if you don't have one already)
shape = HeightMapShape.new()

# Assign size first, otherwise it won't work
shape.map_width = heightmap.get_width()
shape.map_depth = heightmap.get_height()

# Assign the heights using the image's raw data.
# Because the format matches, this is straightforward
shape.map_data = heightmap.get_data()

# Now all is left to do is to assign the shape to your collision node.
``````

But when I try running the code it throws this error message:

I noticed that Godot docs says that map_data data type should be PoolRealArray not PoolByteArray. Could this be the problem?

Kimmo_12345 | 2020-03-19 20:16

Yeah I’ve thrown out this code as an untested example, feel free to adapt

I noticed that Godot docs says that map_data data type should be PoolRealArray not PoolByteArray. Could this be the problem?

Ugh. That’s annoying.
Weeeeeell

``````var float_array = PoolRealArray()
heightmap.lock()
var i = 0
for y in heightmap.get_height():
for x in heightmap.get_width():
float_array[i] = heightmap.get_pixel(x, y).r
i += 1
heightmap.unlock()
``````

Then use `float_array` instead.

Zylann | 2020-03-19 20:22

`Invalid set index '0' (on base: 'PoolRealArray') with value of type 'float'`

Just use `float_array.append(heightmap.get_pixel(x, y).r)` instead and get rid of the counter.

Tooniis | 2020-06-30 21:16

Just give it proper size `heightmap.get_width() * heightmap.get_height()` beforehand. The reason I didnt use `append()` is because at the time, Godot was reallocating the entire array everytime a single value was added, which adds up to horrible performance loss on large maps.

Zylann | 2020-06-30 22:37