Added iso_scale parameter to heightmap generators, which eliminates terracing. As a result, sdf_mode is now useless and was removed.
parent
7161942ee1
commit
4626b4d7a3
|
@ -3,46 +3,39 @@
|
|||
#include "../util/fixed_array.h"
|
||||
|
||||
VoxelStreamHeightmap::VoxelStreamHeightmap() {
|
||||
_heightmap.settings.range.base = -50.0;
|
||||
_heightmap.settings.range.span = 200.0;
|
||||
_heightmap.settings.mode = HeightmapSdf::SDF_VERTICAL_AVERAGE;
|
||||
}
|
||||
|
||||
void VoxelStreamHeightmap::set_channel(VoxelBuffer::ChannelId channel) {
|
||||
ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS);
|
||||
_channel = channel;
|
||||
if (_channel != VoxelBuffer::CHANNEL_SDF) {
|
||||
_heightmap.clear_cache();
|
||||
}
|
||||
}
|
||||
|
||||
VoxelBuffer::ChannelId VoxelStreamHeightmap::get_channel() const {
|
||||
return _channel;
|
||||
}
|
||||
|
||||
void VoxelStreamHeightmap::set_sdf_mode(SdfMode mode) {
|
||||
ERR_FAIL_INDEX(mode, SDF_MODE_COUNT);
|
||||
_heightmap.settings.mode = (HeightmapSdf::Mode)mode;
|
||||
}
|
||||
|
||||
VoxelStreamHeightmap::SdfMode VoxelStreamHeightmap::get_sdf_mode() const {
|
||||
return (VoxelStreamHeightmap::SdfMode)_heightmap.settings.mode;
|
||||
}
|
||||
|
||||
void VoxelStreamHeightmap::set_height_start(float start) {
|
||||
_heightmap.settings.range.base = start;
|
||||
_range.start = start;
|
||||
}
|
||||
|
||||
float VoxelStreamHeightmap::get_height_start() const {
|
||||
return _heightmap.settings.range.base;
|
||||
return _range.start;
|
||||
}
|
||||
|
||||
void VoxelStreamHeightmap::set_height_range(float range) {
|
||||
_heightmap.settings.range.span = range;
|
||||
_range.height = range;
|
||||
}
|
||||
|
||||
float VoxelStreamHeightmap::get_height_range() const {
|
||||
return _heightmap.settings.range.span;
|
||||
return _range.height;
|
||||
}
|
||||
|
||||
void VoxelStreamHeightmap::set_iso_scale(float iso_scale) {
|
||||
_iso_scale = iso_scale;
|
||||
}
|
||||
|
||||
float VoxelStreamHeightmap::get_iso_scale() const {
|
||||
return _iso_scale;
|
||||
}
|
||||
|
||||
void VoxelStreamHeightmap::_bind_methods() {
|
||||
|
@ -50,21 +43,17 @@ void VoxelStreamHeightmap::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_channel", "channel"), &VoxelStreamHeightmap::set_channel);
|
||||
ClassDB::bind_method(D_METHOD("get_channel"), &VoxelStreamHeightmap::get_channel);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_sdf_mode", "mode"), &VoxelStreamHeightmap::set_sdf_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_sdf_mode"), &VoxelStreamHeightmap::get_sdf_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_height_start", "start"), &VoxelStreamHeightmap::set_height_start);
|
||||
ClassDB::bind_method(D_METHOD("get_height_start"), &VoxelStreamHeightmap::get_height_start);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_height_range", "range"), &VoxelStreamHeightmap::set_height_range);
|
||||
ClassDB::bind_method(D_METHOD("get_height_range"), &VoxelStreamHeightmap::get_height_range);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_iso_scale", "scale"), &VoxelStreamHeightmap::set_iso_scale);
|
||||
ClassDB::bind_method(D_METHOD("get_iso_scale"), &VoxelStreamHeightmap::get_iso_scale);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "channel", PROPERTY_HINT_ENUM, VoxelBuffer::CHANNEL_ID_HINT_STRING), "set_channel", "get_channel");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_mode", PROPERTY_HINT_ENUM, HeightmapSdf::MODE_HINT_STRING), "set_sdf_mode", "get_sdf_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height_start"), "set_height_start", "get_height_start");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height_range"), "set_height_range", "get_height_range");
|
||||
|
||||
BIND_ENUM_CONSTANT(SDF_VERTICAL);
|
||||
BIND_ENUM_CONSTANT(SDF_VERTICAL_AVERAGE);
|
||||
BIND_ENUM_CONSTANT(SDF_SEGMENT);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "iso_scale"), "set_iso_scale", "get_iso_scale");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef VOXEL_STREAM_HEIGHTMAP_H
|
||||
#define VOXEL_STREAM_HEIGHTMAP_H
|
||||
|
||||
#include "../util/heightmap_sdf.h"
|
||||
#include "voxel_stream.h"
|
||||
#include <core/image.h>
|
||||
|
||||
|
@ -10,38 +9,31 @@ class VoxelStreamHeightmap : public VoxelStream {
|
|||
public:
|
||||
VoxelStreamHeightmap();
|
||||
|
||||
enum SdfMode {
|
||||
SDF_VERTICAL = HeightmapSdf::SDF_VERTICAL,
|
||||
SDF_VERTICAL_AVERAGE = HeightmapSdf::SDF_VERTICAL_AVERAGE,
|
||||
SDF_SEGMENT = HeightmapSdf::SDF_SEGMENT,
|
||||
SDF_MODE_COUNT = HeightmapSdf::SDF_MODE_COUNT
|
||||
};
|
||||
|
||||
void set_channel(VoxelBuffer::ChannelId channel);
|
||||
VoxelBuffer::ChannelId get_channel() const;
|
||||
|
||||
void set_sdf_mode(SdfMode mode);
|
||||
SdfMode get_sdf_mode() const;
|
||||
|
||||
void set_height_start(float start);
|
||||
float get_height_start() const;
|
||||
|
||||
void set_height_range(float range);
|
||||
float get_height_range() const;
|
||||
|
||||
void set_iso_scale(float iso_scale);
|
||||
float get_iso_scale() const;
|
||||
|
||||
protected:
|
||||
template <typename Height_F>
|
||||
void generate(VoxelBuffer &out_buffer, Height_F height_func, int ox, int oy, int oz, int lod) {
|
||||
void generate(VoxelBuffer &out_buffer, Height_F height_func, Vector3i origin, int lod) {
|
||||
|
||||
const int channel = _channel;
|
||||
const Vector3i bs = out_buffer.get_size();
|
||||
bool use_sdf = channel == VoxelBuffer::CHANNEL_SDF;
|
||||
|
||||
if (oy > get_height_start() + get_height_range()) {
|
||||
if (origin.y > get_height_start() + get_height_range()) {
|
||||
// The bottom of the block is above the highest ground can go (default is air)
|
||||
return;
|
||||
}
|
||||
if (oy + (bs.y << lod) < get_height_start()) {
|
||||
if (origin.y + (bs.y << lod) < get_height_start()) {
|
||||
// The top of the block is below the lowest ground can go
|
||||
out_buffer.clear_channel(_channel, use_sdf ? 0 : _matter_type);
|
||||
return;
|
||||
|
@ -51,28 +43,17 @@ protected:
|
|||
|
||||
if (use_sdf) {
|
||||
|
||||
if (lod == 0) {
|
||||
// When sampling SDF, we may need to precompute values to speed it up depending on the chosen mode.
|
||||
// Unfortunately, only LOD0 can use a cache. lower lods would require a much larger one,
|
||||
// otherwise it would interpolate along higher stride, thus voxel values depend on LOD, and then cause discontinuities.
|
||||
_heightmap.build_cache(height_func, bs.x, bs.z, ox, oz, stride);
|
||||
}
|
||||
int gz = origin.z;
|
||||
for (int z = 0; z < bs.z; ++z, gz += stride) {
|
||||
|
||||
for (int z = 0; z < bs.z; ++z) {
|
||||
for (int x = 0; x < bs.x; ++x) {
|
||||
int gx = origin.x;
|
||||
for (int x = 0; x < bs.x; ++x, gx += stride) {
|
||||
|
||||
// SDF may vary along the column so we use a helper for more precision
|
||||
|
||||
if (lod == 0) {
|
||||
_heightmap.get_column_from_cache(
|
||||
[&out_buffer, x, z, channel](int ly, float v) { out_buffer.set_voxel_f(v, x, ly, z, channel); },
|
||||
x, oy, z, bs.y, stride);
|
||||
} else {
|
||||
HeightmapSdf::get_column_stateless(
|
||||
[&out_buffer, x, z, channel](int ly, float v) { out_buffer.set_voxel_f(v, x, ly, z, channel); },
|
||||
[&height_func, this](int lx, int lz) { return _heightmap.settings.range.xform(height_func(lx, lz)); },
|
||||
_heightmap.settings.mode,
|
||||
ox + (x << lod), oy, oz + (z << lod), stride, bs.y);
|
||||
float h = _range.xform(height_func(gx, gz));
|
||||
int gy = origin.y;
|
||||
for (int y = 0; y < bs.y; ++y, gy += stride) {
|
||||
float sdf = _iso_scale * (gy - h);
|
||||
out_buffer.set_voxel_f(sdf, x, y, z, channel);
|
||||
}
|
||||
|
||||
} // for x
|
||||
|
@ -81,15 +62,15 @@ protected:
|
|||
} else {
|
||||
// Blocky
|
||||
|
||||
int gz = oz;
|
||||
int gz = origin.z;
|
||||
for (int z = 0; z < bs.z; ++z, gz += stride) {
|
||||
|
||||
int gx = ox;
|
||||
int gx = origin.x;
|
||||
for (int x = 0; x < bs.x; ++x, gx += stride) {
|
||||
|
||||
// Output is blocky, so we can go for just one sample
|
||||
float h = _heightmap.settings.range.xform(height_func(gx, gz));
|
||||
h -= oy;
|
||||
float h = _range.xform(height_func(gx, gz));
|
||||
h -= origin.y;
|
||||
int ih = int(h);
|
||||
if (ih > 0) {
|
||||
if (ih > bs.y) {
|
||||
|
@ -106,12 +87,19 @@ protected:
|
|||
private:
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
HeightmapSdf _heightmap;
|
||||
struct Range {
|
||||
float start = -50;
|
||||
float height = 200;
|
||||
|
||||
inline float xform(float x) const {
|
||||
return x * height + start;
|
||||
}
|
||||
};
|
||||
|
||||
VoxelBuffer::ChannelId _channel = VoxelBuffer::CHANNEL_TYPE;
|
||||
int _matter_type = 1;
|
||||
Range _range;
|
||||
float _iso_scale = 0.1;
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(VoxelStreamHeightmap::SdfMode)
|
||||
|
||||
#endif // VOXEL_STREAM_HEIGHTMAP_H
|
||||
|
|
|
@ -8,6 +8,15 @@ inline float get_height_repeat(Image &im, int x, int y) {
|
|||
return im.get_pixel(wrap(x, im.get_width()), wrap(y, im.get_height())).r;
|
||||
}
|
||||
|
||||
inline float get_height_blurred(Image &im, int x, int y) {
|
||||
float h = get_height_repeat(im, x, y);
|
||||
h += get_height_repeat(im, x + 1, y);
|
||||
h += get_height_repeat(im, x - 1, y);
|
||||
h += get_height_repeat(im, x, y + 1);
|
||||
h += get_height_repeat(im, x, y - 1);
|
||||
return h * 0.2f;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
VoxelStreamImage::VoxelStreamImage() {
|
||||
|
@ -21,6 +30,14 @@ Ref<Image> VoxelStreamImage::get_image() const {
|
|||
return _image;
|
||||
}
|
||||
|
||||
void VoxelStreamImage::set_blur_enabled(bool enable) {
|
||||
_blur_enabled = enable;
|
||||
}
|
||||
|
||||
bool VoxelStreamImage::is_blur_enabled() const {
|
||||
return _blur_enabled;
|
||||
}
|
||||
|
||||
void VoxelStreamImage::emerge_block(Ref<VoxelBuffer> p_out_buffer, Vector3i origin_in_voxels, int lod) {
|
||||
|
||||
ERR_FAIL_COND(_image.is_null());
|
||||
|
@ -30,9 +47,15 @@ void VoxelStreamImage::emerge_block(Ref<VoxelBuffer> p_out_buffer, Vector3i orig
|
|||
|
||||
image.lock();
|
||||
|
||||
VoxelStreamHeightmap::generate(out_buffer,
|
||||
[&image](int x, int z) { return get_height_repeat(image, x, z); },
|
||||
origin_in_voxels.x, origin_in_voxels.y, origin_in_voxels.z, lod);
|
||||
if (_blur_enabled) {
|
||||
VoxelStreamHeightmap::generate(out_buffer,
|
||||
[&image](int x, int z) { return get_height_blurred(image, x, z); },
|
||||
origin_in_voxels, lod);
|
||||
} else {
|
||||
VoxelStreamHeightmap::generate(out_buffer,
|
||||
[&image](int x, int z) { return get_height_repeat(image, x, z); },
|
||||
origin_in_voxels, lod);
|
||||
}
|
||||
|
||||
image.unlock();
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@ public:
|
|||
void set_image(Ref<Image> im);
|
||||
Ref<Image> get_image() const;
|
||||
|
||||
void set_blur_enabled(bool enable);
|
||||
bool is_blur_enabled() const;
|
||||
|
||||
void emerge_block(Ref<VoxelBuffer> p_out_buffer, Vector3i origin_in_voxels, int lod);
|
||||
|
||||
private:
|
||||
|
@ -20,6 +23,8 @@ private:
|
|||
|
||||
private:
|
||||
Ref<Image> _image;
|
||||
// Mostly here as demo/tweak. It's better recommended to use an EXR/float image.
|
||||
bool _blur_enabled = false;
|
||||
};
|
||||
|
||||
#endif // HEADER_VOXEL_STREAM_IMAGE
|
||||
|
|
|
@ -29,12 +29,12 @@ void VoxelStreamNoise2D::emerge_block(Ref<VoxelBuffer> p_out_buffer, Vector3i or
|
|||
if (_curve.is_null()) {
|
||||
VoxelStreamHeightmap::generate(out_buffer,
|
||||
[&noise](int x, int z) { return 0.5 + 0.5 * noise.get_noise_2d(x, z); },
|
||||
origin_in_voxels.x, origin_in_voxels.y, origin_in_voxels.z, lod);
|
||||
origin_in_voxels, lod);
|
||||
} else {
|
||||
Curve &curve = **_curve;
|
||||
VoxelStreamHeightmap::generate(out_buffer,
|
||||
[&noise, &curve](int x, int z) { return curve.interpolate_baked(0.5 + 0.5 * noise.get_noise_2d(x, z)); },
|
||||
origin_in_voxels.x, origin_in_voxels.y, origin_in_voxels.z, lod);
|
||||
origin_in_voxels, lod);
|
||||
}
|
||||
|
||||
out_buffer.compress_uniform_channels();
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
#include "heightmap_sdf.h"
|
||||
|
||||
const char *HeightmapSdf::MODE_HINT_STRING = "Vertical,VerticalAverage,Segment";
|
||||
|
||||
float HeightmapSdf::get_constrained_segment_sdf(float p_yp, float p_ya, float p_yb, float p_xb) {
|
||||
|
||||
// P
|
||||
// . B
|
||||
// . /
|
||||
// . / y
|
||||
// ./ |
|
||||
// A o--x
|
||||
|
||||
float s = p_yp >= p_ya ? 1 : -1;
|
||||
|
||||
if (Math::absf(p_yp - p_ya) > 1.f && Math::absf(p_yp - p_yb) > 1.f) {
|
||||
return s;
|
||||
}
|
||||
|
||||
Vector2 p(0, p_yp);
|
||||
Vector2 a(0, p_ya);
|
||||
Vector2 b(p_xb, p_yb);
|
||||
Vector2 closest_point;
|
||||
|
||||
// TODO Optimize given the particular case we are in
|
||||
Vector2 n = b - a;
|
||||
real_t l2 = n.length_squared();
|
||||
if (l2 < 1e-20) {
|
||||
closest_point = a; // Both points are the same, just give any.
|
||||
} else {
|
||||
real_t d = n.dot(p - a) / l2;
|
||||
if (d <= 0.0) {
|
||||
closest_point = a; // Before first point.
|
||||
} else if (d >= 1.0) {
|
||||
closest_point = b; // After first point.
|
||||
} else {
|
||||
closest_point = a + n * d; // Inside.
|
||||
}
|
||||
}
|
||||
|
||||
return s * closest_point.distance_to(p);
|
||||
}
|
|
@ -1,244 +0,0 @@
|
|||
#ifndef HEIGHTMAP_SDF_H
|
||||
#define HEIGHTMAP_SDF_H
|
||||
|
||||
#include "array_slice.h"
|
||||
#include <core/math/vector2.h>
|
||||
#include <vector>
|
||||
|
||||
// Utility class to sample a heightmap as a 3D distance field.
|
||||
// Provides a stateless function, or an accelerated area method using a cache.
|
||||
// Note: this isn't general-purpose, it has been made for several use cases found in this module.
|
||||
class HeightmapSdf {
|
||||
public:
|
||||
enum Mode {
|
||||
SDF_VERTICAL = 0, // Lowest quality, fastest
|
||||
SDF_VERTICAL_AVERAGE,
|
||||
SDF_SEGMENT,
|
||||
SDF_MODE_COUNT
|
||||
};
|
||||
|
||||
static const char *MODE_HINT_STRING;
|
||||
|
||||
struct Range {
|
||||
float base = -50;
|
||||
float span = 200;
|
||||
|
||||
inline float xform(float x) const {
|
||||
return x * span + base;
|
||||
}
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
Mode mode = SDF_VERTICAL;
|
||||
Range range;
|
||||
};
|
||||
|
||||
struct Cache {
|
||||
std::vector<float> heights;
|
||||
int size_z = 0;
|
||||
|
||||
inline float get_local(int x, int z) const {
|
||||
const int i = x + z * size_z;
|
||||
#ifdef TOOLS_ENABLED
|
||||
CRASH_COND(i >= heights.size());
|
||||
#endif
|
||||
return heights[i];
|
||||
}
|
||||
};
|
||||
|
||||
Settings settings;
|
||||
|
||||
// Precomputes data to accelerate the next area fetch.
|
||||
// ox, oz and stride are in world space.
|
||||
// Coordinates sent to the height function are in world space.
|
||||
template <typename Height_F>
|
||||
void build_cache(Height_F height_func, int cache_size_x, int cache_size_z, int ox, int oz, int stride) {
|
||||
|
||||
CRASH_COND(cache_size_x < 0);
|
||||
CRASH_COND(cache_size_z < 0);
|
||||
|
||||
if (settings.mode == SDF_SEGMENT) {
|
||||
// Pad
|
||||
cache_size_x += 2;
|
||||
cache_size_z += 2;
|
||||
ox -= stride;
|
||||
oz -= stride;
|
||||
}
|
||||
|
||||
unsigned int area = cache_size_x * cache_size_z;
|
||||
if (area != _cache.heights.size()) {
|
||||
_cache.heights.resize(area);
|
||||
}
|
||||
_cache.size_z = cache_size_z;
|
||||
|
||||
int i = 0;
|
||||
int gz = oz;
|
||||
|
||||
for (int z = 0; z < cache_size_z; ++z, gz += stride) {
|
||||
int gx = ox;
|
||||
|
||||
for (int x = 0; x < cache_size_x; ++x, gx += stride) {
|
||||
|
||||
switch (settings.mode) {
|
||||
|
||||
case SDF_VERTICAL:
|
||||
case SDF_SEGMENT:
|
||||
_cache.heights[i++] = settings.range.xform(height_func(gx, gz));
|
||||
break;
|
||||
|
||||
case SDF_VERTICAL_AVERAGE:
|
||||
_cache.heights[i++] = settings.range.xform(get_height_blurred(height_func, gx, gz));
|
||||
break;
|
||||
|
||||
default:
|
||||
CRASH_NOW();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear_cache() {
|
||||
_cache.heights.clear();
|
||||
}
|
||||
|
||||
// Core functionality is here.
|
||||
// Slower than using a cache, but doesn't rely on heap memory.
|
||||
// fx and fz use the same coordinate space as the height function.
|
||||
// gy0 and stride are world space.
|
||||
// Coordinates sent to the output function are in grid space.
|
||||
template <typename Height_F, typename Output_F>
|
||||
static void get_column_stateless(Output_F output_func, Height_F height_func, Mode mode, int fx, int gy0, int fz, int stride, int size_y) {
|
||||
|
||||
switch (mode) {
|
||||
|
||||
case SDF_VERTICAL: {
|
||||
float h = height_func(fx, fz);
|
||||
int gy = gy0;
|
||||
for (int y = 0; y < size_y; ++y, gy += stride) {
|
||||
float sdf = gy - h;
|
||||
output_func(y, sdf);
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDF_VERTICAL_AVERAGE: {
|
||||
float h = get_height_blurred(height_func, fx, fz);
|
||||
int gy = gy0;
|
||||
for (int y = 0; y < size_y; ++y, gy += stride) {
|
||||
float sdf = gy - h;
|
||||
output_func(y, sdf);
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDF_SEGMENT: {
|
||||
// Calculate distance to 8 segments going from the point at XZ to its neighbor points,
|
||||
// and pick the smallest distance.
|
||||
// Note: stride is intentionally not used for neighbor sampling.
|
||||
// More than 1 isn't really supported, because it causes inconsistencies when nearest-neighbor LOD is used.
|
||||
|
||||
float h0 = height_func(fx - 1, fz - 1);
|
||||
float h1 = height_func(fx, fz - 1);
|
||||
float h2 = height_func(fx + 1, fz - 1);
|
||||
|
||||
float h3 = height_func(fx - 1, fz);
|
||||
float h4 = height_func(fx, fz);
|
||||
float h5 = height_func(fx + 1, fz);
|
||||
|
||||
float h6 = height_func(fx - 1, fz + 1);
|
||||
float h7 = height_func(fx, fz + 1);
|
||||
float h8 = height_func(fx + 1, fz + 1);
|
||||
|
||||
const float sqrt2 = 1.414213562373095;
|
||||
|
||||
int gy = gy0;
|
||||
for (int y = 0; y < size_y; ++y, gy += stride) {
|
||||
|
||||
float sdf0 = get_constrained_segment_sdf(gy, h4, h0, sqrt2);
|
||||
float sdf1 = get_constrained_segment_sdf(gy, h4, h1, 1);
|
||||
float sdf2 = get_constrained_segment_sdf(gy, h4, h2, sqrt2);
|
||||
|
||||
float sdf3 = get_constrained_segment_sdf(gy, h4, h3, 1);
|
||||
float sdf4 = gy - h4;
|
||||
float sdf5 = get_constrained_segment_sdf(gy, h4, h5, 1);
|
||||
|
||||
float sdf6 = get_constrained_segment_sdf(gy, h4, h6, sqrt2);
|
||||
float sdf7 = get_constrained_segment_sdf(gy, h4, h7, 1);
|
||||
float sdf8 = get_constrained_segment_sdf(gy, h4, h8, sqrt2);
|
||||
|
||||
float sdf = sdf4;
|
||||
|
||||
if (Math::absf(sdf0) < Math::absf(sdf)) {
|
||||
sdf = sdf0;
|
||||
}
|
||||
if (Math::absf(sdf1) < Math::absf(sdf)) {
|
||||
sdf = sdf1;
|
||||
}
|
||||
if (Math::absf(sdf2) < Math::absf(sdf)) {
|
||||
sdf = sdf2;
|
||||
}
|
||||
if (Math::absf(sdf3) < Math::absf(sdf)) {
|
||||
sdf = sdf3;
|
||||
}
|
||||
if (Math::absf(sdf5) < Math::absf(sdf)) {
|
||||
sdf = sdf5;
|
||||
}
|
||||
if (Math::absf(sdf6) < Math::absf(sdf)) {
|
||||
sdf = sdf6;
|
||||
}
|
||||
if (Math::absf(sdf7) < Math::absf(sdf)) {
|
||||
sdf = sdf7;
|
||||
}
|
||||
if (Math::absf(sdf8) < Math::absf(sdf)) {
|
||||
sdf = sdf8;
|
||||
}
|
||||
|
||||
output_func(y, sdf);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
CRASH_NOW();
|
||||
break;
|
||||
|
||||
} // sdf mode
|
||||
}
|
||||
|
||||
// Fastest if a cache has been built before. Prefer this when fetching areas.
|
||||
// Coordinates sent to the output function are in grid space.
|
||||
template <typename Output_F>
|
||||
inline void get_column_from_cache(Output_F output_func, int grid_x, int world_y0, int grid_z, int grid_size_y, int stride) {
|
||||
|
||||
Mode mode = settings.mode;
|
||||
|
||||
if (mode == SDF_VERTICAL_AVERAGE) {
|
||||
// Precomputed in cache, sample directly
|
||||
mode = SDF_VERTICAL;
|
||||
|
||||
} else if (mode == SDF_SEGMENT) {
|
||||
// Pad
|
||||
++grid_x;
|
||||
++grid_z;
|
||||
}
|
||||
|
||||
get_column_stateless(output_func,
|
||||
[&](int x, int z) { return _cache.get_local(x, z); },
|
||||
mode, grid_x, world_y0, grid_z, stride, grid_size_y);
|
||||
}
|
||||
|
||||
private:
|
||||
static float get_constrained_segment_sdf(float p_yp, float p_ya, float p_yb, float p_xb);
|
||||
|
||||
template <typename Height_F>
|
||||
static inline float get_height_blurred(Height_F height_func, int x, int y) {
|
||||
float h = height_func(x, y);
|
||||
h += height_func(x + 1, y);
|
||||
h += height_func(x - 1, y);
|
||||
h += height_func(x, y + 1);
|
||||
h += height_func(x, y - 1);
|
||||
return h * 0.2f;
|
||||
}
|
||||
|
||||
Cache _cache;
|
||||
};
|
||||
|
||||
#endif // HEIGHTMAP_SDF_H
|
Loading…
Reference in New Issue