Merge pull request #55096 from lawnjelly/bvh_expanded_leaf

BVH - add option for expanded AABBs in leaves
This commit is contained in:
Camille Mohr-Daurat 2021-11-22 09:37:16 -07:00 committed by GitHub
commit 3970f28f67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 74 additions and 1 deletions

View file

@ -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

View file

@ -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;
}
};

View file

@ -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));

View file

@ -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

View file

@ -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.

View file

@ -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));

View file

@ -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);

View file

@ -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);

View file

@ -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");

View file

@ -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;
}