Please find below a Playground link: https://playground.babylonjs.com/#N3RH3R#19
Note that the player is intentionally spawned below the camera (since this bug deals with the vertical offset of meshes relative to ArcRotateCamera’s radius), so please click inside the Playground and either:
Hold down the Up arrow key
Click and drag the left mouse button from up to down
Please refer to the lines:
// BUG: If radius <= 3, gun points one way. If radius >= 4, gun points other way.
const radius = 3;
Note that when radius = 3, the gun points outwards.
Some may suggest to remove the first forced render after initializing the player model and setting its parent to the green rectangular prism:
scene.render(); // Force updates by rendering
However, this won’t solve the issue I’m facing in development, since there will be situations where a new gun mesh is attached to a player model after the first scene.render() call with the player model in the scene (for example: a player picking up a new gun).
This first forced scene.render() is an attempt to make a gun’s rotation consistent regardless of whether the gun was attached to a player model during initialization or several minutes into a game.
The player model is composed of 2 meshes (cyan parts and black ball joints). If I only parent the cyan part to the green rectangular prism, the gun has a consistent rotation regardless of the ArcRotateCamera's viewing angle and radius. This is good news!
This means a possible workaround is to make sure my imported meshes only has a single mesh. Regardless, this still seems like a bug, since parenting multiple meshes causes unexpected rotation behavior.
Edit: Nevermind, this possible workaround did not work Intuition is telling me that as long as the ArcRotateCamera can see one of the multiple player model meshes, scene.render() will properly update all gun meshes.
If you wait for 2 seconds, and then look at the player (using mouse drag or arrow keys), the gun will point outwards.
If you look at the player before 2 seconds have elapsed, the gun will point inwards.
Video of Bug:
Edit: An extremely hacky way to work around this is to use Multi Views (2 cameras with one always looking directly at the player), as shown in this Playground.
If I comment out the this.scalingDeterminant *= -1; it does make work your use case.
Indeed, if calling this.skeleton.bones[boneIndex].getWorldMatrix().determinant() in your PG attachToBone method, we can see it returns a negative value when the mesh is visible when you attach the AK47 to the bone. When the mesh is not visible yet, the bone matrices are all 0 so the determinant is 0 and thus scalingDeterminant is not multiplied by -1.
As scalingDeterminant is a public property, you can reset it to 1 and make the PG work:
Hum, I thought the right orientation of the riffle was “outward”, but now I don’t think so, and then the right fix is to call skeleton.prepare() before attaching to the bone:
Indeed, when the mesh is out of view when you attach to the bone, the skeleton has not been prepared yet and all the bone matrices are empty. Calling prepare will initialize the bone matrices with the right values.
[…] I wonder if the TransformNode.attachToBone should call prepare itself to make sure everything is in order before getting the bone world matrix:
@Evgeni_Popov, I’m really thankful for all the time you spent debugging and deep diving into the source code. Could I ask about your workflow with the Playground code and the Babylon.js source code? Have you cloned the full Babylon.js source code and linked it as a source for the Playground code?