Piratux / CaveEditor

Cave editor using Godot and godot_voxel module.
MIT License
3 stars 1 forks source link

Consider integrating do_flatten into godot_voxel module #3

Open Piratux opened 6 months ago

Piratux commented 6 months ago

As title says, consider adding do_flatten function to VoxelTool. This is basically do_hemisphere, with addition of gradual appearance overtime (similar to that of Unreal Engine voxel plugin flatten tool):

// Apply falloff for gradual effect
float weight = std::max(0.0f, (sphere_radius - dist) / sphere_radius);

do_flatten source code example (outdated, but gets the idea across):

void do_flatten(const VoxelBufferInternal &src, VoxelBufferInternal &dst, Vector3 flat_direction, float smoothness, Vector3f sphere_pos,
        float sphere_radius, float sdf_scale, bool mode_add) {
    ZN_PROFILE_SCOPE();

    const Vector3i dst_size = src.get_size();

    ZN_ASSERT_RETURN(sphere_radius > 0);

    ZN_ASSERT_RETURN(dst_size.x > 0);
    ZN_ASSERT_RETURN(dst_size.y > 0);
    ZN_ASSERT_RETURN(dst_size.z > 0);

    dst.create(dst_size);

    const Vector3 sphere_pos_vec3 = Vector3(sphere_pos.x, sphere_pos.y, sphere_pos.z);

    Vector3 dst_pos;
    Vector3 center = Vector3(0, 0, 0);
    // TODO: avoid offsetting plane to go through center?
    real_t plane_d = 0;
    for (dst_pos.z = 0; dst_pos.z < dst_size.z; ++dst_pos.z) {
        for (dst_pos.x = 0; dst_pos.x < dst_size.x; ++dst_pos.x) {
            for (dst_pos.y = 0; dst_pos.y < dst_size.y; ++dst_pos.y) {
                const float src_sd = src.get_voxel_f(dst_pos, VoxelBufferInternal::CHANNEL_SDF);

                Vector3 pos = dst_pos - sphere_pos_vec3;
                float sd_new = sdf_scale *
                math::sdf_smooth_subtract( //
                        math::sdf_sphere(pos, center, sphere_radius), //
                        math::sdf_plane(pos, flat_direction, plane_d), smoothness);

                float sd = 0.0f;

                if (mode_add){
                    sd = math::sdf_union(src_sd, sd_new);
                }
                else{
                    sd = math::sdf_subtract(src_sd, sd_new);
                }

                float dist = pos.length();
                // Apply falloff for gradual effect
                float weight = std::max(0.0f, (sphere_radius - dist) / sphere_radius);

                // TODO: consider adding parameter that controls falloff
                weight = math::clamp(weight * 2.0, 0.1, 1.0);

                sd = Math::lerp(src_sd, sd, weight);

                dst.set_voxel_f(sd, dst_pos, VoxelBufferInternal::CHANNEL_SDF);
            }
        }
    }
}
Piratux commented 3 months ago

Might be preferable to implement general falloff parameter instead, that way all tool edits would benefit from it.