Skip to content

Instantly share code, notes, and snippets.

@mrcdk
Last active December 19, 2025 09:21
Show Gist options
  • Select an option

  • Save mrcdk/9a74946966aed18ed2f7591b6a1f3534 to your computer and use it in GitHub Desktop.

Select an option

Save mrcdk/9a74946966aed18ed2f7591b6a1f3534 to your computer and use it in GitHub Desktop.
Godot physics and rendering server experiment

The settings I changed:

  • physics/3d/run_on_separate_thread: true
  • physics/3d/physics_engine: Jolt Physics
  • physics/common/physics_ticks_per_second: 30
  • physics/common/max_physics_steps_per_frame: 4
  • physics/jolt_physics_3d/simulation/penetration_slop: 0.04
  • physics/jolt_physics_3d/simulation/speculative_contact_distance: 0.04
  • physics/jolt_physics_3d/simulation/baumgarte_stabilization_factor: 0.4
  • physics/jolt_physics_3d/simulation/body_pair_contact_cache_distance_threshold: 0.005
  • physics/jolt_physics_3d/simulation/body_pair_contact_cache_angle_threshold: 15
  • physics/jolt_physics_3d/limits/temporary_memory_buffer_size: 128
  • physics/jolt_physics_3d/limits/max_bodies: 40960
  • physics/jolt_physics_3d/limits/max_body_pairs: 262144
  • physics/jolt_physics_3d/limits/max_contact_constraints: 81920

⚠️ARACHNOPHOBIA TRIGGER WARNING⚠️

Playlist: https://www.youtube.com/playlist?list=PLr4nY7RqmgrP3KawGx2D39sO2eXfj1KXH

⚠️ARACHNOPHOBIA TRIGGER WARNING⚠️

System info:

Godot v4.6.beta (40cf5a0f5) - Manjaro Linux #1 SMP PREEMPT_DYNAMIC Fri, 12 Dec 2025 19:42:49 +0000 on X11 - X11 display driver, Multi-window, 1 monitor - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 4080 SUPER (nvidia; 580.119.02) - AMD Ryzen 9 7950X3D 16-Core Processor (32 threads) - 61.90 GiB memory
extends Node3D
## The target Node3D each entity will follow
@export var target: Node3D
## The initial entities to spawn
@export_range(0, 8000, 1, "or_greater") var initial_entities: int = 1_000
## The amount of entities to spawn when pressing "spawn"
@export_range(0, 1000, 1, "or_greater") var entities_to_spawn: int = 1_00
@export_group("Mesh Settings")
## The entity mesh
@export var mesh: Mesh
## The mesh material
@export var material: Material
@export_group("Physics Settings")
## The shape. Must be a SphereShape3D as it's the most performant shape.
@export var shape: SphereShape3D
## The offset of the shape with respect of the mesh
@export var shape_offset: Vector3
## The jump force. Only works if max_contact_reported is > 0
@export_range(0, 10, 0.1, "or_greater") var jump_force: float = 1.0
## The body's mass
@export_range(0, 10, 0.1, "or_greater") var mass: float = 2
@export_flags_3d_physics var collision_layer: int
@export_flags_3d_physics var collision_mask: int
@export_group("Limits")
## How many updates to the direction will be with relation to the physics frames: physics_frame % update_direction_frames == 0
@export_range(1, 30, 1, "or_greater") var update_direction_frames: int = 8
## How many updates to the speed will be with relation to the physics frames: physics_frame % update_speed == 0
@export_range(1, 60, 1, "or_greater") var update_speed_frames: int = 30
## The amount of max contacts to report
@export_range(0, 32, 1, "prefer_slider") var max_contacts_reported: int = 2
## The angle to detect a wall.
@export_range(0, 360, 0.001, "radians_as_degrees") var floor_wall_angle = deg_to_rad(65)
## The angle to detect the direction of travel. This will limit when the entity will jump.
@export_range(0, 360, 0.001, "radians_as_degrees") var direction_angle = deg_to_rad(120)
var _body_rids: Array[RID]
var _instance_rids: Array[RID]
var _speeds: PackedFloat32Array
var _positions: PackedVector3Array
var _prev_positions: PackedVector3Array
var _prev_directions: PackedVector3Array
var _directions: PackedVector3Array
var _instances_visible := true
var PS = PhysicsServer3D
var RS = RenderingServer
@onready var entity_count_label: Label = $EntityCountLabel
func _ready() -> void:
RS.frame_pre_draw.connect(_interpolate_transforms)
spawn(initial_entities)
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE:
if RS.frame_pre_draw.is_connected(_interpolate_transforms):
RS.frame_pre_draw.disconnect(_interpolate_transforms)
for rid in _body_rids:
if rid.is_valid():
PS.free_rid(rid)
for rid in _instance_rids:
if rid.is_valid():
RS.free_rid(rid)
func _physics_process(_delta: float) -> void:
var target_position = target.global_position
var update_directions = Engine.get_physics_frames() % update_direction_frames == 0
var update_speed = Engine.get_physics_frames() % update_speed_frames == 0
for i in _body_rids.size():
var body_rid = _body_rids[i]
var speed = _speeds[i]
var current_position = _positions[i]
var direction = _directions[i]
if update_directions:
_prev_directions.set(i, direction)
direction = current_position.direction_to(target_position)
direction.y = 0.0
_directions.set(i, direction)
if update_speed:
speed = randf_range(3, 10)
_speeds.set(i, speed)
var instance_rid = _instance_rids[i]
if not RenderingServer.get_current_rendering_method() == "gl_compatibility":
RS.instance_geometry_set_shader_parameter(instance_rid, "speed", speed * 10.0)
var state = PS.body_get_direct_state(body_rid)
var motion = direction.normalized() * speed
motion.y = state.linear_velocity.y
state.linear_velocity = motion
var collisions = state.get_contact_count()
for collision_index in collisions:
var normal = state.get_contact_local_normal(collision_index)
var wall_dot = normal.dot(Vector3.UP)
if acos(wall_dot) >= floor_wall_angle:
var dir_dot = normal.dot(motion.normalized())
if acos(dir_dot) >= direction_angle:
state.apply_central_impulse(Vector3.UP * jump_force)
break
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed(&"spawn"):
spawn(entities_to_spawn)
if event.is_action_pressed(&"toggle_visible"):
_instances_visible = not _instances_visible
for rid in _instance_rids:
RS.instance_set_visible(rid, _instances_visible)
func spawn(amount: int) -> void:
for i in amount:
var min_offset = -50
var max_offset = 50
var initial_position = Vector3(randf_range(min_offset, max_offset), 3.0, randf_range(min_offset, max_offset))
_create_entity(initial_position)
entity_count_label.text = "E: %s" % _body_rids.size()
func _create_entity(initial_position: Vector3) -> void:
var world = get_world_3d()
var speed = randf_range(3, 10)
var temp_transform = Transform3D()
var body_rid = PS.body_create()
PS.body_set_space(body_rid, world.space)
PS.body_set_mode(body_rid, PhysicsServer3D.BODY_MODE_RIGID_LINEAR)
PS.body_set_state(body_rid, PhysicsServer3D.BODY_STATE_CAN_SLEEP, false)
PS.body_set_max_contacts_reported(body_rid, max_contacts_reported)
PS.body_set_collision_layer(body_rid, collision_layer)
PS.body_set_collision_mask(body_rid, collision_mask)
PS.body_add_shape(body_rid, shape.get_rid())
temp_transform.origin = shape_offset
PS.body_set_shape_transform(body_rid, 0, temp_transform)
PS.body_reset_mass_properties(body_rid)
PS.body_set_param(body_rid, PhysicsServer3D.BODY_PARAM_MASS, mass)
PS.body_set_param(body_rid, PhysicsServer3D.BODY_PARAM_FRICTION, 0.0)
PS.body_set_param(body_rid, PhysicsServer3D.BODY_PARAM_LINEAR_DAMP, 0.0)
PS.body_set_param(body_rid, PhysicsServer3D.BODY_PARAM_LINEAR_DAMP_MODE, PhysicsServer3D.BODY_DAMP_MODE_REPLACE)
_body_rids.append(body_rid)
var idx = _body_rids.size() - 1
PS.body_attach_object_instance_id(body_rid, idx)
PS.body_set_state_sync_callback(body_rid, _on_state_sync.bind(idx))
_positions.append(initial_position)
_prev_positions.append(initial_position)
temp_transform.origin = initial_position
PS.body_set_state(body_rid, PhysicsServer3D.BODY_STATE_TRANSFORM, temp_transform)
var instance_rid = RS.instance_create()
RS.instance_set_scenario(instance_rid, world.scenario)
RS.instance_set_base(instance_rid, mesh.get_rid())
if is_instance_valid(material):
RS.instance_set_surface_override_material(instance_rid, 0, material.get_rid())
RS.instance_set_visible(instance_rid, _instances_visible)
RS.instance_geometry_set_lod_bias(instance_rid, 1)
if not RenderingServer.get_current_rendering_method() == "gl_compatibility":
RS.instance_geometry_set_shader_parameter(instance_rid, "speed", speed * 10.0)
_instance_rids.append(instance_rid)
_speeds.append(speed)
_prev_directions.resize(_body_rids.size())
_directions.resize(_body_rids.size())
func _on_state_sync(state: PhysicsDirectBodyState3D, idx: int) -> void:
_prev_positions[idx] = _positions[idx]
_positions[idx] = state.transform.origin
func _interpolate_transforms() -> void:
var fraction = Engine.get_physics_interpolation_fraction()
var dir_delta = remap(Engine.get_physics_frames() % update_direction_frames, 0, update_direction_frames, 0, 1)
for i in _instance_rids.size():
var rid = _instance_rids[i]
var prev_position = _prev_positions[i]
var current_position = _positions[i]
var direction = _prev_directions[i].lerp(_directions[i], dir_delta)
var transform_interpolated = Transform3D()
if not direction.is_zero_approx():
transform_interpolated = transform_interpolated.looking_at(direction, Vector3.UP, true)
transform_interpolated.origin = prev_position.lerp(current_position, fraction)
RS.instance_set_transform(rid, transform_interpolated)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment