LookAt Funktion für Kamera

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Andy90
Beiträge: 63
Registriert: 08.10.2023, 13:02

LookAt Funktion für Kamera

Beitrag von Andy90 »

Hallo und Frohe Weinachten euch allen :) ich arbeite nach wie vor noch an meiner "Engine". Aktuell möchte ich die möglichkeit haben, dass meine Kamera auf ein Entity schaut. Ich habe diesen Ansatz, jedoch funktioniert das ganze nicht so wie gewollt :D

Code: Alles auswählen

        public static void LookAt(Camera camera, Vec3 targetPosition)
        {
            Vec3 forward, right, up;

            forward = Vec3.Normalized(targetPosition - camera.Location);
            right = Vec3.Normalized(Vec3.Cross(new Vec3(0.0f, 1.0f, 0.0f), forward));
            up = Vec3.Cross(forward, right);

            // Calculate pitch and yaw
            float pitch = (float)System.Math.Asin(-forward.Y);
            float yaw = (float)System.Math.Atan2(forward.X, forward.Z);

            // Set camera rotation based on the calculated pitch and yaw
            camera.Rotation.X = ToDegrees(pitch);
            camera.Rotation.Y = ToDegrees(yaw);
        }
mtorc1
Beiträge: 80
Registriert: 20.02.2021, 16:24

Re: LookAt Funktion für Kamera

Beitrag von mtorc1 »

Hi,
also mit forward, right und up vector brauchst du eigentlich keine Rotationen mehr auszurechnen. Du kannst die Kamera-Matrix einfach aus den drei Vektoren setzen. Also:

Code: Alles auswählen

cameraMatrix = Mat4x4(
  right.x,    right.y,    right.z,    0.0f,
  up.x,       up.y,       up.z,       0.0f,
  forward.x,  forward.y,  forward.z,  0.0f,
  pos.x,      pos.y,      pos.z,      1.0f
);
//viewMatrix = inverse(cameraMatrix);
Grüße
Letztes Projekt: Grave of the Pumpkin (ZFX Halloween Action 2021)
Andy90
Beiträge: 63
Registriert: 08.10.2023, 13:02

Re: LookAt Funktion für Kamera

Beitrag von Andy90 »

ok und das bewirkt, dann das die kamera auf das Entity zeigt ?
Benutzeravatar
Jonathan
Establishment
Beiträge: 2370
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: LookAt Funktion für Kamera

Beitrag von Jonathan »

In der Praxis würde man dafür halt einfach eine Bibliotheksfunktion nehmen, z.B.:

https://glm.g-truc.net/0.9.5/api/a00176 ... d75907ce97

So ziemlich jedes Framework für 3D Mathe sollte eine entsprechende Funktion beinhalten. Man kann sich die entsprechende Formel auch selber herleiten, aber mir ist nicht ganz klar, was man damit gewinnt. Ich weiß, dass ich es könnte, aber ich weiß auch, dass ich dabei vermutlich 3 dumme Fehler machen würde und am Ende 1.5 Stunden debuggen muss - und weil es dumme Schusselfehler sein werden habe ich danach dann genau gar nichts gelernt, aber erfolgreich 1.5 Stunden Zeit verschwendet. Also lieber gleich eine Bibliotheksversion nutzen ;)
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Andy90
Beiträge: 63
Registriert: 08.10.2023, 13:02

Re: LookAt Funktion für Kamera

Beitrag von Andy90 »

Die funktion habe ich ja, ich meinte eher das ich die kamera auf ein Objekt fixieren kann. Ich glaube der name LookAt ist etwas falsch gewählt. Glaube in Unity ist das z.b. RotateTowards()
Benutzeravatar
Jonathan
Establishment
Beiträge: 2370
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: LookAt Funktion für Kamera

Beitrag von Jonathan »

Das sollte die Funktion ja genau machen. Ich würde eher vermuten dass du woanders noch ein Problem hast, z.B. wie du die Matrizen im Shader kombinierst etc. dazu kann man aber ohne mehr Hintergrundinfos nix sagen.

Intuitiv: Die Kamera ist im Punkt A (eye), der Punkt B (center) ist genau in der Mitte des Sichtfeldes. Zoom wird über die Projektionsmatrix gesteuert, und Rotation über den Up-Vector. Mehr Freiheitsgrade hat man nicht, damit ist die Darstellung der Szene komplett definiert.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Andy90
Beiträge: 63
Registriert: 08.10.2023, 13:02

Re: LookAt Funktion für Kamera

Beitrag von Andy90 »

Ja ich wollte eben mit pitch und yaw sozusagen die Kamera auf ein Objekt ausrichten. Aber alle Ansätze funktionieren nicht wirklich.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2370
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: LookAt Funktion für Kamera

Beitrag von Jonathan »

Wovon reden wir hier denn überhaupt? Ist der Code oben C#? Wie / womit renderst du was, ist das OpenGL?

Vergiss das pitch und yaw erst mal wieder und benutze eine fertige Funktion, das ist ein absoluter Standardfall den du hier hast. Wenn es mit LookAt (oder äquivalenten) funktioniert kannst (und solltest du vlt.) du immer noch deine eigene Lösung basteln und die vergleichen. Man sollte schon in der Lage sein sich die ganzen Sachen selber korrekt herleiten zu können, wenn man aber diesen Punkt einmal erreicht hat ist es nicht unbedingt immer sinnvoll das auch tatsächlich zu tun :D

Wie werden denn deine Vertices genau transformiert? Was ist mit Model und Projektionmatrix etc.? LookAt funktioniert schon und macht das von dem du redest, aber halt nur wenn man es korrekt funktioniert (was zugegebenerweise am Anfang alles andere als trivial ist).
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Andy90
Beiträge: 63
Registriert: 08.10.2023, 13:02

Re: LookAt Funktion für Kamera

Beitrag von Andy90 »

Ich rendere das ganze mit OpenGL. Den wrapper hierfür habe ich selbst geschrieben https://github.com/Andy16823/NetGL-2023. Allerdings nutze ich das "ModernGL" also ich nutze glm für matrizen etc.

Code: Alles auswählen

        public void SetCamera(Camera camera)
        {
            if(camera.Type == CameraType.Ortho)
            {
                float x = camera.Location.X - (camera.Size.X / 2);
                float y = camera.Location.Y - (camera.Size.Y / 2);
                float top = y + camera.Size.Y;
                float right = x + camera.Size.X;

                p_mat = mat4.Ortho(x, right, y, top, 0.0f, 100.0f);
                v_mat = mat4.LookAt(new vec3(0f, 0f, 1f), new vec3(0f, 0f, 0f), new vec3(0f, 1f, 0f));
            }
            else
            {
                vec3 cameraPosition = camera.Location.ToGlmVec3();
                Vec3 cameraFront = Utils.CalculateCameraFront2(camera);

                p_mat = mat4.Perspective(Utils.ToRadians(45.0f), camera.Size.X / camera.Size.Y, camera.Near, camera.Far);
                v_mat =  mat4.LookAt(cameraPosition, cameraPosition + cameraFront.ToGlmVec3(), new vec3(0.0f, 1.0f, 0.0f));
            }

            if(this.camera == null)
            {
                this.camera = camera;
            }
        }
so setze ich die kamera und so rendere ich z.b. ein Element

Code: Alles auswählen

public void DrawElement3D(Element3D element)
        {
            int elementShaderID = (int)element.Propertys["ShaderID"];

            mat4 mt_mat = Utils.GetModelTransformation(element);
            mat4 mr_mat = Utils.GetModelRotation(element);
            mat4 ms_mat = Utils.GetModelScale(element);
            mat4 m_mat = mt_mat * mr_mat * ms_mat;
            mat4 mvp = p_mat * v_mat * m_mat;

            gl.Enable(OpenGL.Texture2D);
            foreach (var material in element.Model.Materials) 
            {
                gl.UseProgram(elementShaderID);
                gl.UniformMatrix4fv(gl.GetUniformLocation(elementShaderID, "mvp"), 1, false, mvp.ToArray());

                if(this.lightSource != null)
                {
                    Vec3 ligtDirection = lightSource.GetLightDirection(camera);
                    Vec3 lightColor = lightSource.GetLightColor();
                    gl.Uniform3f(gl.GetUniformLocation(elementShaderID, "lightPos"), lightSource.Location.X, lightSource.Location.Y, lightSource.Location.Z);
                    gl.Uniform1f(gl.GetUniformLocation(elementShaderID, "lightIntensity"), lightSource.Intensity);
                    gl.Uniform3f(gl.GetUniformLocation(elementShaderID, "lightColor"), lightColor.X, lightColor.Y, lightColor.Z);
                }

                gl.ActiveTexture(OpenGL.Texture0);
                gl.BindTexture(OpenGL.Texture2D, (int)material.Propeterys["tex_id"]);
                gl.Uniform1I(gl.GetUniformLocation(elementShaderID, "textureSampler"), 0);

                gl.ActiveTexture(OpenGL.Texture1);
                gl.BindTexture(OpenGL.Texture2D, (int)material.Propeterys["normal_id"]);
                gl.Uniform1I(gl.GetUniformLocation(elementShaderID, "normalMap"), 1);

                gl.EnableVertexAttribArray(0);
                gl.BindBuffer(OpenGL.ArrayBuffer ,(int)material.Propeterys["vbo"]);
                gl.VertexAttribPointer(0, 3, OpenGL.Float, false, 0, 0);
                
                gl.EnableVertexAttribArray(2);
                gl.BindBuffer(OpenGL.ArrayBuffer, (int)material.Propeterys["tbo"]);
                gl.VertexAttribPointer(2, 2, OpenGL.Float, false, 0, 0);

                gl.EnableVertexAttribArray(3);
                gl.BindBuffer(OpenGL.ArrayBuffer, (int)material.Propeterys["nbo"]);
                gl.VertexAttribPointer(3, 3, OpenGL.Float, false, 0, 0);

                gl.DrawArrays(OpenGL.Triangles, 0, (int)material.Propeterys["tris"]);
            }

            gl.Disable(OpenGL.Texture2D);
            //Console.WriteLine(gl.GetError());
        }
Das rendern an sich funktioniert auch. Wie gesagt ich glaube der name LookAt ist von mir nicht so gut gewählt.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2370
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: LookAt Funktion für Kamera

Beitrag von Jonathan »

Sieht auf den ersten Blick ok aus - außer dass du eine "GetModelTransformation" Funktion hast, ziemlich sicher sollte das "Translation" heißen. Transformation ist der Oberbegriff für alles was du da machst.

Ansonsten: Gehts denn jetzt oder nicht? Was passiert und was sollte passieren? Benutzt LookAt intern die GLM Implementierung oder deine eigene?
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Andy90
Beiträge: 63
Registriert: 08.10.2023, 13:02

Re: LookAt Funktion für Kamera

Beitrag von Andy90 »

Mit dem Rendern ist alles klar, dass passt alles soweit. Ich habe in der Scene z.b. eine Qube und auf diesen möchte ich die Kamera ausrichten. So das der Qube immer in der Mitte der Kamera ist.

Hier ist noch meine Funktion zur Berechnung der Camera front.

Code: Alles auswählen

        public static Vec3 CalculateCameraFront2(Camera camera)
        {
            Vec3 direction = new Vec3(0f);
            direction.X = (float)(System.Math.Cos(Utils.ToRadians(camera.Rotation.Y)) * System.Math.Cos(Utils.ToRadians(camera.Rotation.X)));
            direction.Y = (float)System.Math.Sin(Utils.ToRadians(camera.Rotation.X));
            direction.Z = (float)(System.Math.Sin(Utils.ToRadians(camera.Rotation.Y)) * System.Math.Cos(Utils.ToRadians(camera.Rotation.X)));
            return Vec3.Normalized(direction);
        }
Also ziel ist es demnach den Pitch und Yaw von der Kamera zu dem Objekt zu berechnen.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2370
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: LookAt Funktion für Kamera

Beitrag von Jonathan »

Andy90 hat geschrieben: 27.12.2023, 13:11 Also ziel ist es demnach den Pitch und Yaw von der Kamera zu dem Objekt zu berechnen.
Warum? In Winkel zu denken macht hier wirklich alles komplizierter. Nützlicher ist die Interpretation, dass eine Matrix die Achsen eines Koordinatensystems auf die eines anderen abbildet und damit dann auch automatisch alle anderen Punkte korrekt abgebildet werden. Die Achsen kriegt man durch simples Subtrahieren und Normalisieren, man braucht keine Winkel und kein Sinus und kein gar nichts. Wenn das nicht klar ist, vielleicht nochmal ein Matrizen-Tutorial lesen. Sowas brauchst du ja auch wenn du z.B. Normalmapping implementieren willst und dir dann irgendwann eine komplette Transformationsmatrix zusammenbauen musst.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Andy90
Beiträge: 63
Registriert: 08.10.2023, 13:02

Re: LookAt Funktion für Kamera

Beitrag von Andy90 »

Verstehe schon was du meinst. Ich müsste allerdings so das gesammte rendering umschreiben. Weil aktuell schaut meine Kamera klasse so aus

Code: Alles auswählen

using Genesis.Core;
using Genesis.Math;
using GlmSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Genesis.Graphics
{
    public class PerspectiveCamera : Camera
    {
        public PerspectiveCamera(Vec3 location, Vec3 size, float near, float far) : base(location, size, near, far)
        {
            this.Type = CameraType.Perspective;
        }

        public Vec3 CameraFront()
        {
            return Utils.CalculateCameraFront2(this);
        }

        public void MoveForward(float value)
        {
            this.Location += Utils.CalculateCameraFront2(this) * value;
        }

        public void MoveBackward(float value)
        {
            this.Location -= Utils.CalculateCameraFront2(this) * value;
        }

        public void MoveUp(float value)
        {
            this.Location += new Vec3(0.0f, value, 0.0f);
        }

        public void MoveDown(float value)
        {
            this.Location -= new Vec3(0.0f, value, 0.0f);
        }

        public void MoveLeft(float value)
        {
            this.Location -= Vec3.Cross(Utils.CalculateCameraFront2(this), new Vec3(0.0f, 1.0f, 0.0f)) * value;
        }

        public void MoveRight(float value)
        {
            this.Location += Vec3.Cross(Utils.CalculateCameraFront2(this), new Vec3(0.0f, 1.0f, 0.0f)) * value;
        } 
        public Vec3 Forward(float distance)
        {
            return this.Location + Utils.CalculateCameraFront2(this) * distance;
        }
    }
}
also ich speichere die view matrix nicht ab, sondern berechne die bei jedem rendern neu, mithilfe der camara front

Code: Alles auswählen

        public static Vec3 CalculateCameraFront2(Camera camera)
        {
            Vec3 direction = new Vec3(0f);
            direction.X = (float)(System.Math.Cos(Utils.ToRadians(camera.Rotation.Y)) * System.Math.Cos(Utils.ToRadians(camera.Rotation.X)));
            direction.Y = (float)System.Math.Sin(Utils.ToRadians(camera.Rotation.X));
            direction.Z = (float)(System.Math.Sin(Utils.ToRadians(camera.Rotation.Y)) * System.Math.Cos(Utils.ToRadians(camera.Rotation.X)));
            return Vec3.Normalized(direction);
        }
Ich glaube ich bin das damals als ich damit begonnen habe einfach alles etwas zu kompliziert angegangen.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2370
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: LookAt Funktion für Kamera

Beitrag von Jonathan »

Ah verstehe - du speicherst deine Kamera als "Blickrichtung in Winkeln", was natürlich den Vorteil hat, dass man sich einfach drehen kann, weil man dazu nur einen Offset auf den Blickwinkel addieren muss. Und du willst jetzt die Kamera auf ein Objekt richten, danach aber die Möglichkeit haben sich trotzdem weiter umsehen zu können. In diesem Falle macht es dann doch tatsächlich Sinn, mit Winkeln zu arbeiten.

Aber auch dann sollte es prinzipiell kein großes Problem sein, die Winkel zu berechnen. Du wirst ja vermutlich schon davon ausgehen, dass der Up-Vector immer gleich bleibt, ansonsten sind pitch und yaw ja nicht sinnvoll definiert.
Aber dann zerleg halt das Problem irgendwie sinnvoll. Baue eine Szene, wo man in jede Richtung irgendwas sieht, damit du immer weiß, wohin die Kamera zeigt. Versuche erstmal nur den Yaw-Winkel korrekt zu berechnen bevor du Pitch hinzunimmst. Rechne notfalls auf einem Blatt Papier nochmal durch, welche Zahlenwerte rauskommen sollen. Da muss man sich einfach durchbeißen und mal einen Tag lang debuggen, aber dann sollte es eigentlich kein großes Problem sein. Am Ende wird es höchstwahrscheinlich ein triviales Fehlerchen sein das dir alles kaputt macht, aber das wird vermutlich niemand für dich suchen.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Matthias Gubisch
Establishment
Beiträge: 470
Registriert: 01.03.2009, 19:09

Re: LookAt Funktion für Kamera

Beitrag von Matthias Gubisch »

Nur mal aus Neugier
Aber was heißt denn funktioniert nicht so wie gewollt?
Ist die Camera instabil? Zeigt sie in die falsche Richtung, Stimmt sie Initial und zeigt erst bei Bewegung seltsames Verhalten?

Fehlersuche fängt immer mit einer Analyse der Diskrepanz zwischen Ist-Verhalten und gewünschtem/erwarteten Verhalten an.
Beim Fragen nach Hilfe hilft dass den Leuten auch dich in die richtige Richtung zu schieben.

Ansonsten gab es ja schon genug Tipps zum Debugging, wenn du Logging (oder die Möglichkeit Text zu rendern) in deiner Engine hast hilft es oft auch die Daten auszugeben
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
Andy90
Beiträge: 63
Registriert: 08.10.2023, 13:02

Re: LookAt Funktion für Kamera

Beitrag von Andy90 »

Habe das nun so gemacht wie du vorgeschlagen hast Jonathan. Habe mir eine scene erstellt mit mehren qubes in verschiedenen locations um die kamera herrum

Code: Alles auswählen

            QUBE

QUBE   KAMERA   QUBE

            QUBE
und habe mit der Scene demnach erst den Yaw Winkel berechnet und danach dann den Winkel für den pitch. Nun funktioniert das ganze auch. Hier mal mein Code

Code: Alles auswählen

public static void LookAt(Camera camera, Vec3 targetPosition)
        {
            camera.Rotation.Y = Utils.CalculateYaw(camera.Location, targetPosition);
            camera.Rotation.X = Utils.CalculatePitch(camera.Location, targetPosition);
        }

        public static float CalculateYaw(Vec3 point1, Vec3 point2)
        {
            double deltaX = point2.X - point1.X;
            double deltaZ = point2.Z - point1.Z;
            float radians = (float)System.Math.Atan2(deltaZ, deltaX);
            float angle = (float)(radians * (180 / System.Math.PI));

            return angle;
        }

        public static float CalculatePitch(Vec3 point1, Vec3 point2)
        {
            double deltaY = point2.Y - point1.Y;
            double horizontalDistance = System.Math.Sqrt((point2.X - point1.X) * (point2.X - point1.X) + (point2.Z - point1.Z) * (point2.Z - point1.Z));
            float radians = (float)System.Math.Atan2(deltaY, horizontalDistance);
            float pitch = (float)(radians * (180 / System.Math.PI));

            return pitch;
        }
Für die Pitch berechnung hatte ich mir etwas hilfe von chatgpt gesucht.

@Matthias Gubisch, mein fehler lag darin das die kamera nicht auf den punkt gezeigt hatte. Also eine falsche Ausrichtung hatte.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2370
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: LookAt Funktion für Kamera

Beitrag von Jonathan »

Andy90 hat geschrieben: 28.12.2023, 14:57 Für die Pitch berechnung hatte ich mir etwas hilfe von chatgpt gesucht.
Eieiei, nennt mich altmodisch, aber ich glaube nicht dass außer Spaß und Spielereien aus diesen Text-Netzwerken irgendetwas nützliches heraus kommen kann. Im besten Fall hast du nichts gelernt (und wenn man Spieleprogrammierung betreiben möchtet schadet es wirklich nicht Winkel komplett selber verstanden zu haben ;) ), im schlimmsten Fall ist es einfach nur Quatsch. Das mag in diesem Fall egal sein, da man ziemlich offensichtlich sehen kann, ob es funktioniert oder nicht; richtig schlimm wird es erst bei Antworten deren Korrektheit man nicht trivial überprüfen kann. Ich hab es schon bei genügend Studenten gesehen, dass dann einfach irgendein Quatsch benutzt oder damit weiter gerechnet wird, was sich dann am langen Ende natürlich rächt. Dinge die man tut zu verstehen ist einfach alternativlos.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Andy90
Beiträge: 63
Registriert: 08.10.2023, 13:02

Re: LookAt Funktion für Kamera

Beitrag von Andy90 »

Er macht viele Fehler, aber ich versuche natürlich das alles zu verstehen und lasse es mir von der KI noch erklären. Der größte Benefit ist wohl, dass es zeit spart beim suchen. Aber ja, ich denke auch, dass umso mehr Leute das nutzen umso mehr wissen geht einfach "verloren".
Benutzeravatar
TomasRiker
Beiträge: 36
Registriert: 18.07.2011, 11:45
Echter Name: David Scherfgen
Wohnort: Hildesheim

Re: LookAt Funktion für Kamera

Beitrag von TomasRiker »

Jonathan hat geschrieben: 29.12.2023, 09:49
Andy90 hat geschrieben: 28.12.2023, 14:57 Für die Pitch berechnung hatte ich mir etwas hilfe von chatgpt gesucht.
Eieiei, nennt mich altmodisch, aber ich glaube nicht dass außer Spaß und Spielereien aus diesen Text-Netzwerken irgendetwas nützliches heraus kommen kann.
Auf die Gefahr hin, dass das jetzt ausartet: Du solltest dir mal GitHub Copilot anschauen (falls nicht schon geschehen). Da bleibt dir die Spucke weg. Ich hatte oft den Eindruck, dass das Teil meine Gedanken lesen kann. Ich fange an etwas zu tippen, und sei es nur ein Kommentar, und dann spuckt es genau das aus, was ich schreiben wollte.
smurfer
Establishment
Beiträge: 199
Registriert: 25.02.2002, 14:55

Re: LookAt Funktion für Kamera

Beitrag von smurfer »

Hi zusammen,

ich muss Jonathan und TomasRiker (im einführenden Satzteil) zustimmen, zum einen muss ich mir gerade bzgl. Machine Learning etwas auf die Zunge beißen, zum anderen sollte das hier nicht zu sehr im Offtopic ausarten. Vielleicht nur zwei kurze Sätze: Falls Machine-Learning-Verfahren verwendet werden, bitte, bitte die Grenzen der Verfahren verstehen und gelöste Dinge auf Basis "herkömmlicher" Quellen erlernen (die letztlich von den ML-Verfahren genutzt werden). Die Verfahren -- gerade generative -- sind nicht auf Korrektheit, sondern auf Plausibilität trainiert.

Beste Grüße, smurfer
Antworten