feat: bounds-based mesh reloading
This commit is contained in:
parent
953e4abe5b
commit
226c821454
7 changed files with 93 additions and 38 deletions
|
|
@ -78,6 +78,7 @@ void Terrain::construct_chunk_grid() {
|
|||
this->meshes.clear();
|
||||
size_t const chunks_per_side{ this->side_length / this->chunk_size };
|
||||
Vector3 const origin{ (float)this->chunk_size / 2.f, 0.f, (float)this->chunk_size / 2.f };
|
||||
this->workload_lock.lock();
|
||||
for (size_t y{ 0 }; y < chunks_per_side; ++y) {
|
||||
for (size_t x{ 0 }; x < chunks_per_side; ++x) {
|
||||
TerrainChunkMesh *chunk{ memnew(TerrainChunkMesh) };
|
||||
|
|
@ -88,8 +89,10 @@ void Terrain::construct_chunk_grid() {
|
|||
add_child(chunk);
|
||||
chunk->set_owner(this);
|
||||
this->meshes.push_back(chunk);
|
||||
this->workload.push_back(chunk);
|
||||
}
|
||||
}
|
||||
this->workload_lock.unlock();
|
||||
}
|
||||
|
||||
float Terrain::height_at(Vector2 world_coordinate) {
|
||||
|
|
@ -103,6 +106,16 @@ float Terrain::height_at(Vector2 world_coordinate) {
|
|||
return height;
|
||||
}
|
||||
|
||||
void Terrain::push_changed(Rect2 area) {
|
||||
for (TerrainChunkMesh *mesh : this->meshes) {
|
||||
this->workload_lock.lock();
|
||||
if (area.intersects(mesh->get_bounds()) && !this->workload.has(mesh)) {
|
||||
workload.push_back(mesh);
|
||||
}
|
||||
this->workload_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void Terrain::set_side_length(size_t length) {
|
||||
this->side_length = length;
|
||||
if (is_inside_tree()) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/math/rect2.h"
|
||||
#include "core/os/mutex.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/vector.h"
|
||||
|
|
@ -18,8 +19,8 @@ protected:
|
|||
|
||||
public:
|
||||
void construct_chunk_grid();
|
||||
void area_dirty(Vector2 from, Vector2 to);
|
||||
float height_at(Vector2 world_coordinate);
|
||||
void push_changed(Rect2 area);
|
||||
|
||||
private:
|
||||
Vector<TerrainChunkMesh *> workload{};
|
||||
|
|
|
|||
|
|
@ -60,8 +60,10 @@ void TerrainChunkMesh::_notification(int what) {
|
|||
default:
|
||||
return;
|
||||
case NOTIFICATION_READY:
|
||||
set_process_thread_group(ProcessThreadGroup::PROCESS_THREAD_GROUP_SUB_THREAD);
|
||||
this->safe_position = get_global_position();
|
||||
float const sizef{ (float)get_size() };
|
||||
this->bounds.position = { this->safe_position.x - sizef / 2.f, this->safe_position.z - sizef / 2.f };
|
||||
this->bounds.size = { sizef, sizef };
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/math/rect2.h"
|
||||
#include "macros.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/resources/mesh.h"
|
||||
|
|
@ -28,8 +29,10 @@ private:
|
|||
Terrain *terrain{ nullptr };
|
||||
size_t detail{ 1 };
|
||||
size_t size{ 1 };
|
||||
Rect2 bounds{};
|
||||
|
||||
public:
|
||||
GET_SET_FNS(Rect2, bounds);
|
||||
GET_SET_FNS(Terrain *, terrain);
|
||||
GET_SET_FNS(size_t, detail);
|
||||
GET_SET_FNS(size_t, size);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
#include "core/config/engine.h"
|
||||
#include "core/variant/variant.h"
|
||||
#include "macros.h"
|
||||
#include "terrain/terrain.h"
|
||||
#include <algorithm>
|
||||
|
||||
void TerrainModifier::_bind_methods() {
|
||||
BIND_HPROPERTY(Variant::INT, blend_mode, PROPERTY_HINT_ENUM, BlendMode_hint());
|
||||
BIND_PROPERTY(Variant::FLOAT, blend_distance);
|
||||
ADD_SIGNAL(MethodInfo(sig_changed));
|
||||
}
|
||||
|
||||
void TerrainModifier::_notification(int what) {
|
||||
|
|
@ -20,9 +20,6 @@ void TerrainModifier::_notification(int what) {
|
|||
}
|
||||
this->thread_safe_global_position = get_global_position();
|
||||
case NOTIFICATION_TRANSFORM_CHANGED:
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
emit_signal(sig_changed);
|
||||
}
|
||||
this->thread_safe_global_position = get_global_position();
|
||||
return;
|
||||
}
|
||||
|
|
@ -56,13 +53,10 @@ float TerrainModifier::blend(float under, float over) {
|
|||
}
|
||||
}
|
||||
|
||||
void TerrainModifier::changed() {
|
||||
this->dirty = true;
|
||||
emit_signal(sig_changed);
|
||||
}
|
||||
|
||||
void TerrainModifier::changed_deferred() {
|
||||
callable_mp(this, &self_type::changed).call_deferred();
|
||||
void TerrainModifier::push_changed(Rect2 area) {
|
||||
if (this->terrain) {
|
||||
this->terrain->push_changed(area);
|
||||
}
|
||||
}
|
||||
|
||||
float TerrainModifier::evaluate_at(Vector2 world_coordinate, float before) {
|
||||
|
|
@ -77,7 +71,6 @@ Vector3 TerrainModifier::get_thread_safe_global_position() const {
|
|||
|
||||
void TerrainModifier::set_blend_distance(float value) {
|
||||
this->blend_distance = value;
|
||||
emit_signal(sig_changed);
|
||||
}
|
||||
|
||||
float TerrainModifier::get_blend_distance() const {
|
||||
|
|
@ -86,15 +79,12 @@ float TerrainModifier::get_blend_distance() const {
|
|||
|
||||
void TerrainModifier::set_blend_mode(BlendMode mode) {
|
||||
this->blend_mode = mode;
|
||||
emit_signal(sig_changed);
|
||||
}
|
||||
|
||||
TerrainModifier::BlendMode TerrainModifier::get_blend_mode() const {
|
||||
return this->blend_mode;
|
||||
}
|
||||
|
||||
String const TerrainModifier::sig_changed{ "changed" };
|
||||
|
||||
void SharedMutex::lock_shared() {
|
||||
this->lock.lock();
|
||||
this->shared_count++;
|
||||
|
|
@ -127,15 +117,60 @@ void TerrainModifierDistance::_bind_methods() {
|
|||
}
|
||||
|
||||
void TerrainModifierDistance::curves_changed() {
|
||||
this->lock.lock_shared();
|
||||
this->lock.lock_exclusive();
|
||||
if (this->distance_height_curve.is_valid()) {
|
||||
this->distance_height_curve->bake();
|
||||
}
|
||||
if (this->distance_weight_curve.is_valid()) {
|
||||
this->distance_weight_curve->bake();
|
||||
}
|
||||
this->lock.unlock_exclusive();
|
||||
if (!update_bounds()) {
|
||||
push_changed(get_bounds());
|
||||
}
|
||||
}
|
||||
|
||||
bool TerrainModifierDistance::update_bounds() {
|
||||
Rect2 const before{ get_bounds() };
|
||||
Rect2 bounds{};
|
||||
Vector3 position{ get_thread_safe_global_position() };
|
||||
bounds.position = { position.x, position.z };
|
||||
bounds.size = { 0, 0 };
|
||||
this->lock.lock_shared();
|
||||
if (this->distance_weight_curve.is_valid()) {
|
||||
float const max_radius{ this->distance_weight_curve->get_max_domain() };
|
||||
float const max_diameter{ 2.f * max_radius };
|
||||
bounds.size = { max_diameter, max_diameter };
|
||||
bounds.position -= { max_radius, max_radius };
|
||||
}
|
||||
this->lock.unlock_shared();
|
||||
changed();
|
||||
this->lock.lock_exclusive();
|
||||
bool const changed{ before != bounds };
|
||||
if (changed) {
|
||||
set_bounds(bounds);
|
||||
push_changed(before);
|
||||
push_changed(bounds);
|
||||
}
|
||||
this->lock.unlock_exclusive();
|
||||
return changed;
|
||||
}
|
||||
|
||||
void TerrainModifierDistance::_notification(int what) {
|
||||
switch (what) {
|
||||
default:
|
||||
return;
|
||||
case NOTIFICATION_READY:
|
||||
update_bounds();
|
||||
set_notify_transform(true);
|
||||
return;
|
||||
case NOTIFICATION_TRANSFORM_CHANGED:
|
||||
if (is_inside_tree()) {
|
||||
if (!update_bounds()) {
|
||||
push_changed(get_bounds());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float TerrainModifierDistance::distance_at(Vector2 const &world_coordinate) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "macros.h"
|
||||
#include "scene/3d/marker_3d.h"
|
||||
#include "scene/resources/curve.h"
|
||||
#include <cmath>
|
||||
class Terrain;
|
||||
|
||||
class TerrainModifier : public Marker3D {
|
||||
|
|
@ -16,9 +17,8 @@ public:
|
|||
|
||||
protected:
|
||||
void _notification(int what);
|
||||
void changed();
|
||||
void changed_deferred();
|
||||
float blend(float under, float over);
|
||||
void push_changed(Rect2 bounds);
|
||||
|
||||
public:
|
||||
virtual float evaluate_at(Vector2 world_coordinate, float before);
|
||||
|
|
@ -27,8 +27,11 @@ private:
|
|||
float blend_distance{ 10.0 };
|
||||
BlendMode blend_mode{ Add };
|
||||
Vector3 thread_safe_global_position{};
|
||||
bool dirty{ false };
|
||||
Terrain *terrain{ nullptr };
|
||||
Rect2 bounds{ { -INFINITY, -INFINITY }, { INFINITY, INFINITY } };
|
||||
|
||||
protected:
|
||||
GET_SET_FNS(Rect2, bounds);
|
||||
|
||||
public:
|
||||
Vector3 get_thread_safe_global_position() const;
|
||||
|
|
@ -36,10 +39,7 @@ public:
|
|||
float get_blend_distance() const;
|
||||
void set_blend_mode(BlendMode mode);
|
||||
BlendMode get_blend_mode() const;
|
||||
GET_SET_FNS(bool, dirty);
|
||||
GET_SET_FNS(Terrain *, terrain);
|
||||
|
||||
static String const sig_changed;
|
||||
};
|
||||
|
||||
MAKE_TYPE_INFO(TerrainModifier::BlendMode, Variant::INT);
|
||||
|
|
@ -59,8 +59,10 @@ class TerrainModifierDistance : public TerrainModifier {
|
|||
GDCLASS(TerrainModifierDistance, TerrainModifier);
|
||||
static void _bind_methods();
|
||||
void curves_changed();
|
||||
bool update_bounds();
|
||||
|
||||
protected:
|
||||
void _notification(int what);
|
||||
virtual float distance_at(Vector2 const &world_coordinate);
|
||||
|
||||
public:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue