I have a rigidbody that is instantiated at runtime based on user action. When at the initial location of the player spawn (0, 1.5, 0), aiming down, and placing a pot after jumping, once landing, the position of both the pot and player become NaN. I want to use a RigidBody player controller because the player should be able to interact with objects. I am using Jolt physics, in case that could be a problem.
I made a thing to add an object to the scene when clicked, but it causes an error when any of the coordinates are zero. I assume it’s some divide by zero error, but I checked everything that seemed obvious to be a problem, but could not find out a fix. I checked the positions of everything, but it all seems to be reasonable. I also logged the transform matrix, which also looks fine.
Edit: also, the world disappears, but only sometimes, despite the same actions.
When the world doesn’t disappear, the collision with the item doesn’t work. Anywhere else, the collision does work fine.
extends Node
func place_item(caster: RayCast3D, item: String):
for i in GlobalConstants.PARTS:
if i.part_id == item:
var rigid_parent: RigidBody3D
if caster.get_collider().get_collision_layer_value(2):
rigid_parent = RigidBody3D.new()
rigid_parent.collision_layer = 0b101
rigid_parent.can_sleep = false
rigid_parent.mass = i.part_mass
get_tree().get_first_node_in_group("scene root").add_child(rigid_parent)
elif caster.get_collider().get_collision_layer_value(3):
rigid_parent = caster.get_collider()
rigid_parent.mass = rigid_parent.mass + i.part_mass
var part = i.part_scene.instantiate()
var offset = part.position
rigid_parent.add_child(part)
var point = caster.get_collision_point()
var normal = caster.get_collision_normal().normalized()
var new_transform = Transform3D(Basis(), offset)
var normal_cross = Vector3.UP.cross(normal)
if not normal_cross.is_zero_approx():
new_transform = new_transform.rotated(normal_cross.normalized(), acos(Vector3.UP.dot(normal)))
new_transform.origin = new_transform.origin + point
part.global_transform = new_transform
The docs say get_collision_normal() returns a zero vector if the ray starts inside the thing it hits. You’re calling normalize() on it. Two things:
normalizing a normal is redundant
unless normalize() explicitly checks for zero vectors, it’s going to try to divide each component of the vector (all of which are 0) by the length, (which is 0), and hilarity will ensue
You still potentially need to deal with that zero vector; your normal var looks like it’s coming in zero sometimes, which means that (for example) Vector3.UP.cross(normal) is going to be trying to cross the up vector with a zero vec, which will make normal_cross be a zero vec.
Are you still seeing the is_finite error? If not, how is it not working?
The entire error I am getting is this E 0:00:01:798 instance_set_transform: Condition "!v.is_finite()" is true. <C++ Source> servers/rendering/renderer_scene_cull.cpp:957 @ instance_set_transform()
I can setup a repo with the full game so far, if you want more info.
Ok, well, at the least that tells you the problem is with a non-finite transform. That suggests a problem with new_transform. Are all of its components looking reasonable?
For that matter, how sure are you that the problem is in this code?
Well, I’m not sure, but the error only appears after the code is run. It might be some chain reaction. The transform looks fine: [X: (1.0, 0.0, 0.0), Y: (0.0, 1.0, 0.0), Z: (0.0, 0.0, 1.0), O: (-0.0, 0.929514, 0.0)]
One thing of note. You’re setting global_transform, which means that to generate the local transform for part it’s going to have to math its way through all the node transforms between path and the root. So the problem could potentially be on anything above it in the hierarchy.
After a lot of fiddling and rewriting, I’m no longer able to reproduce the bug. So, I guess it’s solved, but I’m not sure how. Maybe it is because two rigidbodies intersecting? That wouldn’t explain the fact that the position of all the rigidbodies are normal, so I’m not sure.
Alright, I’ve managed a janky solution, that works. Basically, giving a script to all of the rigid bodies I have, it doesn’t break, but it’s also very hacky and in an ideal world wouldn’t be needed.
extends RigidBody3D
func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
if is_zero_approx(state.transform.origin.x):
state.transform.origin.x = 0.000001
if is_zero_approx(state.transform.origin.y):
state.transform.origin.y = 0.000001
if is_zero_approx(state.transform.origin.z):
state.transform.origin.z = 0.000001
Basically, this just makes it so that the rigid bodies never have a coordinate that is zero so the bug can’t happen. I still don’t know why it happens in the first place. Gotta be something to do with that 0. I wanna say it’s a bug with Jolt, but I’m nearly certain it’s not.