2
$\begingroup$

I have a free floating control bone which is meant to rotate the spine of my character on the global x axis so that my character can look up and down when performing certain actions via my game code editing the orientation of this bone. This works fine when the spine is already facing forward:

straight spine straight spine2

But when the spine is rotated (so that the arm points forward in a way that looks natural), the rotation of the bone constraints tied to the spine bones can only affect the local rotation of the spine:

enter image description here enter image description here

No longer pointing forward after looking up:

enter image description here enter image description here

The problem here is that the character and its arms are no longer facing straight forward when I rotate the control bone. The desired effect is that the rotation of the control bone rotates the bones of the spine in a way that ignores their existing orientation. Is there a way to achieve this effect?

ty.

$\endgroup$

1 Answer 1

4
$\begingroup$

How do I create a bone which controls the "global" rotation of another bone and not its local rotation

That's relatively easy-- you use a copy rotation bone constraint, set to default world->world space.

via my game code editing the orientation of this bone

That is not necessarily so easy, and it doesn't have anything to do with Blender, but with your game code. Constraints are specific to Blender, and if you want to use them with game-variables, you need to code them into your game engine. That is, you need to recreate those constraints. Maybe good news, Blender is all open source. Maybe bad news, Blender is all licensed as GPL, so if you copy code, you have to release your game under the GPL license as well.

The problem here is that the character and its arms are no longer facing straight forward when I rotate the control bone

The arms are inheriting the rotation of the spine, which is inheriting the rotation from the control. If you don't want the arms to inherit rotation from the spine, then you need constraints on the arm bones (or, just disabled "inherit rotation" in properties/bone/relations) to override that inherited rotation. Typically, you might use IK to control the rotation of the arms. But again, if that's something that you want to respond to game variables, then you need to be coding your constraints into your game. Setting them up in Blender won't do anything for you.

Edit, reading your comments: It works for you on "replace" or "before original", but not on "add". And looking at your pics, your spine is spinning about its Y axis when presumably it shouldn't (I can't make out your control's axes.)

So, why doesn't "add" work?

Because Eulers.

An add rotation constraint works pretty simply. It decomposes your bone's world (not local, since you said world) transformation matrix into Euler rotation triplets. It decomposes your target's (world) transformation into Euler triplets. It adds the two together. It recomposes the transformation matrix out of the new, summed Euler triplet.

But, there is more than one way to turn a given orientation into a set of Euler rotations. For instance, XYZ Euler 0,180,180 is the same as XYZ Euler 180,0,0. We say that these are "aliased": for any single given orientation, the Eulers go by multiple "names," like a criminal is the same person but provides different names depending on who's asking. There's not a one-to-one correspondence between orientations and Euler angles. Your one, true orientation tells one person, 180,0,0, but it tells another person, 0,180,180.

So when you add a bone at 180,0,0, what are you getting? Are you adding 180,0,0? Or are you adding 0,180,180? They're not the same thing, not once you add them to other values.

Any 3D program has to decide how to decode orientations into Eulers (if it decides that it needs to do that.) Blender decides to do that in a way that means that there's no aliasing, if no part of that triplet has a value greater than 90 degrees. There are other ways to decide. There's no right way to do it.

For local space, that's kind of reasonable. Riggers know that bones shouldn't rotate more than 90 degrees from the rest. If not because of theory, then because of experience. But because you're measuring in world space, that's 90 degrees relative to the world axes. Which you're almost certain to violate.

But that's not the only reason. The sum of 2 Eulers isn't sequential rotation anyways.

An Euler is a set of 3 sequential rotations, and the order of those rotations matter. That's why we have XYZ, XZY, etc Eulers: they're different orders.

Let [x] be a rotation about the x axis, and [x][z] be the sequential rotation about the x and z axes. The problem is that [x1+x2][y1+y2][z1+z2] does not equal [x1][y1][z1][x2][y2][z2]. The former is what we get with add. The latter is what we get with "after original." When we change our rotations of earlier rotations, we affect later rotations. So when we sum two rotations in the same axis, we get rotation that isn't necessarily in that same axis. (This is kind of what people mean by "gimbal lock", which is a term I'm not fond of because, in practice, it means, "anything unintuitive about Eulers.")

So the right answer here is, "add" is a dumb mode. Any rotation it gives you is largely an artifact of the math used to determine how Euler angles get measured. "Replace" is the best mode (and what you should be using: you have a control, you don't need two.) "After original" and "Before original" are also okay (they don't decompose matrices into arbitrary rotation triplets, they do matrix multiplication.)

Obviously, this is just a bunch of 3D math wankery that probably doesn't matter to anyone that isn't going to start coding constraints. Unfortunately, I think you happen to be somebody who needs to start coding constraints. Because of that, I'm going to recommend, well, learning the math, and where I learned most of my math is from Parbery and Dunn's "3D Math Primer", available at https://gamemath.com/ I bought it hardcover on Amazon, but they've been generous enough to share it for free, online, at the link provided.

$\endgroup$
7
  • $\begingroup$ I've already tried setting the bone constraint properties of Target and Owner to the "world space" but the issue prevails. I still haven't tested if the game engine I'm using even carries over bone constraints of imported armatures, that may become an issue later on and I'll just need to alter the spine bones programmatically somehow while preserving the spine keyframes of the animation. But it is unlikely that I will need to copy blender's code. Though I have found the solution though after tinkering with the constraint properties after setting it to use the "World Space"... $\endgroup$
    – DED
    Dec 28, 2023 at 3:03
  • $\begingroup$ You may've not accounted for the fact that I want to animate the spine independently from this control bone, so I was using "Add" in the Mix property of the control to add the rotation of the control bone onto the spine rather than replacing it entirely. If "Add" is used the issue persists for some reason even when using "world space". I needed to use "Before Original" for the Mix property and now it works perfectly (though I am not 100% sure of the reason). (using "Before Original" also does not fix my issue when the constraints are using Local Space, I tested it to make sure.) $\endgroup$
    – DED
    Dec 28, 2023 at 3:03
  • $\begingroup$ If you care to explain why it works and update your answer to include this information I'll accept it as the answer. $\endgroup$
    – DED
    Dec 28, 2023 at 3:03
  • 1
    $\begingroup$ @DED you might check the edit. I answered what "add" and "before/after original" do. Well, as best as I can. $\endgroup$
    – Nathan
    Dec 28, 2023 at 3:34
  • 1
    $\begingroup$ thanks m8, I sorta take back the need for explaining why it works. I don't really need to know that for a solution to be valid. $\endgroup$
    – DED
    Dec 28, 2023 at 3:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .