Переглянути джерело

Merge pull request #44656 from reduz/cull-fixes-and-optimizations

Cull fixes and optimizations
Juan Linietsky 4 роки тому
батько
коміт
545c894614

+ 27 - 0
core/math/aabb.h

@@ -107,6 +107,9 @@ public:
 	Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
 	Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
 
+	_FORCE_INLINE_ void quantize(float p_unit);
+	_FORCE_INLINE_ AABB quantized(float p_unit) const;
+
 	_FORCE_INLINE_ void set_end(const Vector3 &p_end) {
 		size = p_end - position;
 	}
@@ -427,4 +430,28 @@ void AABB::grow_by(real_t p_amount) {
 	size.z += 2.0 * p_amount;
 }
 
+void AABB::quantize(float p_unit) {
+	size += position;
+
+	position.x -= Math::fposmodp(position.x, p_unit);
+	position.y -= Math::fposmodp(position.y, p_unit);
+	position.z -= Math::fposmodp(position.z, p_unit);
+
+	size.x -= Math::fposmodp(size.x, p_unit);
+	size.y -= Math::fposmodp(size.y, p_unit);
+	size.z -= Math::fposmodp(size.z, p_unit);
+
+	size.x += p_unit;
+	size.y += p_unit;
+	size.z += p_unit;
+
+	size -= position;
+}
+
+AABB AABB::quantized(float p_unit) const {
+	AABB ret = *this;
+	ret.quantize(p_unit);
+	return ret;
+}
+
 #endif // AABB_H

+ 5 - 4
core/math/dynamic_bvh.cpp

@@ -351,17 +351,17 @@ void DynamicBVH::_update(Node *leaf, int lookahead) {
 	_insert_leaf(root, leaf);
 }
 
-void DynamicBVH::update(const ID &p_id, const AABB &p_box) {
-	ERR_FAIL_COND(!p_id.is_valid());
+bool DynamicBVH::update(const ID &p_id, const AABB &p_box) {
+	ERR_FAIL_COND_V(!p_id.is_valid(), false);
 	Node *leaf = p_id.node;
 
 	Volume volume;
 	volume.min = p_box.position;
 	volume.max = p_box.position + p_box.size;
 
-	if ((leaf->volume.min == volume.min) && (leaf->volume.max == volume.max)) {
+	if (leaf->volume.min.is_equal_approx(volume.min) && leaf->volume.max.is_equal_approx(volume.max)) {
 		// noop
-		return;
+		return false;
 	}
 
 	Node *base = _remove_leaf(leaf);
@@ -375,6 +375,7 @@ void DynamicBVH::update(const ID &p_id, const AABB &p_box) {
 	}
 	leaf->volume = volume;
 	_insert_leaf(base, leaf);
+	return true;
 }
 
 void DynamicBVH::remove(const ID &p_id) {

+ 1 - 1
core/math/dynamic_bvh.h

@@ -281,7 +281,7 @@ public:
 	void optimize_top_down(int bu_threshold = 128);
 	void optimize_incremental(int passes);
 	ID insert(const AABB &p_box, void *p_userdata);
-	void update(const ID &p_id, const AABB &p_box);
+	bool update(const ID &p_id, const AABB &p_box);
 	void remove(const ID &p_id);
 	void get_elements(List<ID> *r_elements);
 

+ 17 - 0
core/math/math_funcs.h

@@ -198,6 +198,23 @@ public:
 		value += 0.0;
 		return value;
 	}
+	static _ALWAYS_INLINE_ float fposmodp(float p_x, float p_y) {
+		float value = Math::fmod(p_x, p_y);
+		if (value < 0) {
+			value += p_y;
+		}
+		value += 0.0;
+		return value;
+	}
+	static _ALWAYS_INLINE_ double fposmodp(double p_x, double p_y) {
+		double value = Math::fmod(p_x, p_y);
+		if (value < 0) {
+			value += p_y;
+		}
+		value += 0.0;
+		return value;
+	}
+
 	static _ALWAYS_INLINE_ int posmod(int p_x, int p_y) {
 		int value = p_x % p_y;
 		if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {

+ 23 - 4
servers/rendering/renderer_scene_cull.cpp

@@ -1065,20 +1065,37 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
 	p_instance->transformed_aabb = new_aabb;
 
 	if (p_instance->scenario == nullptr || !p_instance->visible || Math::is_zero_approx(p_instance->transform.basis.determinant())) {
+		p_instance->prev_transformed_aabb = p_instance->transformed_aabb;
 		return;
 	}
 
+	//quantize to improve moving object performance
+	AABB bvh_aabb = p_instance->transformed_aabb;
+
+	if (p_instance->indexer_id.is_valid() && bvh_aabb != p_instance->prev_transformed_aabb) {
+		//assume motion, see if bounds need to be quantized
+		AABB motion_aabb = bvh_aabb.merge(p_instance->prev_transformed_aabb);
+		float motion_longest_axis = motion_aabb.get_longest_axis_size();
+		float longest_axis = p_instance->transformed_aabb.get_longest_axis_size();
+
+		if (motion_longest_axis < longest_axis * 2) {
+			//moved but not a lot, use motion aabb quantizing
+			float quantize_size = Math::pow(2.0, Math::ceil(Math::log(motion_longest_axis) / Math::log(2.0))) * 0.5; //one fifth
+			bvh_aabb.quantize(quantize_size);
+		}
+	}
+
 	if (!p_instance->indexer_id.is_valid()) {
 		if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
-			p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].insert(p_instance->transformed_aabb, p_instance);
+			p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].insert(bvh_aabb, p_instance);
 		} else {
-			p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].insert(p_instance->transformed_aabb, p_instance);
+			p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].insert(bvh_aabb, p_instance);
 		}
 	} else {
 		if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
-			p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].update(p_instance->indexer_id, p_instance->transformed_aabb);
+			p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].update(p_instance->indexer_id, bvh_aabb);
 		} else {
-			p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].update(p_instance->indexer_id, p_instance->transformed_aabb);
+			p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].update(p_instance->indexer_id, bvh_aabb);
 		}
 	}
 
@@ -1124,6 +1141,8 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
 	}
 
 	pair.pair();
+
+	p_instance->prev_transformed_aabb = p_instance->transformed_aabb;
 }
 
 void RendererSceneCull::_unpair_instance(Instance *p_instance) {

+ 1 - 0
servers/rendering/renderer_scene_render.h

@@ -172,6 +172,7 @@ public:
 
 		AABB aabb;
 		AABB transformed_aabb;
+		AABB prev_transformed_aabb;
 
 		struct InstanceShaderParameter {
 			int32_t index = -1;