0
\$\begingroup\$

I'm sorry if the title is bad, but i'll try my best to explain my problem.

Consider a simple hierarchy of objects (Object1 -> Object2 -> Object3)

If i now were to rotate Object1 by 45 degrees in the x axis, i believe Object2 and Object3 should also be rotated by 45 degrees in the x axis but the rotation origin changes and is inherited from the parent

I do understand that when working with matrices i just multiply the parent and child transforms together(afaik) but in my case i am not using matrices(For a solid reason)

Instead i just have 3 rotation functions(1 for each axis) and before each rotation i set the pivot point/origin like this:

for each vertex in object:
vertex.translate(-origin)
vertex.rotate(.....)
vertex.translate(+origin)

I am trying to figure out how to compute the origin for each object in a way where it inherits the rotation(?) from the parent.

What i thought i had to do is simply 'accumulate' origins, for example: If i use the same example as above where i rotate Object1 then i computed the origins the following way:

Object1.origin = Object1.origin
Object2.origin = Object1.origin + Object2.origin
Object3.origin = Object1.origin + Object2.origin + Object3.origin

But that doesn't seem to work, example of 4 objects in blender(i'll call them Object1, Object2, Object3, Object4, so Object1 has a child Object2 which has a child Object3 which has a child Object4) where i rotate Object1 in the x axis: https://i.imgur.com/PI9Jsm8.gif

Example of the same object being rotated in the x axis(by roughly the same amount) in my program where i set the origin for each rotation the way i explained above: https://i.imgur.com/geGqGP2.gif

This looks wrong, and im not sure what the right way to do it is, heres the pseudocode(as it's simpler to understand) that computes the origin for each object and rotates it:

// getAllChildren returns the object itself, it's children(including indirect children)
// so if use the above example and Object1 was the input, then it'd return Object1, Object2, Object3, Object4.
// if the input was Object2 it'd return Object2, Object3, Object4
// getUntilRootReverseOrder() returns all the parents of that object(including indirect ones)
// so if the input was Object4 then it would return Object3, Object2, Object1
// if the input was Object2 it would return Object1

for each object in object.getAllChildren() {
List parents = object.getUntilRootReverseOrder()
origin = object.origin
for each parent in parents {
    origin.add(parent.origin)
    object.setRotationOrigin(origin)
    object.rotate(...)
  }
}

My goal is to have the objects rotate the same exact was as in blender, any help & advice is much appreciated.

The reason why i am not using either matrices or quaternions is because i am working on a tool for a fairly old engine which just uses euler angles for rotations(it does not use matrices at all anywhere in the engine) however i am perfectly fine with using either matrices or quaternions as long as the end result can be encoded as euler angles (and of course i need the origin for each rotation) To be more specific, it is not a tool for just me(i am planning to make it open source) if i were to edit the engine itself and made it use matrices or quaternions, everyone who would use the tool would also have to do the same which isn't ideal.

Actual code of how i apply rotations if helpful at all:

    private void applyRotation(int[] labels, int dx, int dy, int dz) {
        for (int label : labels) {
            if (skeleton.getVertexGroup(label) == null) {
                continue;
            }
            for (int vertex : skeleton.getVertexGroup(label)) {
                skeleton.translate(vertex, -originX, -originY, -originZ);
                if (dz != 0) skeleton.rotateRoll(vertex, SINE[dz], COSINE[dz]); // roll
                if (dx != 0) skeleton.rotatePitch(vertex, SINE[dx], COSINE[dx]); // pitch
                if (dy != 0) skeleton.rotateYaw(vertex, SINE[dy], COSINE[dy]); // yaw
                skeleton.translate(vertex, +originX, +originY, +originZ);
            }
        }
    }

Example input & desired output:

Input: a rotation(eg 45 degrees in the x axis) for Object1 (I also have information about all the children of Object1 and their pivot points)

Desired output: The rotations for Object2, Object3, Object4 in euler angles(im assuming they're all 45 degrees in the x axis tho) and their pivot points(and of course also the pivot point of Object1)

The rotation is represented as a quaternion initially but can easily be converted to either a rotation matrix or even euler angles(afaik most math libraries have those functions built in)

Using matrices this is what i thought could potentially work, but im not 100% sure: if i were to rotate Bone1 which has 3 children(including indirect) (Bone 2-4)

float rotation = PI / 4; // 45 degrees

Matrix bone1Matrix = Matrix.identity().translate(Bone1.localPosition).rotateX(rotation)

Matrix bone2Matrix = bone1Matrix.multiply(Matrix.identity().translate(Bone2.localPosition).rotateX(rotation)

Matrix bone3Matrix = bone2Matrix.multiply(Matrix.identity().translate(Bone3.localPosition).rotateX(rotation)

Matrix bone4Matrix = bone3Matrix.multiply(Matrix.identity().translate(Bone4.localPosition).rotateX(rotation) 

And the origin of each bone would just be the translation part of their matrix(just a guess)

the rotation of each bone would either be the accumulated rotation or the initial rotation(i'd assume it's the latter)

\$\endgroup\$
3
  • \$\begingroup\$ This isn't too bad, if you're able to represent your rotations as quaternions and rotate a point by a quaternion. If you need to represent rotations as angle triplets and execute them by three separate function calls, one for each angle, then you are headed for a world of painful trigonometry. Any possibility of using a quaternion-based method here? (Also, it may help to explain what the "solid reason" to not use matrix multiplication is in this case. That's a somewhat unusual constraint, and whatever reason that is might have wider-reaching implications on what solutions are best here) \$\endgroup\$
    – DMGregory
    Dec 3 '21 at 22:32
  • \$\begingroup\$ Was just about to include that. (anyway i edited my question now) \$\endgroup\$
    – Suic
    Dec 3 '21 at 22:35
  • \$\begingroup\$ Also included the method for applying rotations just in case \$\endgroup\$
    – Suic
    Dec 3 '21 at 22:40
0
\$\begingroup\$

I figured it out, since my 3 other bones(bone 2-4) had no transformation applied to them, they all simply inherited the legs global transform(so in my case bone 2-4 matrices were just identity matrices)e

\$\endgroup\$

You must log in to answer this question.

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