Godot Version
4.2.1
Question
Hi hi!
I’m doing some tests with multi-threading. I’ve got a use case in which I want to deal with many thousands of batched raycasts, I’ve got a lot of leeway with how fast those should be executed so doing those on a separate thread makes a lot of sense to me.
I’ve made a quick prototype script in GDScript to sort things out since I’m new to multi-threading. My code seems to work fine, I’m able to execute many many thousands of raycasts on a single worker thread, maintaining 60 fps.
I verify my ray-cast results by drawing debug spheres on hit-positions, and lines on no hits, which works almost entirely as desired, very few raycasts give me this error:
MultithreadedRaycaster.gd:41 @ ray_cast(): Condition "space->locked" is true. Returning: false
According to the docs:
… Due to this, the only time accessing space is safe is during the Node._physics_process() callback. Accessing it from outside this function may result in an error due to space being locked.
Ray-casting — Godot Engine (stable) documentation in English
It is explained why this error happens, but not what locked exactly means or entails.
Does this mean it simply isn’t able to execute the raycast, or does it mean the space state information is outdated but is still able to execute the intersect_ray function (Which is what it looks like)?
Global Scope singletons are all thread-safe. Accessing servers from threads is supported (for RenderingServer and Physics servers, ensure threaded or thread-safe operation is enabled in the project settings!).
Thread-safe APIs — Godot Engine (stable) documentation in English
I cannot find any setting related to “threaded or thread-safe operation”. I don’t know if this is deprecated because this page has not been updated yet for 4.2, but it seems like this might alleviate the issue.
Here are my results with 15,000 raycasts, in a test scene with my node in a closed room. All hit results should return positive. If I get a negative hit result, I draw a red line showing to display that failed raycast.
extends Node3D
var worker_thread_1 : Thread
var directions : Array
func _ready():
directions = generate_directions(15000)
worker_thread_1 = Thread.new()
func _physics_process(delta):
global_position = global_position + Vector3(0,0.002,0)
DebugDraw3D.draw_sphere(global_position, 0.02, Color.PURPLE, delta)
# start thread when it's not doing anything
if worker_thread_1.is_started() == false:
# Grabbing space state on main thread, sending it into raycast function
var space_state = get_world_3d().direct_space_state
worker_thread_1.start(raycast_to_directions.bind(directions, global_position, space_state))
# stop thread when it's done
if worker_thread_1.is_alive() == false:
worker_thread_1.wait_to_finish()
Would love to hear if anyone has any ideas or could help me out here. Thanks!