How can character's body be continuously rotated when its head is already turned by 60°`?
Asked Answered
A

2

16

After some experimenting I parented an empty (HeadCam) to the character's neck. This snippet allow rotation of the head synchronously to the CardboardHead/Camera.

void LateUpdate() {
    neckBone.transform.rotation = Camera.transform.rotation *  Quaternion.Euler( 0,0,-90);
    Camera.transform.position = HeadCam.transform.position;
}

enter image description here

The character's arms shouldn't move when only the head rotates as long in the range -60° to 60° after that I would like to move the whole character with the arms still visible. The following method works as long the character isn't rotated by more than 180° after that the characters flips by 180° how could I achieve constant rotation?

void LateUpdate() {
    Quaternion camRot = Camera.transform.rotation * Quaternion.Euler( 0,0,-90);                 
    neckBone.transform.rotation = camRot;
    float yrot = camRot.eulerAngles.y;
    float ydelta = 0;
    if ( yrot < 300f && yrot > 180 ) {
        ydelta = yrot - 300f;
    }
    if ( yrot > 60f && yrot < 180 ) {
        ydelta = yrot - 60;
    }
    playerObj.transform.rotation =  Quaternion.Euler(0, ydelta, 0); 
    Camera.transform.position = HeadCam.transform.position;
}

enter image description here

A java applet for testing the algorithm standalone: https://github.com/3dbug/blender/blob/master/HeadCamRot.java

Admiralty answered 4/6, 2015 at 21:14 Comment(4)
couldn't you use an animation easier for this purpose?Glossography
@Glossography it is a virtual reallity app the rotation must be in real time applied according to the cameras movement. Basically you would see yourself when you look down.Admiralty
I'm not sure about virtual reality stuff- maybe the mouselook script from the unity5 prefabs could help youGlossography
Ah, I see. Er, well, I didn't, but now I do.Salgado
A
1

Finally I found a solution for this:

private float bodyRot = 0F;
private float FOV = 70f;

void LateUpdate() {
    if ( neckBone != null ) {
        Quaternion camRotQ = CameraFacing.transform.rotation * Quaternion.Euler( 0,0,-90);
        neckBone.transform.rotation = camRotQ;
        float camRot = camRotQ.eulerAngles.y;

        float delta = camRot- bodyRot;
        if ( delta > 180 ) {
            delta -= 360;
        }
        if ( delta < -180 ) {
            delta += 360;
        }
        if ( Math.Abs(delta) > FOV ) {
            if ((delta > FOV || delta < -180) && delta < 180) {
                bodyRot = camRot - FOV;
            }
            delta = camRot- bodyRot;
            if ((delta < FOV || delta > 180 ) ) {
                bodyRot = camRot + FOV;
            }
        }
        playerObj.transform.rotation =  Quaternion.Euler(0, bodyRot, 0); 
        CameraFacing.transform.position = cameraMount.transform.position;
    }
}
Admiralty answered 8/6, 2015 at 22:13 Comment(0)
R
3

One possible solution would be:

// Transform of the full body of the character.
Transform body;
// Transform of the head (child of |body| component).
Transform head;
// Maximum delta angle in degrees.
float maxAngle = 60.0f;

void RotateCharacter(Quaternion target) {
  // Rotate head as much as possible without exceeding the joint angle.
  head.rotation = Quaternion.RotateTowards (body.rotation, target, maxAngle);
  // Complete the remainder of the rotation by body.
  body.rotation = target * Quaternion.Inverse (head.localRotation);
}

Please keep in mind that you might need to limit non-horizontal rotations beforehand, i.e., I assumed given x & z angles of the passed rotation won't exceed maxAngle. Besides, even so, it should be quite straightforward to add that limitation as well inside the function above if needed.

Hope it helps.

Rejoin answered 6/6, 2015 at 0:25 Comment(3)
Thanks, what should be used as target? Currently I read the rotation from the Cardboard camera and base calculation on it.Admiralty
Cardboard camera's orientation (Transform.rotation) should be the target in this case. Of course, if your character model has some initial orientation, i.e., not the same as camera's initial orientation, you should also take that into account to match its final rotation.Rejoin
Thanks again, this probably takes more time fto get it right. When I find a solution I will post it here. The problem can be reduced to Unitys behaviour to wrap rotation on 0 and 360° so the calculation need to take this into account. ` Quaternion.RotateTowards`could be really helpful in some cases.Admiralty
A
1

Finally I found a solution for this:

private float bodyRot = 0F;
private float FOV = 70f;

void LateUpdate() {
    if ( neckBone != null ) {
        Quaternion camRotQ = CameraFacing.transform.rotation * Quaternion.Euler( 0,0,-90);
        neckBone.transform.rotation = camRotQ;
        float camRot = camRotQ.eulerAngles.y;

        float delta = camRot- bodyRot;
        if ( delta > 180 ) {
            delta -= 360;
        }
        if ( delta < -180 ) {
            delta += 360;
        }
        if ( Math.Abs(delta) > FOV ) {
            if ((delta > FOV || delta < -180) && delta < 180) {
                bodyRot = camRot - FOV;
            }
            delta = camRot- bodyRot;
            if ((delta < FOV || delta > 180 ) ) {
                bodyRot = camRot + FOV;
            }
        }
        playerObj.transform.rotation =  Quaternion.Euler(0, bodyRot, 0); 
        CameraFacing.transform.position = cameraMount.transform.position;
    }
}
Admiralty answered 8/6, 2015 at 22:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.