Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HeightMapShape3D update with Image data #87889

Merged
merged 1 commit into from
Apr 4, 2024

Conversation

smix8
Copy link
Contributor

@smix8 smix8 commented Feb 3, 2024

Adds HeightMapShape3D update with Image data.

Populating height values in a heightmap collision from an image file is a common use.
It shouldnt be required that users need to read large image data arrays with slow scripts to achieve this basic thing.

So what this pr does is add update_map_data_from_image() as a new function to HeightMapShape3D.

The function allows a single component black&white Image in format FORMAT_RF (32 bit) or FORMAT_RH (16 bit) or FORMAT_R8 (8 bit) as input and to define a minimum and maximum height range. The image pixel values read in 0.0 to 1.0 range are then remapped to those values.

The code for this was actually found in part on the PhysicsServer3D as more or less dead-code not reachable by users. It also makes far more sense to have this functionality on the collision shape directly to update the map_data. This data array is commonly used for other related stuff, like creating procedual meshes from the heightmap data.

Full usage example to create heightmap collision from an image file:

extends Node3D

func _ready() -> void:
    var heightmap_texture: Texture = ResourceLoader.load("res://heightmap_image.exr")
    var heightmap_image: Image = heightmap_texture.get_image()
    heightmap_image.convert(Image.FORMAT_RF)

    var heightmap_shape: HeightMapShape3D = HeightMapShape3D.new()
    var height_min: float = 0.0
    var height_max: float = 10.0
    heightmap_shape.update_map_data_from_image(heightmap_image, height_min, height_max)

    var static_body: StaticBody3D = StaticBody3D.new()
    var collision_shape: CollisionShape3D = CollisionShape3D.new()
    collision_shape.shape = heightmap_shape
    static_body.add_child(collision_shape)
    add_child(static_body)

@smix8 smix8 added this to the 4.3 milestone Feb 3, 2024
@smix8 smix8 requested a review from a team as a code owner February 3, 2024 03:30
@Redwarx008
Copy link
Contributor

Great feature, it would be even better if the HeightMapShape3D could be updated partially from the height map image.

doc/classes/HeightMapShape3D.xml Outdated Show resolved Hide resolved
scene/resources/height_map_shape_3d.cpp Outdated Show resolved Hide resolved
doc/classes/HeightMapShape3D.xml Show resolved Hide resolved
@smix8 smix8 force-pushed the heightmap_image branch 2 times, most recently from dfbc6d6 to 90ee092 Compare February 6, 2024 08:51
@smix8
Copy link
Contributor Author

smix8 commented Feb 6, 2024

Added error msgs and support for the lower precision formats Image::FORMAT_RH and Image::FORMAT_R8.

@Redwarx008 Partial updates (and reads) should be also made available, not only for the image but also for the normal byte array. I will see what I can do but that deserves its own pr.

@smix8 smix8 force-pushed the heightmap_image branch 2 times, most recently from 5588463 to d2722cc Compare February 6, 2024 17:04
@smix8 smix8 force-pushed the heightmap_image branch 2 times, most recently from 8ed22fc to c207190 Compare February 26, 2024 13:51
Copy link
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally (rebased on top of master 29b3d9e), it works as expected.

Testing project: test_pr_87889.zip

Screenshot_20240403_193452 png webp

Comment on lines +217 to +229
DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);

real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);

if (height_value < new_min_height) {
new_min_height = height_value;
}
if (height_value > new_max_height) {
new_max_height = height_value;
}

map_data_ptrw[i] = height_value;
}
Copy link
Member

@Calinou Calinou Apr 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this code can be moved below the switch statement, and have the default branch use return instead. This way, we can avoid repetition in the 2 branches below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not easily, the way pixel_value is calculated depends on the data type, and it needs to be calculate in the for loop for each index.

Adds HeightMapShape3D update with Image data.
@akien-mga akien-mga merged commit 734a254 into godotengine:master Apr 4, 2024
16 checks passed
@akien-mga
Copy link
Member

Thanks!

@smix8 smix8 deleted the heightmap_image branch April 6, 2024 00:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants