2
0
Эх сурвалжийг харах

Merge pull request #55096 from lawnjelly/bvh_expanded_leaf

BVH - add option for expanded AABBs in leaves
Camille Mohr-Daurat 3 жил өмнө
parent
commit
3970f28f67

+ 6 - 0
core/math/bvh.h

@@ -704,6 +704,11 @@ private:
 		// Note that non pairable items can pair with pairable,
 		// so all types must be added to the list
 
+#ifdef BVH_EXPAND_LEAF_AABBS
+		// if using expanded AABB in the leaf, the redundancy check will already have been made
+		BOUNDS &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb;
+		item_get_AABB(p_handle, expanded_aabb);
+#else
 		// aabb check with expanded aabb. This greatly decreases processing
 		// at the cost of slightly less accurate pairing checks
 		// Note this pairing AABB is separate from the AABB in the actual tree
@@ -720,6 +725,7 @@ private:
 		// this tick, because it is vital that the AABB is kept up to date
 		expanded_aabb = aabb;
 		expanded_aabb.grow_by(tree._pairing_expansion);
+#endif
 
 		// this code is to ensure that changed items only appear once on the updated list
 		// collision checking them multiple times is not needed, and repeats the same thing

+ 10 - 0
core/math/bvh_pair.inc

@@ -59,4 +59,14 @@ struct ItemPairs {
 
 		return userdata;
 	}
+
+	// experiment : scale the pairing expansion by the number of pairs.
+	// when the number of pairs is high, the density is high and a lower collision margin is better.
+	// when there are few local pairs, a larger margin is more optimal.
+	real_t scale_expansion_margin(real_t p_margin) const {
+		real_t x = real_t(num_pairs) * (1.0 / 9.0);
+		x = MIN(x, 1.0);
+		x = 1.0 - x;
+		return p_margin * x;
+	}
 };

+ 27 - 0
core/math/bvh_public.inc

@@ -9,6 +9,13 @@ BVHHandle item_add(T *p_userdata, bool p_active, const BOUNDS &p_aabb, int32_t p
 	BVHABB_CLASS abb;
 	abb.from(p_aabb);
 
+	// NOTE that we do not expand the AABB for the first create even if
+	// leaf expansion is switched on. This is for two reasons:
+	// (1) We don't know if this object will move in future, in which case a non-expanded
+	// bound would be better...
+	// (2) We don't yet know how many objects will be paired, which is used to modify
+	// the expansion margin.
+
 	// handle to be filled with the new item ref
 	BVHHandle handle;
 
@@ -115,6 +122,15 @@ bool item_move(BVHHandle p_handle, const BOUNDS &p_aabb) {
 	BVHABB_CLASS abb;
 	abb.from(p_aabb);
 
+#ifdef BVH_EXPAND_LEAF_AABBS
+	if (USE_PAIRS) {
+		// scale the pairing expansion by the number of pairs.
+		abb.expand(_pairs[ref_id].scale_expansion_margin(_pairing_expansion));
+	} else {
+		abb.expand(_pairing_expansion);
+	}
+#endif
+
 	BVH_ASSERT(ref.tnode_id != BVHCommon::INVALID);
 	TNode &tnode = _nodes[ref.tnode_id];
 
@@ -129,9 +145,20 @@ bool item_move(BVHHandle p_handle, const BOUNDS &p_aabb) {
 		BVHABB_CLASS &leaf_abb = leaf.get_aabb(ref.item_id);
 
 		// no change?
+#ifdef BVH_EXPAND_LEAF_AABBS
+		BOUNDS leaf_aabb;
+		leaf_abb.to(leaf_aabb);
+
+		// This test should pass in a lot of cases, and by returning false we can avoid
+		// collision pairing checks later, which greatly reduces processing.
+		if (expanded_aabb_encloses_not_shrink(leaf_aabb, p_aabb)) {
+			return false;
+		}
+#else
 		if (leaf_abb == abb) {
 			return false;
 		}
+#endif
 
 #ifdef BVH_VERBOSE_MOVES
 		print_line("item_move " + itos(p_handle.id()) + "(within tnode aabb) : " + _debug_aabb_to_string(abb));

+ 3 - 0
core/math/bvh_tree.h

@@ -50,6 +50,9 @@
 
 #define BVHABB_CLASS BVH_ABB<BOUNDS, POINT>
 
+// not sure if this is better yet so making optional
+#define BVH_EXPAND_LEAF_AABBS
+
 // never do these checks in release
 #if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
 //#define BVH_VERBOSE

+ 16 - 0
doc/classes/ProjectSettings.xml

@@ -1030,6 +1030,11 @@
 			Size of the hash table used for the broad-phase 2D hash grid algorithm.
 			[b]Note:[/b] Not used if [member ProjectSettings.physics/2d/use_bvh] is enabled.
 		</member>
+		<member name="physics/2d/bvh_collision_margin" type="float" setter="" getter="" default="1.0">
+			Additional expansion applied to object bounds in the 2D physics bounding volume hierarchy. This can reduce BVH processing at the cost of a slightly coarser broadphase, which can stress the physics more in some situations.
+			The default value will work well in most situations. A value of 0.0 will turn this optimization off, and larger values may work better for larger, faster moving objects.
+			[b]Note:[/b] Used only if [member ProjectSettings.physics/2d/use_bvh] is enabled.
+		</member>
 		<member name="physics/2d/cell_size" type="int" setter="" getter="" default="128">
 			Cell size used for the broad-phase 2D hash grid algorithm (in pixels).
 			[b]Note:[/b] Not used if [member ProjectSettings.physics/2d/use_bvh] is enabled.
@@ -1109,6 +1114,11 @@
 			The default linear damp in 3D.
 			[b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_fps], [code]60[/code] by default) will bring the object to a stop in one iteration.
 		</member>
+		<member name="physics/3d/godot_physics/bvh_collision_margin" type="float" setter="" getter="" default="0.1">
+			Additional expansion applied to object bounds in the 3D physics bounding volume hierarchy. This can reduce BVH processing at the cost of a slightly coarser broadphase, which can stress the physics more in some situations.
+			The default value will work well in most situations. A value of 0.0 will turn this optimization off, and larger values may work better for larger, faster moving objects.
+			[b]Note:[/b] Used only if [member ProjectSettings.physics/3d/godot_physics/use_bvh] is enabled.
+		</member>
 		<member name="physics/3d/godot_physics/use_bvh" type="bool" setter="" getter="" default="true">
 			Enables the use of bounding volume hierarchy instead of octree for 3D physics spatial partitioning. This may give better performance.
 		</member>
@@ -1477,9 +1487,15 @@
 			See also [member rendering/quality/skinning/force_software_skinning].
 			[b]Note:[/b] When the software skinning fallback is triggered, custom vertex shaders will behave in a different way, because the bone transform will be already applied to the modelview matrix.
 		</member>
+		<member name="rendering/quality/spatial_partitioning/bvh_collision_margin" type="float" setter="" getter="" default="0.1">
+			Additional expansion applied to object bounds in the 3D rendering bounding volume hierarchy. This can reduce BVH processing at the cost of a slightly reduced accuracy.
+			The default value will work well in most situations. A value of 0.0 will turn this optimization off, and larger values may work better for larger, faster moving objects.
+			[b]Note:[/b] Used only if [member ProjectSettings.rendering/quality/spatial_partitioning/use_bvh] is enabled.
+		</member>
 		<member name="rendering/quality/spatial_partitioning/render_tree_balance" type="float" setter="" getter="" default="0.0">
 			The rendering octree balance can be changed to favor smaller ([code]0[/code]), or larger ([code]1[/code]) branches.
 			Larger branches can increase performance significantly in some projects.
+			[b]Note:[/b] Not used if [member ProjectSettings.rendering/quality/spatial_partitioning/use_bvh] is enabled.
 		</member>
 		<member name="rendering/quality/spatial_partitioning/use_bvh" type="bool" setter="" getter="" default="true">
 			Enables the use of bounding volume hierarchy instead of octree for rendering spatial partitioning. This may give better performance.

+ 4 - 1
main/main.cpp

@@ -176,8 +176,11 @@ static String get_full_version_string() {
 // FIXME: Could maybe be moved to PhysicsServerManager and Physics2DServerManager directly
 // to have less code in main.cpp.
 void initialize_physics() {
-	// This must be defined BEFORE the 3d physics server is created
+	// This must be defined BEFORE the 3d physics server is created,
+	// otherwise it won't always show up in the project settings page.
 	GLOBAL_DEF("physics/3d/godot_physics/use_bvh", true);
+	GLOBAL_DEF("physics/3d/godot_physics/bvh_collision_margin", 0.1);
+	ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/godot_physics/bvh_collision_margin", PropertyInfo(Variant::REAL, "physics/3d/godot_physics/bvh_collision_margin", PROPERTY_HINT_RANGE, "0.0,2.0,0.01"));
 
 	/// 3D Physics Server
 	physics_server = PhysicsServerManager::new_server(ProjectSettings::get_singleton()->get(PhysicsServerManager::setting_property_name));

+ 1 - 0
servers/physics/broad_phase_bvh.cpp

@@ -127,6 +127,7 @@ BroadPhaseSW *BroadPhaseBVH::_create() {
 
 BroadPhaseBVH::BroadPhaseBVH() {
 	bvh.params_set_thread_safe(GLOBAL_GET("rendering/threads/thread_safe_bvh"));
+	bvh.params_set_pairing_expansion(GLOBAL_GET("physics/3d/godot_physics/bvh_collision_margin"));
 	bvh.set_pair_callback(_pair_callback, this);
 	bvh.set_unpair_callback(_unpair_callback, this);
 	bvh.set_check_pair_callback(_check_pair_callback, this);

+ 1 - 0
servers/physics_2d/broad_phase_2d_bvh.cpp

@@ -123,6 +123,7 @@ BroadPhase2DSW *BroadPhase2DBVH::_create() {
 
 BroadPhase2DBVH::BroadPhase2DBVH() {
 	bvh.params_set_thread_safe(GLOBAL_GET("rendering/threads/thread_safe_bvh"));
+	bvh.params_set_pairing_expansion(GLOBAL_GET("physics/2d/bvh_collision_margin"));
 	bvh.set_pair_callback(_pair_callback, this);
 	bvh.set_unpair_callback(_unpair_callback, this);
 	bvh.set_check_pair_callback(_check_pair_callback, this);

+ 2 - 0
servers/physics_2d/physics_2d_server_sw.cpp

@@ -1317,6 +1317,8 @@ Physics2DServerSW::Physics2DServerSW() {
 	GLOBAL_DEF("physics/2d/bp_hash_table_size", 4096);
 	GLOBAL_DEF("physics/2d/cell_size", 128);
 	GLOBAL_DEF("physics/2d/large_object_surface_threshold_in_cells", 512);
+	GLOBAL_DEF("physics/2d/bvh_collision_margin", 1.0);
+	ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/bvh_collision_margin", PropertyInfo(Variant::REAL, "physics/2d/bvh_collision_margin", PROPERTY_HINT_RANGE, "0.0,20.0,0.1"));
 
 	bool use_bvh = GLOBAL_GET("physics/2d/use_bvh");
 

+ 4 - 0
servers/visual/visual_server_scene.cpp

@@ -100,6 +100,7 @@ void VisualServerScene::camera_set_use_vertical_aspect(RID p_camera, bool p_enab
 
 VisualServerScene::SpatialPartitioningScene_BVH::SpatialPartitioningScene_BVH() {
 	_bvh.params_set_thread_safe(GLOBAL_GET("rendering/threads/thread_safe_bvh"));
+	_bvh.params_set_pairing_expansion(GLOBAL_GET("rendering/quality/spatial_partitioning/bvh_collision_margin"));
 }
 
 VisualServerScene::SpatialPartitionID VisualServerScene::SpatialPartitioningScene_BVH::create(Instance *p_userdata, const AABB &p_aabb, int p_subindex, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask) {
@@ -4119,6 +4120,9 @@ VisualServerScene::VisualServerScene() {
 	render_pass = 1;
 	singleton = this;
 	_use_bvh = GLOBAL_DEF("rendering/quality/spatial_partitioning/use_bvh", true);
+	GLOBAL_DEF("rendering/quality/spatial_partitioning/bvh_collision_margin", 0.1);
+	ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/spatial_partitioning/bvh_collision_margin", PropertyInfo(Variant::REAL, "rendering/quality/spatial_partitioning/bvh_collision_margin", PROPERTY_HINT_RANGE, "0.0,2.0,0.01"));
+
 	_visual_server_callbacks = nullptr;
 }