Merge pull request #559 from nekomatata/physics-tests-3d-update

Fixes and adjustments in 3D physics tests
This commit is contained in:
Aaron Franke
2020-12-14 20:36:01 -05:00
committed by GitHub
15 changed files with 542 additions and 21 deletions

View File

@@ -26,7 +26,7 @@ _global_script_class_icons={
[application]
config/name="Physics Tests"
config/name="3D Physics Tests"
run/main_scene="res://main.tscn"
config/icon="res://icon.png"
@@ -71,5 +71,5 @@ restart_test={
[rendering]
quality/driver/driver_name="GLES2"
environment/default_clear_color=Color( 0, 0, 0, 1 )
environment/default_clear_color=Color( 0.184314, 0.184314, 0.184314, 1 )
quality/filters/msaa=2

View File

@@ -1,10 +1,33 @@
class_name Test
extends Node
signal wait_done()
var _timer
var _timer_started = false
var _wait_physics_ticks_counter = 0
func _physics_process(_delta):
if (_wait_physics_ticks_counter > 0):
_wait_physics_ticks_counter -= 1
if (_wait_physics_ticks_counter == 0):
emit_signal("wait_done")
func create_rigidbody_box(size):
var template_shape = BoxShape.new()
template_shape.extents = 0.5 * size
var template_collision = CollisionShape.new()
template_collision.shape = template_shape
var template_body = RigidBody.new()
template_body.add_child(template_collision)
return template_body
func start_timer(timeout):
if _timer == null:
@@ -32,5 +55,10 @@ func is_timer_canceled():
return _timer.paused
func wait_for_physics_ticks(tick_count):
_wait_physics_ticks_counter = tick_count
return self
func _on_timer_done():
_timer_started = false

View File

@@ -14,6 +14,22 @@ var _tests = [
"id": "Functional Tests/Friction",
"path": "res://tests/functional/test_friction.tscn",
},
{
"id": "Functional Tests/Box Stack",
"path": "res://tests/functional/test_stack.tscn",
},
{
"id": "Functional Tests/Box Pyramid",
"path": "res://tests/functional/test_pyramid.tscn",
},
{
"id": "Functional Tests/Raycasting",
"path": "res://tests/functional/test_raycasting.tscn",
},
{
"id": "Performance Tests/Broadphase",
"path": "res://tests/performance/test_perf_broadphase.tscn",
},
{
"id": "Performance Tests/Contacts",
"path": "res://tests/performance/test_perf_contacts.tscn",

View File

@@ -0,0 +1,58 @@
extends Test
export(int, 1, 100) var height = 10
export(int, 1, 100) var width_max = 100
export(int, 1, 100) var depth_max = 1
export(Vector3) var box_size = Vector3(1.0, 1.0, 1.0)
export(Vector3) var box_spacing = Vector3(0.0, 0.0, 0.0)
func _ready():
_create_pyramid()
func _create_pyramid():
var root_node = $Pyramid
var template_shape = BoxShape.new()
template_shape.extents = 0.5 * box_size
var template_collision = CollisionShape.new()
template_collision.shape = template_shape
var template_body = RigidBody.new()
template_body.add_child(template_collision)
var pos_y = 0.5 * box_size.y + box_spacing.y
for level in height:
var level_index = height - level - 1
var num_boxes = 2 * level_index + 1
var num_boxes_width = min(num_boxes, width_max)
var num_boxes_depth = min(num_boxes, depth_max)
var row_node = Spatial.new()
row_node.transform.origin = Vector3(0.0, pos_y, 0.0)
row_node.name = "Row%02d" % (level + 1)
root_node.add_child(row_node)
var pos_x = -0.5 * (num_boxes_width - 1) * (box_size.x + box_spacing.x)
for box_index_x in num_boxes_width:
var pos_z = -0.5 * (num_boxes_depth - 1) * (box_size.z + box_spacing.z)
for box_index_z in num_boxes_depth:
var box_index = box_index_x * box_index_z
var box = template_body.duplicate()
box.transform.origin = Vector3(pos_x, 0.0, pos_z)
box.name = "Box%02d" % (box_index + 1)
row_node.add_child(box)
pos_z += box_size.z + box_spacing.z
pos_x += box_size.x + box_spacing.x
pos_y += box_size.y + box_spacing.y
template_body.queue_free()

View File

@@ -0,0 +1,16 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://tests/functional/test_pyramid.gd" type="Script" id=1]
[ext_resource path="res://tests/static_scene_plane.tscn" type="PackedScene" id=2]
[ext_resource path="res://utils/camera_orbit.gd" type="Script" id=4]
[node name="Test" type="Spatial"]
script = ExtResource( 1 )
[node name="Pyramid" type="Spatial" parent="."]
[node name="StaticBodyPlane" parent="." instance=ExtResource( 2 )]
[node name="Camera" type="Camera" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 6.62348, 22.9474 )
script = ExtResource( 4 )

View File

@@ -0,0 +1,78 @@
extends Test
var _do_raycasts = false
onready var _raycast_visuals = ImmediateGeometry.new()
func _ready():
var material = SpatialMaterial.new()
material.flags_unshaded = true
material.vertex_color_use_as_albedo = true
_raycast_visuals.material_override = material
add_child(_raycast_visuals)
move_child(_raycast_visuals, get_child_count())
yield(start_timer(0.5), "timeout")
if is_timer_canceled():
return
_do_raycasts = true
func _physics_process(_delta):
if !_do_raycasts:
return
_do_raycasts = false
Log.print_log("* Start Raycasting...")
_raycast_visuals.clear()
_raycast_visuals.begin(Mesh.PRIMITIVE_LINES)
for shape in $Shapes.get_children():
var body = shape as PhysicsBody
var space_state = body.get_world().direct_space_state
Log.print_log("* Testing: %s" % body.name)
var center = body.global_transform.origin
# Raycast entering from the top.
var res = _add_raycast(space_state, center + Vector3(0.0, 2.0, 0.0), center)
Log.print_log("Raycast in: %s" % ("HIT" if res else "NO HIT"))
# Raycast exiting from inside.
center.x -= 0.2
res = _add_raycast(space_state, center, center - Vector3(0.0, 3.0, 0.0))
Log.print_log("Raycast out: %s" % ("HIT" if res else "NO HIT"))
# Raycast all inside.
center.x += 0.4
res = _add_raycast(space_state, center, center - Vector3(0.0, 0.8, 0.0))
Log.print_log("Raycast inside: %s" % ("HIT" if res else "NO HIT"))
_raycast_visuals.end()
func _add_raycast(space_state, pos_start, pos_end):
var result = space_state.intersect_ray(pos_start, pos_end)
if result:
_raycast_visuals.set_color(Color.green)
else:
_raycast_visuals.set_color(Color.red.darkened(0.5))
# Draw raycast line.
_raycast_visuals.add_vertex(pos_start)
_raycast_visuals.add_vertex(pos_end)
# Draw raycast arrow.
_raycast_visuals.add_vertex(pos_end)
_raycast_visuals.add_vertex(pos_end + Vector3(-0.05, 0.1, 0.0))
_raycast_visuals.add_vertex(pos_end)
_raycast_visuals.add_vertex(pos_end + Vector3(0.05, 0.1, 0.0))
return result

View File

@@ -0,0 +1,74 @@
[gd_scene load_steps=10 format=2]
[ext_resource path="res://assets/robot_head/godot3_robot_head_collision.tres" type="Shape" id=1]
[ext_resource path="res://tests/functional/test_raycasting.gd" type="Script" id=2]
[ext_resource path="res://utils/exception_cylinder.gd" type="Script" id=3]
[ext_resource path="res://utils/camera_orbit.gd" type="Script" id=4]
[sub_resource type="BoxShape" id=1]
[sub_resource type="CapsuleShape" id=2]
[sub_resource type="CylinderShape" id=3]
[sub_resource type="ConvexPolygonShape" id=4]
points = PoolVector3Array( -0.7, 0, -0.7, -0.3, 0, 0.8, 0.8, 0, -0.3, 0, -1, 0 )
[sub_resource type="SphereShape" id=5]
[node name="Test" type="Spatial"]
script = ExtResource( 2 )
[node name="Shapes" type="Spatial" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 9.35591, 0 )
[node name="RigidBodyBox" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 0, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyBox"]
transform = Transform( 0.579556, 0.0885213, 0.145926, 0, 0.939693, -0.205212, -0.155291, 0.330366, 0.544604, 0, 0, 0 )
shape = SubResource( 1 )
[node name="RigidBodyCapsule" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyCapsule"]
transform = Transform( 0.8, 0, 0, 0, -1.30337e-07, -0.8, 0, 0.8, -1.30337e-07, 0, 0, 0 )
shape = SubResource( 2 )
[node name="RigidBodyCylinder" type="RigidBody" parent="Shapes"]
mode = 3
script = ExtResource( 3 )
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyCylinder"]
transform = Transform( 0.772741, -0.258819, 2.59821e-08, 0.2, 0.933013, -0.207055, 0.0535898, 0.25, 0.772741, 0, 0, 0 )
shape = SubResource( 3 )
[node name="RigidBodyConvex" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, -0.210678, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyConvex"]
transform = Transform( 2, 0, 0, 0, 2.89766, -0.517939, 0, 0.776908, 1.93177, 0, 0.3533, 0 )
shape = SubResource( 4 )
[node name="RigidBodySphere" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 0, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodySphere"]
transform = Transform( 1.2, 0, 0, 0, 1.2, 0, 0, 0, 1.2, 0, 0, 0 )
shape = SubResource( 5 )
[node name="StaticBodyHead" type="StaticBody" parent="Shapes"]
transform = Transform( 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, -6, 3.93357 )
[node name="CollisionShape" type="CollisionShape" parent="Shapes/StaticBodyHead"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 )
shape = ExtResource( 1 )
[node name="Camera" type="Camera" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 5.8667, 11.8164 )
script = ExtResource( 4 )

View File

@@ -0,0 +1,53 @@
extends Test
export(int, 1, 100) var height = 10
export(int, 1, 100) var width = 1
export(int, 1, 100) var depth = 1
export(Vector3) var box_size = Vector3(1.0, 1.0, 1.0)
export(Vector3) var box_spacing = Vector3(0.0, 0.0, 0.0)
func _ready():
_create_stack()
func _create_stack():
var root_node = $Stack
var template_shape = BoxShape.new()
template_shape.extents = 0.5 * box_size
var template_collision = CollisionShape.new()
template_collision.shape = template_shape
var template_body = RigidBody.new()
template_body.add_child(template_collision)
var pos_y = 0.5 * box_size.y + box_spacing.y
for level in height:
var row_node = Spatial.new()
row_node.transform.origin = Vector3(0.0, pos_y, 0.0)
row_node.name = "Row%02d" % (level + 1)
root_node.add_child(row_node)
var pos_x = -0.5 * (width - 1) * (box_size.x + box_spacing.x)
for box_index_x in width:
var pos_z = -0.5 * (depth - 1) * (box_size.z + box_spacing.z)
for box_index_z in depth:
var box_index = box_index_x * box_index_z
var box = template_body.duplicate()
box.transform.origin = Vector3(pos_x, 0.0, pos_z)
box.name = "Box%02d" % (box_index + 1)
row_node.add_child(box)
pos_z += box_size.z + box_spacing.z
pos_x += box_size.x + box_spacing.x
pos_y += box_size.y + box_spacing.y
template_body.queue_free()

View File

@@ -0,0 +1,16 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://tests/functional/test_stack.gd" type="Script" id=1]
[ext_resource path="res://tests/static_scene_plane.tscn" type="PackedScene" id=2]
[ext_resource path="res://utils/camera_orbit.gd" type="Script" id=4]
[node name="Test" type="Spatial"]
script = ExtResource( 1 )
[node name="Stack" type="Spatial" parent="."]
[node name="StaticBodyPlane" parent="." instance=ExtResource( 2 )]
[node name="Camera" type="Camera" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.53602, 12.2684 )
script = ExtResource( 4 )

View File

@@ -0,0 +1,155 @@
extends Test
const BOX_SIZE = Vector3(0.8, 0.8, 0.8)
const BOX_SPACE = Vector3(1.0, 1.0, 1.0)
export(int, 1, 1000) var row_size = 20
export(int, 1, 1000) var column_size = 20
export(int, 1, 1000) var depth_size = 20
var _objects = []
var _log_physics = false
var _log_physics_time = 0
var _log_physics_time_start = 0
func _ready():
_create_objects()
_log_physics_start()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_add_objects()
_log_physics_start()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_move_objects()
_log_physics_start()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_remove_objects()
_log_physics_start()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
Log.print_log("* Done.")
func _exit_tree():
for object in _objects:
object.free()
func _physics_process(_delta):
if _log_physics:
var time = OS.get_ticks_usec()
var time_delta = time - _log_physics_time
var time_total = time - _log_physics_time_start
_log_physics_time = time
Log.print_log(" Physics Tick: %.3f ms (total = %.3f ms)" % [0.001 * time_delta, 0.001 * time_total])
func _log_physics_start():
_log_physics = true
_log_physics_time_start = OS.get_ticks_usec()
_log_physics_time = _log_physics_time_start
func _log_physics_stop():
_log_physics = false
func _create_objects():
_objects.clear()
var template_body = create_rigidbody_box(BOX_SIZE)
template_body.gravity_scale = 0.0
Log.print_log("* Creating objects...")
var timer = OS.get_ticks_usec()
var pos_x = -0.5 * (row_size - 1) * BOX_SPACE.x
for row in row_size:
var pos_y = -0.5 * (column_size - 1) * BOX_SPACE.y
for column in column_size:
var pos_z = -0.5 * (depth_size - 1) * BOX_SPACE.z
for depth in depth_size:
var box = template_body.duplicate()
box.transform.origin = Vector3(pos_x, pos_y, pos_z)
box.name = "Box%03d" % (row * column + 1)
_objects.push_back(box)
pos_z += BOX_SPACE.z
pos_y += BOX_SPACE.y
pos_x += BOX_SPACE.x
timer = OS.get_ticks_usec() - timer
Log.print_log(" Create Time: %.3f ms" % (0.001 * timer))
template_body.queue_free()
func _add_objects():
var root_node = $Objects
Log.print_log("* Adding objects...")
var timer = OS.get_ticks_usec()
for object in _objects:
root_node.add_child(object)
timer = OS.get_ticks_usec() - timer
Log.print_log(" Add Time: %.3f ms" % (0.001 * timer))
func _move_objects():
Log.print_log("* Moving objects...")
var timer = OS.get_ticks_usec()
for object in _objects:
object.transform.origin += BOX_SPACE
timer = OS.get_ticks_usec() - timer
Log.print_log(" Move Time: %.3f ms" % (0.001 * timer))
func _remove_objects():
var root_node = $Objects
Log.print_log("* Removing objects...")
var timer = OS.get_ticks_usec()
for object in _objects:
root_node.remove_child(object)
timer = OS.get_ticks_usec() - timer
Log.print_log(" Remove Time: %.3f ms" % (0.001 * timer))

View File

@@ -0,0 +1,13 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://tests/performance/test_perf_broadphase.gd" type="Script" id=1]
[ext_resource path="res://utils/camera_orbit.gd" type="Script" id=5]
[node name="Test" type="Spatial"]
script = ExtResource( 1 )
[node name="Objects" type="Spatial" parent="."]
[node name="Camera" type="Camera" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 29.8407 )
script = ExtResource( 5 )

View File

@@ -10,7 +10,7 @@ const OPTION_TYPE_SPHERE = "Shape type/Sphere"
export(Array) var spawns = Array()
export(int) var spawn_count = 100
export(int, 1, 10) var spawn_multipiler = 5
export(int, 1, 10) var spawn_multiplier = 5
var _object_templates = []
@@ -36,6 +36,11 @@ func _ready():
_start_all_types()
func _exit_tree():
for object_template in _object_templates:
object_template.free()
func _on_option_selected(option):
cancel_timer()
@@ -123,9 +128,10 @@ func _spawn_objects(type_index):
Log.print_log("* Spawning: " + template_node.name)
for _index in range(spawn_multipiler):
for _node_index in spawn_count / spawn_multipiler:
for _index in range(spawn_multiplier):
for _node_index in spawn_count / spawn_multiplier:
var node = template_node.duplicate() as Spatial
node.transform.origin = Vector3.ZERO
spawn_parent.add_child(node)

View File

@@ -1,25 +1,12 @@
[gd_scene load_steps=5 format=2]
[gd_scene load_steps=4 format=2]
[ext_resource path="res://assets/robot_head/godot3_robot_head_collision.tres" type="Shape" id=1]
[ext_resource path="res://assets/robot_head/godot3_robot_head.mesh" type="ArrayMesh" id=2]
[sub_resource type="PlaneMesh" id=1]
[sub_resource type="ConcavePolygonShape" id=2]
data = PoolVector3Array( -1, 0, 1, 1, 0, -1, 1, 0, 1, -1, 0, 1, -1, 0, -1, 1, 0, -1 )
[ext_resource path="res://tests/static_scene_plane.tscn" type="PackedScene" id=3]
[node name="StaticScene" type="Spatial"]
[node name="StaticBodyPlane" type="StaticBody" parent="."]
[node name="MeshInstance" type="MeshInstance" parent="StaticBodyPlane"]
transform = Transform( 50, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0 )
mesh = SubResource( 1 )
material/0 = null
[node name="CollisionShape" type="CollisionShape" parent="StaticBodyPlane"]
transform = Transform( 50, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0 )
shape = SubResource( 2 )
[node name="StaticBodyPlane" parent="." instance=ExtResource( 3 )]
[node name="StaticBodyHead" type="StaticBody" parent="."]
transform = Transform( 10, 0, 0, 0, 8.66025, 5, 0, -5, 8.66025, 0, -11.1389, 2.29332 )

View File

@@ -0,0 +1,17 @@
[gd_scene load_steps=3 format=2]
[sub_resource type="PlaneMesh" id=1]
[sub_resource type="ConcavePolygonShape" id=2]
data = PoolVector3Array( -1, 0, 1, 1, 0, -1, 1, 0, 1, -1, 0, 1, -1, 0, -1, 1, 0, -1 )
[node name="StaticBodyPlane" type="StaticBody"]
[node name="MeshInstance" type="MeshInstance" parent="."]
transform = Transform( 50, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0 )
mesh = SubResource( 1 )
material/0 = null
[node name="CollisionShape" type="CollisionShape" parent="."]
transform = Transform( 50, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0 )
shape = SubResource( 2 )

View File

@@ -13,6 +13,10 @@ func _enter_tree():
remove_child(_entry_template)
func _exit_tree():
_entry_template.free()
func clear():
while get_child_count():
var entry = get_child(get_child_count() - 1)