BVH - add option for expanded AABBs in leaves
This PR adds a define BVH_EXPAND_LEAF_AABBS which is set, which stores expanded AABBs in the tree instead of exact AABBs. This makes the logic less error prone when considering reciprocal collisions in the pairing, as all collision detect is now taking place between expanded AABB against expanded AABB, rather than expanded AABB against exact AABB. The flip side of this is that the intersection tests will now be less exact when expanded margins are set. All margins are now user customizable via project settings, and take account of collision pairing density to adjust the margin dynamically.
This commit is contained in:
parent
4a29f657b6
commit
211dc8cd2d
10 changed files with 74 additions and 1 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1325,6 +1325,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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue