5 minutes of hesitation

Well, I implemented general movement according to what you described above, so now I’m trying to convert all the different kind of movements I had to suit this new system (not modifying loc/facing directly, but passing velocities (let them be constant for now, no accelerations). Conceptually I wanted just spinning around local Y (initial facing is arbitrary) at some constant rpm. So for every new facing I calculate next desired direction (tdir) which is advanced by HALF_PI in rotation direction.

…it’s advanced by half-pi in the local rotational space… ie: it’s exactly the same as UNIT_X in local space.

If you just wanted to see it spinning around y then set the angular velocity to new Vec3d(0, someValue, 0).

As it stands, this line:
Vec3d newRotVel = new Vec3d(tdir.dot(Vec3d.UNIT_X), tdir.dot(Vec3d.UNIT_Y), tdir.dot(Vec3d.UNIT_Z)).mult(12);
Is the equivalent of:
Vec3d newRotVel = new Vec3d(tdir.x, tdir.y, tdir.z).mult(12);

…and it doesn’t really make sense to set the axes rotations to a direction vector. They are generally not directly related.

It doesn’t work for me, since it is world space where everything is happening in the end. I mean I need angles components to compensate initial facing, which is not UNIT_Z…

or, do you mean I could do it once for all in integration system, and pass local velocities everywhere else?

Edit: I’ll better make a picture, I guess, gimme some time
Edit2:

So I wanted it to spin around facing.mult(unitY) vector. Location and facing in this case are both equal to world translation and rotation (there’s no hierarchy). Integration system is as follows:

Pose pose = ed.getComponent(eId, Pose.class);
Linear linear = ed.getComponent(eId, Linear.class);
            
Vec3d vel = linear.getVelocity();
vel.addScaledVectorLocal(linear.getAcceleration(), tpf);
            
Vec3d loc = pose.getLocation();
loc.addScaledVectorLocal(vel, tpf);

Angular angular = ed.getComponent(eId, Angular.class);
            
Vec3d rotVel = angular.getVelocity();
rotVel.addScaledVectorLocal(angular.getAcceleration(), tpf);
            
Quatd facing = pose.getFacing();
facing.addScaledVectorLocal(rotVel, tpf);
                       
Pose newPose = pose.changeFacing(facing);
newPose = newPose.changeLocation(loc);
ed.setComponent(eId, newPose);

Well, I’m not sure about ambiguity of ‘world’ here, they set as local in modelstate, but I mean there’s single translation and single rotation for these, no multiplications.

Vec3d rotVel = new Vec3d(0, someValue, 0);
Vec3d localRotVel = orientation.mult(rotVel);
orientation.addScaledVector(localRotVel, tpf);

That same feeling, when you tried everything but something that straightforward… :pensive:

p.s. about the order… it seems that for Y works (someValue, 0, 0) and (0, someValue, 0) works for X.

Let’s be sure what we’re talking about. When you say “for Y works”… what rotation are you seeing. Describe as in head movement… like “nodding yes”, “shaking head no”, “touching ear to shoulder.”

Edit: and by the way, I listed them in x, y, z order.

“For Y” I see rotation around facing.mult(unitY) as on my picture. In terms of Eulers I’m not sure what it would be, since it looks like yaw but typically yaw is shown on pictures around Z axis, which is going up (in case of JME this is Y going up). So when I pass (something, 0, 0) I see rotation around local Y, which is local (to object) up axis. Unless something is completely screwed with my coordinate system, of course.

It’s not what I’d expect but usually my rotational velocity like this is set from torques supplied by the collision system. And all of that math came from the same place.

So while it isn’t what I’d expect, it is theoretically possible that the order is strange.

Something tickles my brain that the collision system treats “x” as the ‘axis of penetration’… which is generally ‘y’ in local space. Maybe there was some strange math built in.

To be honest, I’d have to put together a simple test case to check it and I do not have time at the moment.

It’s also possible that my fly-by help has steered you (pun intended) wrong on the local rotation thing.

I assumed that addScaledVector() was in world space relative to the quatd but I could just as easily see it accumulating on top of the quatd (relative to local space).

…again, I’d have to make some test code to try it. It’s weird because in debugging this stuff, I’ve never had any confusion about which axis was which.

I didn’t even mind to ask for that, you were of a tremendous help here already, this is just for those who may read later: just do a simple test to ensure you got the right axis, cause when there is something arbitrary it is easy to overlook. And as always there’s a possibility of something being wrong with axes on my side (though I’m pretty sure I didn’t do anything specific to swap them or something). Anyway, thanks, Paul, looks like now I have a lot of stuff to rework and so won’t interfere and bother you here for some time :slight_smile:

I’ve confirmed that the math works like I expected so there may be something wrong with your coordinate system.

Here is some sample code that proves that the axes are x=“nodding yes”, y=“saying no”, z=“touching ear to shoulder”… in as much as I tested the “saying no” bit.

        Quatd quat = new Quatd();
        Vec3d look = quat.mult(new Vec3d(0, 0, 1)); 
        Vec3d up = quat.mult(new Vec3d(0, 1, 0)); 
        Vec3d left = quat.mult(new Vec3d(1, 0, 0));
        System.out.println("look:" + look + "  up:" + up + "  left:" + left);
        
        quat.addScaledVectorLocal(new Vec3d(0, 1, 0), 0.21);
        quat.normalizeLocal();
         
        look = quat.mult(new Vec3d(0, 0, 1)); 
        up = quat.mult(new Vec3d(0, 1, 0)); 
        left = quat.mult(new Vec3d(1, 0, 0));
        System.out.println("look:" + look + "  up:" + up + "  left:" + left);
        
        quat.addScaledVectorLocal(new Vec3d(0, 1, 0), 0.2);
        quat.normalizeLocal();
         
        look = quat.mult(new Vec3d(0, 0, 1)); 
        up = quat.mult(new Vec3d(0, 1, 0)); 
        left = quat.mult(new Vec3d(1, 0, 0));
        System.out.println("look:" + look + "  up:" + up + "  left:" + left);

Output:

        look:Vec3[0.0, 0.0, 1.0]  up:Vec3[0.0, 1.0, 0.0]  left:Vec3[1.0, 0.0, 0.0]
        look:Vec3[0.2077099972799881, 0.0, 0.978190450285601]  up:Vec3[0.0, 0.9999999999999999, 0.0]  left:Vec3[0.978190450285601, 0.0, -0.2077099972799881]
        look:Vec3[0.3972980072913946, 0.0, 0.9176896498284631]  up:Vec3[0.0, 1.0000000000000002, 0.0]  left:Vec3[0.9176896498284631, 0.0, -0.3972980072913946]

So we see that rotating around the y axis (the second value) does not change the up axis at all… as we’d expect for rotation around the y axis.

I also confirmed that addScaledVector is operating in in world space so I was right to have you multiple by orientation first.

        System.out.println("90 degrees rotation...");
        quat = new Quatd().fromAngles(0, Math.PI * 0.5, 0);
        look = quat.mult(new Vec3d(0, 0, 1)); 
        up = quat.mult(new Vec3d(0, 1, 0)); 
        left = quat.mult(new Vec3d(1, 0, 0));
        System.out.println("look:" + look + "  up:" + up + "  left:" + left);
        
        quat.addScaledVectorLocal(new Vec3d(1, 0, 0), 0.2);
        quat.normalizeLocal();
         
        look = quat.mult(new Vec3d(0, 0, 1)); 
        up = quat.mult(new Vec3d(0, 1, 0)); 
        left = quat.mult(new Vec3d(1, 0, 0));
        System.out.println("look:" + look + "  up:" + up + "  left:" + left);

Output:

        90 degrees rotation...
        look:Vec3[1.0, 0.0, 2.220446049250313E-16]  up:Vec3[0.0, 1.0, 0.0]  left:Vec3[2.220446049250313E-16, 0.0, -1.0]
        look:Vec3[1.0000000000000002, -4.163336342344337E-17, 1.6653345369377348E-16]  up:Vec3[1.3877787807814457E-17, 0.9801980198019804, 0.19801980198019808]  left:Vec3[1.6653345369377348E-16, 0.19801980198019808, -0.9801980198019805]        

If we were in local space, I’d have expected that to change the look vector and the up vector but instead it changes left and up… because we are sideways with respect to world axes.

1 Like

Ok (well, not Ok actually for me), I’ll double check these things during my replacement. While operating with quaternions I was using mostly lookat and fromangleaxis so everything looked smooth, so I think I’ll have to place some more debug dots to see what is what on screen and in the code…

Hmm I encounter a rare (maybe once per 20 turns) bug with aligning exactly at PI (counter direction) from target point. I’ve checked all the octants and I’m pretty sure geometrically I supply right signs to rotational vel’s components and abs of all the turns must be less than PI, so I suspect kind of precision error… I guess the dot calc is misleaded by the symmetry of cos value around 180: Cos(181°) == Cos(179°) == -0.9998 and hence sometimes it aligns to 180. I don’t see angleBetween implementation so this makes me suspect that either I’m wrong on the whole concept or there must be some other way this case is solved?

I’d have to see code where this comes up. Usually stuff behind you doesn’t matter.

…and problems with 180 degrees generally indicates a Quaternion is involved somewhere it shouldn’t be.

Then there’s another quick question, there is something like:

Vec3d rotVel = ...
return facing.inverse().mult(rotVel);

and then in movement system:

facing.addScaledVectorLocal(facing.mult(rotVel), tpf);

is it always 1:1 match before and after?

I don’t understand the context of the question.

Here’s the code:

Vec3d tdirN = targetPoint.subtract(worldLoc).normalize();
Vec3d left = worldRot.mult(Vec3d.UNIT_X);
Vec3d up = worldRot.mult(Vec3d.UNIT_Y);
double dotX = tdirN.dot(left);
double dotY = tdirN.dot(up);

Vec3d rotVel = new Vec3d( -dotY, dotX, 0 );
rotVel = facing.inverse().mult(rotVel);

then in movement system rotVel is processed as

facing.addScaledVectorLocal(facing.mult(rotVel), tpf);

Yeah, I mean what’s the issue with this code?

Sometimes it rotates not towards target but exactly opposite…
edit: and I checked tdirN and worldRot.mult(Vec3d.UNIT_Z) - they’re opposite by PI.
edit2: I even tried brute force correction if dotX, dotY are close to zero but dotZ is negative - it returns to that same opposite direction…