- Home /
Orienting bones to Y forward
So I have a simple mesh made in blender, with two bones. When I import this into unity, the rotations are corrected for the model, but the bones are another story.
Each bone always has its local forward direction set to X (for any model I import), while the rest of the model is correct. I need to be able to manipulate this bone in code (it will not be used for any sort of animation), and it is causing me grief.
My goal is to have an attached script reference the bone, and make it point in the direction of a normal from elsewhere in my game. The rotation is never correct though, and usually WILDLY incorrect.
I know that the most likely culprit is the X axis being forward for the bone. So what I am wondering is two things:
Is there a way to get this exported from blender such that the model, armature, and bones all have the same forward vector?
If not, what could I do in my script to transform the bone such that Y is the forward axis; without actually moving the bone (as this would move the mesh)
Here aer some code snippets I had tried:
GameObject go = GameObject.Instantiate(prefabSegment);
Transform start = go.transform.FindChild("Skeleton/Segment_Start").transform;
Transform end = go.transform.FindChild("Skeleton/Segment_Start/Segment_End").transform;
start.position = splineSeg.Value.position;
start.rotation = Quaternion.FromToRotation(start.forward, splineSeg.Value.direction);
And
Quaternion.LookRotation(splineSeg.Value.direction)
btw, splineSeg is a LinkedListNode containing some information from a portion of a bezier curve; so ".direction" is the normal I want to use as the direction to face the bone in. prefabSegment is the imported mesh
It is also worth noting that the setting of position is absolutely correct; the issue lays with rotation (be it code bugs, export issues, or both).
I am at a loss here.
Hi, is it a space problem ? The bone rotation is always expressed in the space of it's parent transform. You would then have to orient the bone using the normal in its parent transform's space, using transform.parent.InverseTransformDirection( normal-in-world-space ) and using the result to create a rotation using Quaternion.LookRotation. There is usually some trial & error with this kind of code, using Debug.DrawLine helps ;-)
@dns: The bones in blender are weird in that they always have a local Y axis that points along the length of the bone, and is unchangeable. On import, unity DOES do some kind of conversion, but it chooses X as the forward vector which is even more bizarre. Your solution confused me a bit though. :P
Great that the solution Cherno provided did the job! Sorry for the confusion :)
@Cherno: That was an excellent idea. I tried the empty gameobject approach, and it worked beautifully. It is even more concise in my code than a bunch of math would have been. Only took 5 $$anonymous$$utes to implement that. Thank you so much! I still wish I understood rotations better in general to understand your second suggestion, but the first idea does the job quick and dirty.
The parent rotation method is ok if it's not done every frame. The second method I described goes like this:
//make the bone look at a position (such as the head bone)
bone.LookAt(targetPos);
//the same bone is then rotated certain amounts of degrees around the x,y and z axes; this is done with a rotation offset vector which holds the required degree values for the xyz axes.
Vector3 offsetRot = new Vector3(0,-90,270);
bone.Rotate(offsetRot );
This can easily be done every frame to make the head look at a position with the right axies orientation.
Oooohhhhh I get it now. So basically I use LookAt as normal, and then apply a rotation using the rotation unity gave it upon import to offset it. $$anonymous$$ake sense. It would be a bit more difficult as the bones' import rotation changes based on it's parent (and they are linked). but at least knowing what you meant helps to get around that.
Fortunately, this is not done every frame (or most frames). The player would be manipulating an object, and once done this code would no longer be called.
Anyways, thank you for the explanation.
Answer by Cherno · Sep 23, 2015 at 09:30 AM
It's a common problem and one that doesn't have a neat solution. What you can do is:
Temporarily create an empty gameobject at the bone's position with the desired rotation, make it a parent of the bone, and rotate it, then unparent it and destroy it.
Apply the rotation to the bone (in LateUpdate()), and also apply a rotation offset vector to it's rotation. For example, you apply Transform.LookAt first, and then use Transform.Rotate.