Added slope limit

master
Marc Gilleron 2020-12-30 23:24:30 +00:00
parent 2b292818c0
commit a766e8aefb
2 changed files with 59 additions and 6 deletions

View File

@ -217,6 +217,22 @@ void VoxelInstancer::set_layer_offset_along_normal(int layer_index, float offset
layer->offset_along_normal = offset; layer->offset_along_normal = offset;
} }
void VoxelInstancer::set_layer_min_slope_degrees(int layer_index, float degrees) {
ERR_FAIL_INDEX(layer_index, _layers.size());
Layer *layer = _layers[layer_index];
ERR_FAIL_COND(layer == nullptr);
layer->max_surface_normal_y = min(1.f, Math::cos(Math::deg2rad(clamp(degrees, -180.f, 180.f))));
}
void VoxelInstancer::set_layer_max_slope_degrees(int layer_index, float degrees) {
ERR_FAIL_INDEX(layer_index, _layers.size());
Layer *layer = _layers[layer_index];
ERR_FAIL_COND(layer == nullptr);
layer->min_surface_normal_y = max(-1.f, Math::cos(Math::deg2rad(clamp(degrees, -180.f, 180.f))));
}
void VoxelInstancer::remove_layer(int layer_index) { void VoxelInstancer::remove_layer(int layer_index) {
ERR_FAIL_INDEX(layer_index, _layers.size()); ERR_FAIL_INDEX(layer_index, _layers.size());
Layer *layer = _layers[layer_index]; Layer *layer = _layers[layer_index];
@ -326,6 +342,9 @@ void VoxelInstancer::on_block_enter(Vector3i grid_position, int lod_index, Array
const float scale_range = layer->max_scale - layer->min_scale; const float scale_range = layer->max_scale - layer->min_scale;
const bool random_vertical_flip = layer->random_vertical_flip; const bool random_vertical_flip = layer->random_vertical_flip;
const float offset_along_normal = layer->offset_along_normal; const float offset_along_normal = layer->offset_along_normal;
const float normal_min_y = layer->min_surface_normal_y;
const float normal_max_y = layer->max_surface_normal_y;
const bool slope_filter = normal_min_y != -1.f || normal_max_y != 1.f;
Vector3 global_up(0.f, 1.f, 0.f); Vector3 global_up(0.f, 1.f, 0.f);
@ -357,33 +376,61 @@ void VoxelInstancer::on_block_enter(Vector3i grid_position, int lod_index, Array
// TODO Check if that position has been edited somehow, so we can decide to not spawn there // TODO Check if that position has been edited somehow, so we can decide to not spawn there
// Or remesh from generator and compare sdf but that's expensive // Or remesh from generator and compare sdf but that's expensive
// Pick a random rotation from the floor's normal.
// Warning: sometimes mesh normals are not perfectly normalized
Vector3 axis_y; Vector3 axis_y;
// Warning: sometimes mesh normals are not perfectly normalized.
// The cause is for meshing speed on CPU. It's normalized on GPU anyways.
Vector3 surface_normal = nr[i];
bool surface_normal_is_normalized = false;
bool sphere_up_is_computed = false;
if (vertical_alignment == 0.f) { if (vertical_alignment == 0.f) {
axis_y = nr[i].normalized(); surface_normal.normalize();
surface_normal_is_normalized = true;
axis_y = surface_normal;
} else { } else {
if (_up_mode == UP_MODE_SPHERE) { if (_up_mode == UP_MODE_SPHERE) {
global_up = (block_local_transform.origin + t.origin).normalized(); global_up = (block_local_transform.origin + t.origin).normalized();
sphere_up_is_computed = true;
} }
if (vertical_alignment < 1.f) { if (vertical_alignment < 1.f) {
axis_y = nr[i].linear_interpolate(global_up, vertical_alignment).normalized(); axis_y = surface_normal.linear_interpolate(global_up, vertical_alignment).normalized();
} else { } else {
axis_y = global_up; axis_y = global_up;
} }
} }
if (slope_filter) {
if (!surface_normal_is_normalized) {
surface_normal.normalize();
}
float y = surface_normal.y;
if (_up_mode == UP_MODE_SPHERE) {
if (!sphere_up_is_computed) {
global_up = (block_local_transform.origin + t.origin).normalized();
}
y = surface_normal.dot(global_up);
}
if (y < normal_min_y || y > normal_max_y) {
// Discard
continue;
}
}
t.origin += offset_along_normal * axis_y; t.origin += offset_along_normal * axis_y;
// Allows to use two faces of a single rock to create variety in the same layer // Allows to use two faces of a single rock to create variety in the same layer
if (random_vertical_flip && (pcg1.rand() & 1) == 1) { if (random_vertical_flip && (pcg1.rand() & 1) == 1) {
axis_y = -axis_y; axis_y = -axis_y;
// TODO Should have to flip another axis as well?
} }
// Pick a random rotation from the floor's normal.
// TODO A pool of precomputed random directions would do the job too // TODO A pool of precomputed random directions would do the job too
const Vector3 dir = Vector3(pcg1.randf() - 0.5f, pcg1.randf() - 0.5f, pcg1.randf() - 0.5f); const Vector3 dir = Vector3(pcg1.randf() - 0.5f, pcg1.randf() - 0.5f, pcg1.randf() - 0.5f);
const Vector3 axis_x = axis_y.cross(dir).normalized(); const Vector3 axis_x = axis_y.cross(dir).normalized();
@ -609,6 +656,10 @@ void VoxelInstancer::_bind_methods() {
&VoxelInstancer::set_layer_random_vertical_flip); &VoxelInstancer::set_layer_random_vertical_flip);
ClassDB::bind_method(D_METHOD("set_layer_offset_along_normal", "layer_index", "offset"), ClassDB::bind_method(D_METHOD("set_layer_offset_along_normal", "layer_index", "offset"),
&VoxelInstancer::set_layer_offset_along_normal); &VoxelInstancer::set_layer_offset_along_normal);
ClassDB::bind_method(D_METHOD("set_layer_min_slope_degrees", "layer_index", "degrees"),
&VoxelInstancer::set_layer_min_slope_degrees);
ClassDB::bind_method(D_METHOD("set_layer_max_slope_degrees", "layer_index", "degrees"),
&VoxelInstancer::set_layer_max_slope_degrees);
ClassDB::bind_method(D_METHOD("remove_layer", "layer_index"), &VoxelInstancer::remove_layer); ClassDB::bind_method(D_METHOD("remove_layer", "layer_index"), &VoxelInstancer::remove_layer);
ClassDB::bind_method(D_METHOD("debug_get_block_count"), &VoxelInstancer::debug_get_block_count); ClassDB::bind_method(D_METHOD("debug_get_block_count"), &VoxelInstancer::debug_get_block_count);

View File

@ -41,6 +41,8 @@ public:
void set_layer_max_scale(int layer_index, float max_scale); void set_layer_max_scale(int layer_index, float max_scale);
void set_layer_vertical_alignment(int layer_index, float vertical_alignment); void set_layer_vertical_alignment(int layer_index, float vertical_alignment);
void set_layer_offset_along_normal(int layer_index, float offset); void set_layer_offset_along_normal(int layer_index, float offset);
void set_layer_min_slope_degrees(int layer_index, float degrees);
void set_layer_max_slope_degrees(int layer_index, float degrees);
void remove_layer(int layer_index); void remove_layer(int layer_index);
void on_block_enter(Vector3i grid_position, int lod_index, Array surface_arrays); void on_block_enter(Vector3i grid_position, int lod_index, Array surface_arrays);
@ -75,8 +77,8 @@ private:
float max_scale = 1.f; float max_scale = 1.f;
float offset_along_normal = 0.f; float offset_along_normal = 0.f;
bool random_vertical_flip = false; bool random_vertical_flip = false;
// float min_slope = 0.f; float min_surface_normal_y = -1.f;
// float max_slope = 1.f; float max_surface_normal_y = 1.f;
// float min_height = 0.f; // float min_height = 0.f;
// float max_height = 10000.f; // float max_height = 10000.f;