Jump to content
Unity Insider Forum

LookAt mit allen Extras benötigt, nur Wie? [gelöst - in Grenzen]


L.Tester

Recommended Posts

Guten Morgen Forum,

Gegeben ist ein Modell mit Animation, an welchem ich keine Grundsätzlichen Änderungen vornehmen kann.
Das Modell hat ein "Halsgelenk", das ich in LateUpdate ausrichten möchte. Natürlich und leider ist bei dem Halsgelenk "Oben" nicht (0,1,0) und "Vorne" nicht (0,0,1), sondern (irgendwas). Weiter wird das Modell in alle Richtungen gedreht werden, "Oben" ist dann immer Modell.transform.up. Die Animation bewegt vom "Halsgelenk" aus gesehen eine Hierachie von Eltern-Joints
Das Ausrichten soll nicht über eine absolute Rotation erfolgen, sondern über ... delta R, heißt das so? Eine Rotations-Änderung.
Als Hilfselement habe ich ein Gameobject unter das "Halsgelenk" eingefügt, das manierlich nach vorne schaut und den Kopf hoch hält - bildlich gesprochen.

Unten angefügt ist meine bisherige "LateUpdate", die leider keinen "Up"-Vektor berücksichtigt.

Meine Suchbegriffe, eigentlich ganz ergiebig, aber dennoch ...
lookat, forward, up, quaternion, convert, transform

Mein Problem ist, das ich keine der im Netz angebotenen Lösungswege zum laufen bekomme: Die Vorschläge über localRotation, InverseTransformDirection bzw. TransformDirection drehen bei mir um die falschen Achsen, die Matrix-Lösung bekomme ich nicht mal ansatzweise in Unity implementiert, die Lösungen über das Kreuzprodukt Jittern beziehungsweise nähern sich nur iterativ dem Ziel. Es gibt einfach zu viele Möglichkeiten, etwas falsch zu machen wenn man keine Ahnung hat - zumal ich nicht immer weiß, was "unter der Haube" abläuft.

Ich bin an einem Punkt angekommen, an dem ich sehr kleinlaut um einen funktionierenden Code bitten muss.
Bitte, kann mir jemand hier weiterhelfen? 

 

So soll es später aussehen, nur mit der Berücksichtigung von "Oben":



    private void LateUpdate()
    {
        //eyes + neckJoint haben die selbe Position

        Vector3 lookDirectionWorld = target.position - eyes.position;

        Vector3 fromVector = eyes.forward;
        Vector3 toVector = lookDirectionWorld;


        Quaternion rotation = Quaternion.FromToRotation(fromVector, toVector);

        neckJoint.rotation = rotation * neckJoint.rotation;


        Debug.DrawRay(eyes.position, eyes.forward * 31, Color.cyan);
    }


 Gruß von Lutz

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn du das Humanoid-Animation-System benutzt, dann könnte dir ein altes Tutorial von mir helfen. Das ist zwar mit einer alten Version von Unity gemacht, aber grundsätzlich sind alle Elemente noch genauso da. In dieser Folge zeige ich, wie man den Kopf eines Männchens über die Animationsbefehle einem Ziel folgen lässt.

 

Vielleicht hilfts dir.

Link zu diesem Kommentar
Auf anderen Seiten teilen

N'Abend Forum, hier der ThreadStarter.

Wenn man bedenkt, das dieses Problem nur ein "klitzekleines" Hindernis sein sollte, welches ich "mal eben" lösen wollte ....

Also, eine komplette Lösung gibt es noch nicht, dazu hatte ich an diesem Wochenende auch zu wenig Zeit. ABER, ein Teilerfolg: Ein Problem ist ja, das ich eine Rotations-ÄNDERUNG brauche. Das entspricht also Rotation2 - Rotation1 bzw. Quaternion2 - Quaternion1.


    private Quaternion QDifference(Quaternion a, Quaternion b)
    {
        return Quaternion.Inverse(a) * b;
    }

Ich glaube, da muss ich noch ein wenig umstellen, denn in LateUpdate() musste ich auch noch was umstellen, das könnte sonst zu Verwirrung führen. Hier habe ich nur schnell getestet ob das Teilproblem so gelöst werden kann :

    private void LateUpdate()
    {
        //eyes + neckJoint haben die selbe Position
        
        Vector3 lookDirectionWorld = target.position - eyes.position;

        Vector3 fromVector = eyes.forward;
        Vector3 toVector = lookDirectionWorld;


        Quaternion rotation1 = Quaternion.LookRotation(lookDirectionWorld, Vector3.up);
        Quaternion rotation2 = QDifference(neckJoint.rotation, rotation1);

        neckJoint.rotation =  neckJoint.rotation * rotation2;

        Debug.DrawRay(eyes.position, eyes.forward * 31, Color.cyan);
    }

Klappt!

Ich werde jetzt Schluss machen, nächste Woche geht es weiter. Ich denke, ihr könnt euch zurücklehnen und warten, der Rest sollte doch ein Klacks sein ...

Gruß von Lutz.

 

Hallo @malzbie, oder auf Youtube: @MrMalzbie,

ich habe Dein Video nebenbei laufen lassen : Nein, ich benutze kein Humanoid-Animation-System. Ich glaube, ich könnte es ähnlich wie Du über OnAnimatorIK() lösen. Jetzt möchte ich aber erstmal bei der Manipulation der Animation in LateUpdate() bleiben. Ich glaube, das ich damit auskomme: Ausserdem: Ich lerne auch noch, mit Quaternions umzugehen - zumindest im Rahmen von Unity, die mathematischen Grundlagen überfordern mich etwas.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Forum, hier der ThreadStarter,

So viele Wochenenden - und dann brachte eine entscheidende Zeile Code innerhalb einer halben Stunde das Ergebnis.
Wer es brauchen kann, hoffentlich hat der Mann mit dem Hut nicht so viel zu meckern:

using UnityEngine;

/*
 Führt durch die Überlagerung von RotationDeltaSoll beziehungsweise über den smoothen Wert RotationDeltaLast ein Transform einem Target nach.
 Der Wert von RotationDeltaSoll wird anhand des Hilfsobjektes Eyes berechnet, welches korrekt ausgerichtet und dem Transform untergeordnet ist.
 Dadurch ist es nicht notwendig, daß das Transform bezüglich Vorne/Oben korrekt ausgerichtet ist.
Benutzt wird die Unity-Funktion Quaternion.LookRotatin.
 */

public class LookAt1 : MonoBehaviour
{

    public Transform NeckJoint;
    public Transform Eyes;


    public Transform Target;


    public bool Clamped;

    public float MaxY_Deg;
    public float MaxX_Deg;

    public float Acceleration;

    private Quaternion rotationDeltaLast;



    private void LateUpdate()
    {
        Quaternion RotationDeltasoll = MyLookAtDelta(Eyes, Target, Vector3.up);


        Vector3 v3 = RotationDeltasoll.eulerAngles;
        v3.y = MyClamp(v3.y, MaxY_Deg);
        v3.x = MyClamp(v3.x, MaxX_Deg);
        RotationDeltasoll.eulerAngles = v3;

        rotationDeltaLast = Quaternion.LerpUnclamped(rotationDeltaLast, RotationDeltasoll, Acceleration);
        NeckJoint.rotation = rotationDeltaLast * NeckJoint.rotation;
    }



    private float MyClamp(float f, float max)
    {
        if (f > 180)
            f -= 360;
        f = Mathf.Clamp(f, -max, max);
        if (Mathf.Abs(f) == max)
            Clamped = true;
        else
            Clamped = false;
        if (f < 0)
            f += 360;
        return f;
    }



    private Quaternion MyLookAtDelta(Transform correctTransform, Transform target)
    {
        return MyLookAtDelta(correctTransform, target.position - correctTransform.position, Vector3.up);
    }

    private Quaternion MyLookAtDelta(Transform correctTransform, Transform target, Vector3 up)
    {
        return MyLookAtDelta(correctTransform, target.position - correctTransform.position, up);
    }

    private Quaternion MyLookAtDelta(Transform correctTransform, Vector3 lookDirection)
    {
        return MyLookAtDelta(correctTransform, lookDirection, Vector3.up);
    }

    private Quaternion MyLookAtDelta(Transform correctTransform, Vector3 lookDirection, Vector3 up)
    {
        return Quaternion.LookRotation(lookDirection, up) * Quaternion.Inverse(correctTransform.rotation);
    }

    private Quaternion QDifference(Quaternion a, Quaternion b)
    {
        return b * Quaternion.Inverse(a);
    }


}

Ich benutze das Script in einer etwas anderen Form, für euch habe ich den Ballast raus genommen und nochmal überprüft. 

Ich denke, man könnte ohne das Hilfsobjekt auskommen, aber ich will endlich weiterkommen, und da es funktioniert ...

 

Gruß von Lutz.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...