Add Physics 3D benchmarks (#76)

* Add Area3D benchmark
* Add CharacterBody3D benchmark
* Add Raycast3D benchmark
* Add SoftBody3D benchmark
* Add TriangleMesh benchmark
* Set physics 3D benchmarks to run for 10 seconds
This commit is contained in:
Emmanouil Papadeas
2024-06-20 01:43:17 +03:00
committed by GitHub
parent 5becabc28a
commit f1ee9ebccb
9 changed files with 440 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
extends Benchmark
const SPREAD_H := 20.0
const SPREAD_V := 10.0
class TestScene:
extends Node3D
var num_character_bodies: int
var num_area_3d: int
var visualize := true
var area_3d_nodes: Array[Area3D]
var time_accum := 0.0
var shapes: Array[Shape3D] = [
BoxShape3D.new(),
CapsuleShape3D.new(),
SphereShape3D.new(),
]
var meshes: Array[Mesh] = [
BoxMesh.new(),
CapsuleMesh.new(),
SphereMesh.new(),
]
func _init(_num_character_bodies: int, _num_area_3d: int, _visualize: bool) -> void:
num_character_bodies = _num_character_bodies
num_area_3d = _num_area_3d
visualize = _visualize
func _ready() -> void:
if visualize:
var camera := Camera3D.new()
camera.position = Vector3(0.0, 20.0, 20.0)
camera.rotate_x(-0.8)
add_child(camera)
for i in num_character_bodies:
var character_body := CharacterBody3D.new()
character_body.position = Vector3(
randf_range(-SPREAD_H, SPREAD_H),
randf_range(0.0, SPREAD_V),
randf_range(-SPREAD_H, SPREAD_H)
)
add_random_shape(character_body)
add_child(character_body)
for i in num_area_3d:
var area_2d := Area3D.new()
area_2d.position = Vector3(
randf_range(-SPREAD_H, SPREAD_H),
randf_range(0.0, SPREAD_V),
randf_range(-SPREAD_H, SPREAD_H)
)
add_random_shape(area_2d)
add_child(area_2d)
area_3d_nodes.append(area_2d)
func _physics_process(delta: float) -> void:
for i in area_3d_nodes.size():
time_accum += delta
area_3d_nodes[i].position += Vector3(sin(time_accum), 0.0, cos(time_accum)) * 4.0
func add_random_shape(parent: CollisionObject3D) -> void:
var r := randi() % shapes.size()
var collision_shape := CollisionShape3D.new()
collision_shape.shape = shapes[r]
if visualize:
var mesh_instance := MeshInstance3D.new()
mesh_instance.mesh = meshes[r]
parent.add_child(mesh_instance)
parent.add_child(collision_shape)
func _init() -> void:
benchmark_time = 10e6
test_physics = true
test_idle = true
func benchmark_1000_area_3d() -> TestScene:
return TestScene.new(2000, 1000, true)

View File

@@ -0,0 +1,66 @@
extends Benchmark
const SPEED := 30.0
const JUMP_VELOCITY := -40.0
const SPREAD_H := 32.0
const SPREAD_V := 20.0
class TestScene:
extends Node3D
var grid_map_scene := preload("res://supplemental/gridmap_scene.tscn")
var grid_map_node: Node3D
var n_of_character_bodies: int
var visualize := true
var character_bodies: Array[CharacterBody3D] = []
var capsule_mesh := CapsuleMesh.new()
func _init(_n_of_character_bodies: int, _visualize: bool) -> void:
n_of_character_bodies = _n_of_character_bodies
visualize = _visualize
func _ready() -> void:
grid_map_node = grid_map_scene.instantiate()
add_child(grid_map_node)
for i in n_of_character_bodies:
var body := CharacterBody3D.new()
body.position = Vector3(
randf_range(-SPREAD_H, SPREAD_H), randf_range(-SPREAD_V, SPREAD_V), 0.0
)
body.axis_lock_linear_z = true
var collision_shape := CollisionShape3D.new()
collision_shape.shape = CapsuleShape3D.new()
body.add_child(collision_shape)
if visualize:
var mesh_instance := MeshInstance3D.new()
mesh_instance.mesh = capsule_mesh
body.add_child(mesh_instance)
grid_map_node.add_child(body)
character_bodies.append(body)
func _physics_process(delta: float) -> void:
for body in character_bodies:
if not body.is_on_floor():
body.velocity += body.get_gravity() * delta
if body.is_on_floor():
body.velocity.y = JUMP_VELOCITY
var direction := randf_range(-1.0, 1.0)
if direction:
body.velocity.x = direction * SPEED
else:
body.velocity.x = move_toward(body.velocity.x, 0, SPEED)
body.move_and_slide()
func _init() -> void:
benchmark_time = 10e6
test_physics = true
test_idle = true
func benchmark_1000_character_bodies_3d() -> TestScene:
return TestScene.new(1000, true)

View File

@@ -0,0 +1,56 @@
extends Benchmark
const N_OF_RAYCASTS := 10_000
const N_OF_SHAPES := 2000
const SPREAD_H := 20.0
var space: RID
var bodies: Array[RID]
var shapes: Array[RID]
func _setup_scene() -> void:
space = PhysicsServer3D.space_create()
PhysicsServer3D.space_set_active(space, true)
for i in N_OF_SHAPES:
var body := PhysicsServer3D.body_create()
var shape: RID
var r := randi() % 3
match r:
0:
shape = PhysicsServer3D.box_shape_create()
1:
shape = PhysicsServer3D.capsule_shape_create()
2:
shape = PhysicsServer3D.sphere_shape_create()
PhysicsServer3D.body_add_shape(body, shape)
shapes.append(shape)
PhysicsServer3D.body_set_space(body, space)
bodies.append(body)
var transform := Transform3D()
transform.origin = _rand_pos()
PhysicsServer3D.body_set_state(body, PhysicsServer3D.BODY_STATE_TRANSFORM, transform)
func _cast_raycasts() -> void:
var space_state := PhysicsServer3D.space_get_direct_state(space)
for i in N_OF_RAYCASTS:
var query := PhysicsRayQueryParameters3D.create(_rand_pos(), _rand_pos())
space_state.intersect_ray(query)
func _clear_scene() -> void:
for i in shapes.size(): # shapes and bodies should have the same size
PhysicsServer3D.free_rid(shapes[i])
PhysicsServer3D.free_rid(bodies[i])
PhysicsServer3D.free_rid(space)
func _rand_pos() -> Vector3:
return Vector3(randf_range(-SPREAD_H, SPREAD_H), 0.0, 0.0)
func benchmark_10_000_raycast_3d() -> void:
_setup_scene()
_cast_raycasts()
_clear_scene()

View File

@@ -0,0 +1,73 @@
extends Benchmark
const SPREAD_H := 20.0
const SPREAD_V := 80.0
class TestScene:
extends Node3D
var n_of_rigidbodies: int
var visualize := true
var shapes: Array[Shape3D] = [
BoxShape3D.new(),
CapsuleShape3D.new(),
SphereShape3D.new(),
]
var meshes: Array[Mesh] = [
BoxMesh.new(),
CapsuleMesh.new(),
SphereMesh.new(),
]
func _init(_n_of_rigidbodies: int, _visualize: bool) -> void:
n_of_rigidbodies = _n_of_rigidbodies
visualize = _visualize
func _ready() -> void:
var softbody := SoftBody3D.new()
var plane_mesh := PlaneMesh.new()
plane_mesh.size = Vector2(60, 60)
plane_mesh.subdivide_depth = 21
plane_mesh.subdivide_width = 21
softbody.mesh = plane_mesh
softbody.set_point_pinned(11, true)
softbody.set_point_pinned(253, true)
softbody.set_point_pinned(275, true)
softbody.set_point_pinned(517, true)
add_child(softbody)
if visualize:
var camera := Camera3D.new()
camera.position = Vector3(0.0, 20.0, 20.0)
camera.rotate_x(-0.8)
add_child(camera)
for i in n_of_rigidbodies:
var rigid := RigidBody3D.new()
rigid.position = Vector3(
randf_range(-SPREAD_H, SPREAD_H),
randf_range(0.0, SPREAD_V),
randf_range(-SPREAD_H, SPREAD_H)
)
add_random_shape(rigid)
add_child(rigid)
func add_random_shape(parent: CollisionObject3D) -> void:
var r := randi() % shapes.size()
var collision_shape := CollisionShape3D.new()
collision_shape.shape = shapes[r]
if visualize:
var mesh_instance := MeshInstance3D.new()
mesh_instance.mesh = meshes[r]
parent.add_child(mesh_instance)
parent.add_child(collision_shape)
func _init() -> void:
benchmark_time = 10e6
test_physics = true
test_idle = true
func benchmark_softbody_3d_500_rigidbodies() -> TestScene:
return TestScene.new(500, true)

View File

@@ -0,0 +1,66 @@
extends Benchmark
const SPREAD_H := 25.0
const SPREAD_V := 10.0
class TestScene:
extends Node3D
var collision_scene := preload("res://supplemental/8ball.glb")
var n_of_rigidbodies: int
var visualize := true
var shapes: Array[Shape3D] = [
BoxShape3D.new(),
CapsuleShape3D.new(),
SphereShape3D.new(),
]
var meshes: Array[Mesh] = [
BoxMesh.new(),
CapsuleMesh.new(),
SphereMesh.new(),
]
func _init(_n_of_rigidbodies: int, _visualize: bool) -> void:
n_of_rigidbodies = _n_of_rigidbodies
visualize = _visualize
func _ready() -> void:
var collision_node := collision_scene.instantiate() as Node3D
collision_node.rotate_y(PI / 2.0)
collision_node.scale = Vector3(7, 7, 7)
add_child(collision_node)
if visualize:
var camera := Camera3D.new()
camera.position = Vector3(0.0, 20.0, 20.0)
camera.rotate_x(-0.8)
add_child(camera)
for i in n_of_rigidbodies:
var rigid := RigidBody3D.new()
rigid.position = Vector3(
randf_range(-SPREAD_H, SPREAD_H),
randf_range(0.0, SPREAD_V),
randf_range(-SPREAD_H, SPREAD_H)
)
add_random_shape(rigid)
add_child(rigid)
func add_random_shape(parent: CollisionObject3D) -> void:
var r := randi() % shapes.size()
var collision_shape := CollisionShape3D.new()
collision_shape.shape = shapes[r]
if visualize:
var mesh_instance := MeshInstance3D.new()
mesh_instance.mesh = meshes[r]
parent.add_child(mesh_instance)
parent.add_child(collision_shape)
func _init() -> void:
benchmark_time = 10e6
test_physics = true
test_idle = true
func benchmark_triangle_mesh_3d_1000_rigidbodies() -> TestScene:
return TestScene.new(1000, true)

BIN
supplemental/8ball.glb Normal file

Binary file not shown.

View File

@@ -0,0 +1,39 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://6i35ubecst4p"
path="res://.godot/imported/8ball.glb-f349e8267bede1518210679565847aa4.scn"
[deps]
source_file="res://supplemental/8ball.glb"
dest_files=["res://.godot/imported/8ball.glb-f349e8267bede1518210679565847aa4.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={}
fbx/importer=0
fbx/allow_geometry_helper_nodes=false
fbx/embedded_image_handling=1
gltf/naming_version=1
gltf/embedded_image_handling=1

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,43 @@
[gd_resource type="MeshLibrary" load_steps=9 format=3 uid="uid://x303bfmllwmk"]
[sub_resource type="BoxMesh" id="BoxMesh_mqd7q"]
[sub_resource type="BoxShape3D" id="BoxShape3D_0i8f0"]
[sub_resource type="SphereMesh" id="SphereMesh_1yxu2"]
[sub_resource type="SphereShape3D" id="SphereShape3D_atl5i"]
[sub_resource type="CylinderMesh" id="CylinderMesh_ox1xu"]
[sub_resource type="CylinderShape3D" id="CylinderShape3D_v4aqj"]
[sub_resource type="CapsuleMesh" id="CapsuleMesh_4mk8y"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_s7i7c"]
[resource]
item/0/name = "Box"
item/0/mesh = SubResource("BoxMesh_mqd7q")
item/0/mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
item/0/shapes = [SubResource("BoxShape3D_0i8f0"), Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)]
item/0/navigation_mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
item/0/navigation_layers = 1
item/1/name = "Sphere"
item/1/mesh = SubResource("SphereMesh_1yxu2")
item/1/mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
item/1/shapes = [SubResource("SphereShape3D_atl5i"), Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)]
item/1/navigation_mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
item/1/navigation_layers = 1
item/2/name = "Cylinder"
item/2/mesh = SubResource("CylinderMesh_ox1xu")
item/2/mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
item/2/shapes = [SubResource("CylinderShape3D_v4aqj"), Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)]
item/2/navigation_mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
item/2/navigation_layers = 1
item/3/name = "Capsule"
item/3/mesh = SubResource("CapsuleMesh_4mk8y")
item/3/mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
item/3/shapes = [SubResource("CapsuleShape3D_s7i7c"), Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)]
item/3/navigation_mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
item/3/navigation_layers = 1