2020-01-26 22:43:47 +00:00
|
|
|
#ifndef VOXEL_GENERATOR_HEIGHTMAP_H
|
|
|
|
#define VOXEL_GENERATOR_HEIGHTMAP_H
|
2020-01-21 22:41:55 +00:00
|
|
|
|
2020-12-18 21:19:02 +00:00
|
|
|
#include "../../storage/voxel_buffer.h"
|
|
|
|
#include "../voxel_generator.h"
|
2021-12-13 21:38:10 +00:00
|
|
|
#include <core/io/image.h>
|
2020-01-21 22:41:55 +00:00
|
|
|
|
2020-01-26 22:34:26 +00:00
|
|
|
class VoxelGeneratorHeightmap : public VoxelGenerator {
|
|
|
|
GDCLASS(VoxelGeneratorHeightmap, VoxelGenerator)
|
2020-01-21 22:41:55 +00:00
|
|
|
public:
|
2020-01-26 22:34:26 +00:00
|
|
|
VoxelGeneratorHeightmap();
|
2021-01-16 13:41:46 +00:00
|
|
|
~VoxelGeneratorHeightmap();
|
2020-01-21 22:41:55 +00:00
|
|
|
|
2021-09-26 17:21:44 +01:00
|
|
|
void set_channel(VoxelBuffer::ChannelId p_channel);
|
2020-02-15 03:12:13 +08:00
|
|
|
VoxelBuffer::ChannelId get_channel() const;
|
|
|
|
int get_used_channels_mask() const override;
|
|
|
|
|
2020-01-21 23:57:22 +00:00
|
|
|
void set_height_start(float start);
|
|
|
|
float get_height_start() const;
|
2020-01-21 22:41:55 +00:00
|
|
|
|
|
|
|
void set_height_range(float range);
|
|
|
|
float get_height_range() const;
|
|
|
|
|
2020-01-26 20:08:25 +00:00
|
|
|
void set_iso_scale(float iso_scale);
|
|
|
|
float get_iso_scale() const;
|
|
|
|
|
2020-01-21 22:41:55 +00:00
|
|
|
protected:
|
|
|
|
template <typename Height_F>
|
2022-01-08 22:49:48 +00:00
|
|
|
Result generate(zylann::voxel::VoxelBufferInternal &out_buffer, Height_F height_func, Vector3i origin, int lod) {
|
2021-01-16 13:41:46 +00:00
|
|
|
Parameters params;
|
|
|
|
{
|
|
|
|
RWLockRead rlock(_parameters_lock);
|
|
|
|
params = _parameters;
|
|
|
|
}
|
2020-01-21 22:41:55 +00:00
|
|
|
|
2021-01-16 13:41:46 +00:00
|
|
|
const int channel = params.channel;
|
2020-01-21 22:41:55 +00:00
|
|
|
const Vector3i bs = out_buffer.get_size();
|
2022-01-08 22:49:48 +00:00
|
|
|
const bool use_sdf = channel == zylann::voxel::VoxelBufferInternal::CHANNEL_SDF;
|
2020-01-21 22:41:55 +00:00
|
|
|
|
2020-01-26 20:08:25 +00:00
|
|
|
if (origin.y > get_height_start() + get_height_range()) {
|
2020-01-21 22:41:55 +00:00
|
|
|
// The bottom of the block is above the highest ground can go (default is air)
|
2021-09-16 20:33:45 +01:00
|
|
|
Result result;
|
|
|
|
result.max_lod_hint = true;
|
|
|
|
return result;
|
2020-01-21 22:41:55 +00:00
|
|
|
}
|
2020-01-26 20:08:25 +00:00
|
|
|
if (origin.y + (bs.y << lod) < get_height_start()) {
|
2020-01-21 22:41:55 +00:00
|
|
|
// The top of the block is below the lowest ground can go
|
2021-01-16 13:41:46 +00:00
|
|
|
out_buffer.clear_channel(params.channel, use_sdf ? 0 : params.matter_type);
|
2021-09-16 20:33:45 +01:00
|
|
|
Result result;
|
|
|
|
result.max_lod_hint = true;
|
|
|
|
return result;
|
2020-01-21 22:41:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const int stride = 1 << lod;
|
|
|
|
|
|
|
|
if (use_sdf) {
|
2020-01-26 20:08:25 +00:00
|
|
|
int gz = origin.z;
|
|
|
|
|
2021-01-16 13:41:46 +00:00
|
|
|
for (int z = 0; z < bs.z; ++z, gz += stride) {
|
2020-01-26 20:08:25 +00:00
|
|
|
int gx = origin.x;
|
|
|
|
|
2021-01-16 13:41:46 +00:00
|
|
|
for (int x = 0; x < bs.x; ++x, gx += stride) {
|
|
|
|
float h = params.range.xform(height_func(gx, gz));
|
2020-01-26 20:08:25 +00:00
|
|
|
int gy = origin.y;
|
|
|
|
for (int y = 0; y < bs.y; ++y, gy += stride) {
|
2021-01-16 13:41:46 +00:00
|
|
|
float sdf = params.iso_scale * (gy - h);
|
2020-01-26 20:08:25 +00:00
|
|
|
out_buffer.set_voxel_f(sdf, x, y, z, channel);
|
2020-01-21 22:41:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // for x
|
|
|
|
} // for z
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Blocky
|
|
|
|
|
2020-01-26 20:08:25 +00:00
|
|
|
int gz = origin.z;
|
2020-01-21 22:41:55 +00:00
|
|
|
|
2021-01-16 13:41:46 +00:00
|
|
|
for (int z = 0; z < bs.z; ++z, gz += stride) {
|
2020-01-26 20:08:25 +00:00
|
|
|
int gx = origin.x;
|
2020-01-21 22:41:55 +00:00
|
|
|
|
2021-01-16 13:41:46 +00:00
|
|
|
for (int x = 0; x < bs.x; ++x, gx += stride) {
|
2020-01-21 22:41:55 +00:00
|
|
|
// Output is blocky, so we can go for just one sample
|
2021-01-16 13:41:46 +00:00
|
|
|
float h = params.range.xform(height_func(gx, gz));
|
2020-01-26 20:08:25 +00:00
|
|
|
h -= origin.y;
|
2021-10-08 02:35:52 +01:00
|
|
|
int ih = int(h) >> lod;
|
2020-01-21 22:41:55 +00:00
|
|
|
if (ih > 0) {
|
|
|
|
if (ih > bs.y) {
|
|
|
|
ih = bs.y;
|
|
|
|
}
|
2021-01-16 13:41:46 +00:00
|
|
|
out_buffer.fill_area(
|
|
|
|
params.matter_type, Vector3i(x, 0, z), Vector3i(x + 1, ih, z + 1), channel);
|
2020-01-21 22:41:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // for x
|
|
|
|
} // for z
|
|
|
|
} // use_sdf
|
2021-09-16 20:33:45 +01:00
|
|
|
|
|
|
|
return Result();
|
2020-01-21 22:41:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static void _bind_methods();
|
|
|
|
|
2020-01-26 20:08:25 +00:00
|
|
|
struct Range {
|
2021-11-06 02:04:16 +00:00
|
|
|
float start = -50.f;
|
|
|
|
float height = 200.f;
|
2020-01-26 20:08:25 +00:00
|
|
|
|
|
|
|
inline float xform(float x) const {
|
|
|
|
return x * height + start;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-01-16 13:41:46 +00:00
|
|
|
struct Parameters {
|
2022-01-08 22:49:48 +00:00
|
|
|
zylann::voxel::VoxelBufferInternal::ChannelId channel = zylann::voxel::VoxelBufferInternal::CHANNEL_SDF;
|
2021-01-16 13:41:46 +00:00
|
|
|
int matter_type = 1;
|
|
|
|
Range range;
|
|
|
|
float iso_scale = 0.1;
|
|
|
|
};
|
|
|
|
|
2021-02-19 01:30:22 +00:00
|
|
|
RWLock _parameters_lock;
|
2021-01-16 13:41:46 +00:00
|
|
|
Parameters _parameters;
|
2020-01-21 22:41:55 +00:00
|
|
|
};
|
|
|
|
|
2020-01-26 22:43:47 +00:00
|
|
|
#endif // VOXEL_GENERATOR_HEIGHTMAP_H
|