SOLVED - Arcball Rotation mit Verschieben und Zoom mit Maus



  • EDIT: Das Problem ist mittlerweile gelöst. Den Code findet ihr in meinem letzten Post. Ich habe mir erlaubt, auch alle Videos von YouTube zu entfernen - ausgenommen das, auf welches ich im letzten Post verweise. Danke für alle Hilfen und Anregungen...

    Hallo.

    Ich stelle einen Körper mit opengl dar. Der Körper wirdgeladen und seine BoundingBox wird berechnet. XMin, xMax, yMin etc. sind also bekannt. Über die Maus kann ich den Körper dann drehen (glrotate), verschieben (gltranslate) und zoomen (glscale).

    Funktioniert erstmal alles wunderbar. Allerdings verschwindet der Körper nach ein paar Operationen. Er wird in erster Linie in der Tiefe geclipped - manchmal auch zur Seite hin.

    Mir ist bekannt, dass ich die zu zeichnen Box mit glortho (es soll orthogonal projiziert werden) festlegte und ich die zNear und zFar Ebene über gluPerspective festlege.

    Wenn ich jedoch bei glortho meine mir bekannten Körper-Abmessungen angebe und die maximale Koordinatendifferenz zur Festlegung von zNear (immer 1.0) und zFar (1.0 + maximale Abmessung) nutze mache ich alles nur schlimmer.

    Am besten fahre ich noch komplett ohne glortho und zNear immer 1.0 und zFar immer 1.0, wenngleich dann oben beschriebenes passiert.

    Hat jemand einen Tipp für mich, wie ich diese Parameter sinnvoll wählen kann?

    Vielen Dank,
    CJens



  • Verwendest du nun GlOrtho oder GluPerspective? Beide Befehle zugleich geht nicht. Da du ja wohl offentsichtlich Orthogonal zeichen willst, musst du auch nur GlOrtho verwenden, und dann dort nearVal und farVal angeben.

    https://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml

    Ist bei die zNear nun -1 oder +1 ? Du schreibst +1 aber ich denke doch du meinst Minus oder?


  • Mod

    vielleicht kannst du relevante code stellen posten oder vom beschriebenen problem ein kurzes video machen (youtube).



  • Danke, dass sich so viele dafür interessiert haben und entschuldigt, die späte Antwort - ich habe nach nem Umzug erst seit vorgestern wieder Internet und hatte den Request via Handy reingestellt.

    Ich lade ein vorhandenes Gitter. Dieses möchte ich darstellen und wie folgt bewegen:
    Rechte Maustaste ist verschieben.
    Mausrad ist zoom
    Mittlere Maustaste ist drehen um den Körperschwerpunkt.

    Das ganze klappt auch ganz gut, aber nach ein paar Transformationen verschwindet das Gitter. Ich gehe von einem falsch definierten Z Buffer aus.

    Ich habe ein Video von dem Fall auf Youtube geladen.
    https://www.youtube.com/watch?v=k1JgoH40e5k

    Es wird schon immer nicht das gesamte Auto angezeigt. Aber nach 33 Sekunden passiert "etwas" und dann ist das Netz kaum noch zu sehen.

    Das Programm habe ich in C# geschrieben. Ich nutze Tao-Framework. Hier relevanter Code:

    /*Mausaktionen auf dem OGL-Steuerelement:*/
            private void MainOGL_MouseMove(object sender, MouseEventArgs e)
            {
                OGL_Handle.OGLMouseMove(e);
            }
    
            private void MainOGL_MouseDown(object sender, MouseEventArgs e)
            {
                OGL_Handle.OGLMouseDown(e);
                MainControls.OGL.Refresh();
            }
    
            private void MainOGL_MouseWheel(object sender, MouseEventArgs e)
            {
                OGL_Handle.OGLMouseWheel(e);
                MainControls.OGL.Refresh();
            }
    
    /*Code, wenn die Maus bewegt wird*/
           public static void OGLMouseMove(MouseEventArgs e){
                int[] XClick = new int[2] { e.X, e.Y };
                double[] WC = new double[3] { .0, .0, .0 };
                bool OnTarget = false;
    
    /*Lade aktuelle Projektions- und Modelviewmatrix und den aktuellen Viewport*/
                UpdateOGLMatrix();
    
    /*Liefert die Weltkoordinaten des letzten Clicks*/
                OnTarget = OGL_Handle.WorldCoord(XClick, ref WC, OGL_Handle.MyViewPort, OGL_Handle.MyModelView, OGL_Handle.MyProject);
    
                if (e.Button == MouseButtons.Right)
                {
                    OGL_Handle.Panning(e);
                    MainControls.MainStatusText.Text = "Panning...";
                    OGL_Handle.RenderImmidiate();
                    MainControls.OGL.Refresh();
                }
                else if (e.Button == MouseButtons.Middle)
                {
                    OGL_Handle.Rotating(e);
                    MainControls.MainStatusText.Text = "Rotating...";
                    OGL_Handle.RenderImmidiate();
                    MainControls.OGL.Refresh();
                }
            }
    
            public static void UpdateOGLMatrix()
            {
                Gl.glGetIntegerv(Gl.GL_VIEWPORT, MyViewPort);
                Gl.glGetDoublev(Gl.GL_MODELVIEW_MATRIX, MyModelView);
                Gl.glGetDoublev(Gl.GL_PROJECTION_MATRIX, MyProject);
            }
    
    /*Drehen*/
            public static void Rotating(MouseEventArgs e){
                double ax, ay, az;
                double bx, by, bz;
                double angle;
                ax = e.Y - LastClick[1];
                ay = e.X - LastClick[0];
                LastClick[0] = e.X; LastClick[1] = e.Y;
                az = 0.0;
    
                Gl.glGetIntegerv(Gl.GL_VIEWPORT, MyViewPort);
                angle = Math.Sqrt(ax * ax + ay * ay + az * az) /(double)(MyViewPort[2] + 1) * 180.0;
    
                Gl.glGetDoublev(Gl.GL_MODELVIEW_MATRIX, MyModelView);
    
                double[] MyModelViewInvers = new double[16];
                __gluInvertMatrixd(MyModelView, MyModelViewInvers);
    
                bx = MyModelViewInvers[0] * ax + MyModelViewInvers[4] * ay +
                    MyModelViewInvers[8] * az;
                by = MyModelViewInvers[1] * ax + MyModelViewInvers[5] * ay +
                    MyModelViewInvers[9] * az;
                bz = MyModelViewInvers[2] * ax + MyModelViewInvers[6] * ay +
                    MyModelViewInvers[10] * az;
    
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
                Gl.glTranslated(OGL_Handle.RotationCenter[0], OGL_Handle.RotationCenter[1], 0.0);
                Gl.glRotated(angle, bx, by, bz);
                Gl.glTranslated(-OGL_Handle.RotationCenter[1], -OGL_Handle.RotationCenter[1], 0.0);
            }
    
    /*Verschieben*/
            public static void Panning(MouseEventArgs e)
            {
                double Factor = 1.5;
    
                double[] MouseWorld = new double[3]{.0,.0,.0};
                int[] Mouse = new int[2]{e.X, e.Y};
                UpdateOGLMatrix(); 
                WorldCoord(Mouse, ref MouseWorld, MyViewPort, MyModelView, MyProject);
    
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
                Gl.glTranslated(Factor * (MouseWorld[0] - LastClickWorld[0]),
                    Factor * (MouseWorld[1] - LastClickWorld[1]), 
                    Factor * (MouseWorld[2] - LastClickWorld[2]));
            }
    
    /*Skalieren*/
            public static void Scaling(MouseEventArgs e)
            {
                int[] XStart = new int[2] { e.X, e.Y };
    
                double[] MouseWorld = new double[3] { .0, .0, .0 };
                double f = Math.Exp(0.1 * (double)e.Delta / 120.0);
                ZoomFactor *= f;
    
                UpdateOGLMatrix(); 
                WorldCoord(XStart, ref MouseWorld, MyViewPort, MyModelView, MyProject);
    
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
                Gl.glTranslated(MouseWorld[0], MouseWorld[1], MouseWorld[2]);
                Gl.glScaled(f, f, f);
                Gl.glTranslated(-MouseWorld[0], -MouseWorld[1], -MouseWorld[2]);
            }
    

    Hier noch der Code des Renderers:

    public static void RenderImmidiate(){
                SimpleOpenGlControl OGL = MainControls.OGL;
                Struct_cs.TFamily* Fam = null;
                Struct_cs.TFace* F = null;
                CFamily CF = null;
    
                if (OGL != null)
                {
                    ClearScreen();
    
                    GlobalVariables.AllLightSettings.UpdateAllLights();
    
                    if (GlobalVariables.MainGraphicSettings.DisplayStyle == DisplayTypeENUM.SOLID) { Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_FILL); } else { Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_LINE); }
                    foreach (CMesh CM in GlobalVariables.MeshStack)
                    {
                        for (int k = 1; k < CM.CFamilies.Count(); k++)
                        {
                            CF = CM.CFamilies[k];
                            if (CF.Display == true)
                            {
                                Fam = CF.Fam;
    
                                SetMaterial(CF);
    
                                Gl.glColor4f((float)CF.FamilyColor.R / 255, (float)CF.FamilyColor.G / 255, (float)CF.FamilyColor.B / 255, (float)CF.Alpha/255);
    
                                for (UInt32 i = 0; i < Fam->npFace; i++)
                                {
                                    F = Fam->ppFace[i];
                                    switch (F->nNode)
                                    {
                                        case 3:
                                            Gl.glBegin(Gl.GL_TRIANGLES);
                                            Gl.glNormal3d(F->Normal.vx[0], F->Normal.vx[1], F->Normal.vx[2]);
                                            Gl.glVertex3d(F->ppNode[0]->P.x[0], F->ppNode[0]->P.x[1], F->ppNode[0]->P.x[2]);
                                            Gl.glVertex3d(F->ppNode[1]->P.x[0], F->ppNode[1]->P.x[1], F->ppNode[1]->P.x[2]);
                                            Gl.glVertex3d(F->ppNode[2]->P.x[0], F->ppNode[2]->P.x[1], F->ppNode[2]->P.x[2]);
                                            Gl.glEnd();
                                            break;
                                        case 4:
                                            Gl.glBegin(Gl.GL_QUADS);
                                            Gl.glNormal3d(F->Normal.vx[0], F->Normal.vx[1], F->Normal.vx[2]);
                                            Gl.glVertex3d(F->ppNode[0]->P.x[0], F->ppNode[0]->P.x[1], F->ppNode[0]->P.x[2]);
                                            Gl.glVertex3d(F->ppNode[1]->P.x[0], F->ppNode[1]->P.x[1], F->ppNode[1]->P.x[2]);
                                            Gl.glVertex3d(F->ppNode[2]->P.x[0], F->ppNode[2]->P.x[1], F->ppNode[2]->P.x[2]);
                                            Gl.glVertex3d(F->ppNode[3]->P.x[0], F->ppNode[3]->P.x[1], F->ppNode[3]->P.x[2]);
                                            Gl.glEnd();
                                            break;
                                        default:
                                            Gl.glBegin(Gl.GL_POLYGON);
                                            Gl.glNormal3d(F->Normal.vx[0], F->Normal.vx[1], F->Normal.vx[2]);
                                            for (uint j = 0; j < F->nNode; j++)
                                            {
                                                Gl.glVertex3d(F->ppNode[j]->P.x[0], F->ppNode[j]->P.x[1], F->ppNode[j]->P.x[2]);
                                            }
                                            Gl.glEnd();
                                            break;
                                    }
                                }
                            }
                        }
                    }
                    Gl.glFinish();
                }
            }
    

    Und der Code zur Initialisierung der Modelview- und Projectionmatrix:

    public static void InitProjectionMatrix()
            {
                int hoehe = MainControls.OGL.Size.Height;
                int breite = MainControls.OGL.Size.Width;
                double aspect = 0.0;
                if (hoehe == 0){hoehe = 1;}
                Gl.glViewport(0, 0, breite, hoehe);
                Gl.glMatrixMode(Gl.GL_PROJECTION);
                Gl.glLoadIdentity();
                aspect = (double)breite / (double)hoehe;
                Gl.glOrtho(-5, 5, -5, 5, 1, 10);
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
            }
    
            public static void InitModelviewMatrix()
            {
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
                Gl.glLoadIdentity();
                Gl.glTranslated(0.0, 0.0, -9.0);
                Gl.glRotated(-45.0, 1.0, 0.0, 0.0);
            }
    

    Mir ist durchaus bewusst, dass der Renderer alles andere als optimal ist, vor allem, da immer das gleiche Objekt gezeigt wird. Aber bevor ich das Problem mit dem Z Buffer hier nicht gelöst habe, möchte ich mich nicht an Vertex Buffer Objects ranwagen.

    Ich bin für jeden Tipp sehr dankbar.

    Grüße,
    CJens



  • Was passiert, wenn du bei GlORtho eine andere Z-Far-Ebene angibst? Kommt der Fehler dann schneller?

    Für mich sieht es in der Tat wie ein Clipping-Problem aus.

    Löscht ClearScreen auch wirklich den Z-Puffer?



  • Hallo.

    Ja, ClearScreen löscht auch den Tiefenbuffer. Anbei die Funktion:

    public static void ClearScreen()
            {
                Gl.glClearColor((float)(GlobalVariables.MainGraphicSettings.Background_Color.R / 256.0), (float)(GlobalVariables.MainGraphicSettings.Background_Color.G / 256.0), (float)(GlobalVariables.MainGraphicSettings.Background_Color.B / 256.0), (float)1.0);
                Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
            }
    

    Ich glaube aber nicht mehr, dass es an dem Tiefenbuffer liegt, denn ich habe die Zoom-Funktion jetzt über glOrtho realisiert - da wird also nicht mehr skaliert.

    public static void Scaling(MouseEventArgs e)
            {
                int[] XStart = new int[2] { e.X, e.Y };
                int[] fViewPort = new int[4];
    
                double[] MouseWorld = new double[3] { .0, .0, .0 };
                double f = Math.Exp(0.2 * (double)e.Delta / 120.0);
                ZoomFactor *= f;
    
                UpdateOGLMatrix(); 
                WorldCoord(XStart, ref MouseWorld, MyViewPort, MyModelView, MyProject);
    
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
                Gl.glTranslated(MouseWorld[0], MouseWorld[1], MouseWorld[2]);
                Gl.glMatrixMode(Gl.GL_PROJECTION);
                Gl.glLoadIdentity();
                Gl.glOrtho(-1 * ZoomFactor, 1 * ZoomFactor, -1 * ZoomFactor, 1 * ZoomFactor, 1, 10);
                MainControls.MainStatusText.Text = "ZF: " + ZoomFactor + "glOrtho(" + -5 * ZoomFactor + ", " + 5 * ZoomFactor + ", " + 5 * ZoomFactor + ", " + -5 * ZoomFactor + ", 1, 10)";
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
                Gl.glTranslated(-MouseWorld[0], -MouseWorld[1], -MouseWorld[2]);
            }
    

    Mir fiel auch auf, dass der Fehler nach dem Verschieben eher auftritt.



  • Ich kann jetzt nicht direkt den Fehler finden aber ich habe das so verstanden, dass du eine Arcball-Rotation machen willst. Stimmt das oder stehe ich auf dem Schlauch? Wenn ja, dann versuch dir das mal anzusehen:

    http://nehe.gamedev.net/tutorial/arcball_rotation/19003/



  • Hallo.

    Das ist richtig. Ich werde mir das Beispiel auch mal ansehen - das zehnte Beispiel dann :-/.

    Ich habe jetzt mein Beispiel sehr stark vereinfacht, so dass es sich jeder kopieren könnte. Ich arbeite ja nicht mit nativem OGL sondern mit der tao-framework in C#. Ausgeführt sieht das dann so aus:
    https://youtu.be/tXyNaJQ_A3U

    Das ist sehr interessant, denn es wird folgendes deutlich:
    Die Rotation funktioniert.
    Das Zoomen funktioniert.
    Erst nachdem ich einmal verschoben habe, wird der Würfel nicht mehr korrekt dargestellt.

    Anbei der komplette Code mit allem Schnick-Schnack. Hier erstmal die Klasse der Userform Form1:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using Tao.OpenGl;
    using Tao.Platform.Windows;
    
    namespace OwnExample
    {
        public unsafe partial class Form1 : Form
        {
            private static float _dragPosX = (float).0, _dragPosY = (float).0, _dragPosZ = (float).0;
    
            public Form1()
            {
                InitializeComponent();
                this.simpleOpenGlControl1.InitializeContexts();
                C_OGL.AssociateOGL(this.simpleOpenGlControl1);
                C_OGL.InitializeOGL();
                C_OGL.ReShapeOGL();
                C_OGL.Render();
            }
    
            private void simpleOpenGlControl1_SizeChanged(object sender, EventArgs e)
            {
                C_OGL.ReShapeOGL();
                C_OGL.Render();
            }
    
            private void simpleOpenGlControl1_MouseWheel(object sender, MouseEventArgs e)
            {
                double s = System.Math.Exp((double)e.Delta * 0.001);
                double px, py, pz;
    
                C_OGL.UpdateOGLMatrix();
                C_OGL.pos(&px, &py, &pz, e.X, e.Y, C_OGL.ViewPort);
                Gl.glScalef((float)s, (float)s, (float)s);
    
                C_OGL.Render();
                C_OGL.OGL.Refresh();
            }
    /*
    ZOOM
    */
            private void simpleOpenGlControl1_MouseMove(object sender, MouseEventArgs e)
            {
                double px, py, pz;
                int x = e.X, y = e.Y;
                int dx = x - C_OGL.MouseX;
                int dy = y - C_OGL.MouseY;
    
                C_OGL.UpdateOGLMatrix();
                C_OGL.pos(&px, &py, &pz, x, y, C_OGL.ViewPort);
    
                toolStripStatusLabel1.Text = "Cursor-position (x/y/z): " + px.ToString() + " / " + py.ToString() + " / " + pz.ToString();
    
                if (e.Button == System.Windows.Forms.MouseButtons.Right) 
                {
    /*
    TRANSLATION
    */
                    Gl.glMatrixMode(Gl.GL_MODELVIEW);
                    Gl.glLoadIdentity();
                    Gl.glTranslatef((float)px - _dragPosX, (float)py - _dragPosY, (float)pz - _dragPosZ);
                    Gl.glMultMatrixd(C_OGL.ModelViewMatrix);
    
                    _dragPosX = (float)px;
                    _dragPosY = (float)py;
                    _dragPosZ = (float)pz;
                }
                else if (e.Button == System.Windows.Forms.MouseButtons.Left){ 
    /*
    ROTATION
    */
                    double ax, ay, az;
                    double bx, by, bz;
                    double angle;
                    double[] _MatrixInverse = new double[16];
                    C_OGL.InvertMatrixd(C_OGL.ModelViewMatrix, _MatrixInverse);
    
                    ax = dy;
                    ay = dx;
                    az = 0.0;
                    angle = C_OGL.vlen(ax, ay, az) / (double)(C_OGL.ViewPort[2] + 1) * 180.0;
    
                    bx = _MatrixInverse[0] * ax + _MatrixInverse[4] * ay + _MatrixInverse[8] * az;
                    by = _MatrixInverse[1] * ax + _MatrixInverse[5] * ay + _MatrixInverse[9] * az;
                    bz = _MatrixInverse[2] * ax + _MatrixInverse[6] * ay + _MatrixInverse[10] * az;
    
                    Gl.glRotatef((float)angle, (float)bx, (float)by, (float)bz);
                }
    
                C_OGL.Render();
                C_OGL.OGL.Refresh();
                C_OGL.MouseX = x;
                C_OGL.MouseY = y;
            }
        }
    }
    

    Dann noch die Klasse C_OGL in welcher die Berechnungen, das Rendern etc. durchgeführt wird:

    namespace OwnExample
    {
        public static unsafe class C_OGL
        {
            public static int w = 0, h = 0;
            public static SimpleOpenGlControl OGL = null;
            private static double xMin = -.75, xMax = .75;
            private static double yMin = -.5, yMax = 1.2;
            private static double zMin = -1.0, zMax = 0.5;
    
            public static double OGLleft = .0, OGLright = .0, OGLtop = .0, OGLbottom = .0;
            public static double OGLzNear = -10.0, OGLzFar = 10.0;
    
            public static double[] ModelViewMatrix = new double[16];
            public static double[] ProjectionMatrix = new double[16];
            public static double[] InvModelViewMatrix = new double[16];
            public static int[] ViewPort = new int[4];
            public static int MouseX = 0, MouseY = 0;
            public static void AssociateOGL(SimpleOpenGlControl fOGL)
            {
                OGL = fOGL;
            }
    
            public static void ClearScreen()
            {
                Gl.glClearColor((float)1.0, (float)1.0, (float)1.0, (float)1.0);
                Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
            }
    
            public static void Render()
            {
                double[] ColRed = new double[4] { 1.0, 0.0, 0.0, 1.0 };
                double[] ColGreen = new double[4] { 0.0, 1.0, 0.0, 1.0 };
                double[] ColBlue = new double[4] { 0.0, 0.0, 1.0, 1.0 };
    
                ClearScreen();
    
    #region DrawCube
                Gl.glColor4dv(ColRed);
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMin, zMin);
                Gl.glVertex3d(xMin, yMin, zMax);
                Gl.glVertex3d(xMin, yMax, zMax);
                Gl.glVertex3d(xMin, yMax, zMin);
                Gl.glEnd();
    
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMax, yMin, zMin);
                Gl.glVertex3d(xMax, yMin, zMax);
                Gl.glVertex3d(xMax, yMax, zMax);
                Gl.glVertex3d(xMax, yMax, zMin);
                Gl.glEnd();
    
                Gl.glColor4dv(ColGreen);
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMax, zMin);
                Gl.glVertex3d(xMin, yMax, zMax);
                Gl.glVertex3d(xMax, yMax, zMax);
                Gl.glVertex3d(xMax, yMax, zMin);
                Gl.glEnd();
    
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMin, zMin);
                Gl.glVertex3d(xMin, yMin, zMax);
                Gl.glVertex3d(xMax, yMin, zMax);
                Gl.glVertex3d(xMax, yMin, zMin);
                Gl.glEnd();
    
                Gl.glColor4dv(ColBlue);
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMax, zMin);
                Gl.glVertex3d(xMax, yMax, zMin);
                Gl.glVertex3d(xMax, yMin, zMin);
                Gl.glVertex3d(xMin, yMin, zMin);
                Gl.glEnd();
    
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMax, zMax);
                Gl.glVertex3d(xMax, yMax, zMax);
                Gl.glVertex3d(xMax, yMin, zMax);
                Gl.glVertex3d(xMin, yMin, zMax);
                Gl.glEnd();
    #endregion DrawCube
    
                Gl.glFinish();
            }
    
            public static void UpdateOGLMatrix()
            {
                Gl.glGetIntegerv(Gl.GL_VIEWPORT, ViewPort);
                Gl.glGetDoublev(Gl.GL_MODELVIEW_MATRIX, ModelViewMatrix);
                Gl.glGetDoublev(Gl.GL_PROJECTION_MATRIX, ProjectionMatrix);
            }
    
            public static void InitializeOGL()
            {
                Gl.glEnable(Gl.GL_DOUBLEBUFFER);
                Gl.glEnable(Gl.GL_DEPTH_TEST);
            }
    
            public static void ReShapeOGL()
            {
                Gl.glViewport(0, 0, OGL.Size.Width, OGL.Size.Height);
    
                OGLtop = 1.0;
                OGLbottom = -1.0;
                OGLleft = -(double)OGL.Size.Width / (double)OGL.Size.Height;
                OGLright = -OGLleft;
    
                Gl.glMatrixMode(Gl.GL_PROJECTION);
                Gl.glLoadIdentity();
                Gl.glOrtho(OGLleft, OGLright, OGLbottom, OGLtop, OGLzNear, OGLzFar);
    
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
            }
    
            public static void pos(double *px,double *py,double *pz, int x, int y, int[] viewport)
            {
                *px = (double)(x-viewport[0])/(double)(viewport[2]);
                *py = (double)(y-viewport[1])/(double)(viewport[3]);
    
                *px = OGLleft + (*px)*(OGLright-OGLleft);
                *py = OGLtop  + (*py)*(OGLbottom-OGLtop);
                *pz = OGLzNear;
            }
    
            public static double vlen(double x, double y, double z) { return System.Math.Sqrt(x * x + y * y + z * z); }
    
            public static bool InvertMatrixd(double[] m, double[] invOut)
            {
                double[] inv = new double[16];
                double det;
                int i;
                inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15]
                + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
                inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15]
                - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
                inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15]
                + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
                inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14]
                - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
                inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15]
                - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
                inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15]
                + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
                inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15]
                - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
                inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14]
                + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
                inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15]
                + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
                inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15]
                - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
                inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15]
                + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
                inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14]
                - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
                inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11]
                - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
                inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11]
                + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
                inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11]
                - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
                inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10]
                + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
                det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
                if (det == 0)
                    return false;
                det = 1.0 / det;
                for (i = 0; i < 16; i++)
                    invOut[i] = inv[i] * det;
                return true;
            }
        }
    }
    


  • Also, ich habe die Lösung. Der Fehler liegt in Zeile 69 bei dem Code der Userform, welchen ich in meinem letzten Post beschrieben habe. Hier darf NICHT in Z-Richtung transformiert werden.

    Also, falscher Code:

    Gl.glTranslatef((float)px - _dragPosX, (float)py - _dragPosY, (float)pz - _dragPosZ);
    

    ...und so ist es richtig:

    Gl.glTranslatef((float)px - _dragPosX, (float)py - _dragPosY, (float).0);
    

    Das Resultat sieht dann so aus:
    https://youtu.be/7KsHYcBXCIM

    Da solche eine Problemstellung scheinbar öfters auftaucht, hier nochmal der Code.

    Userform:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using Tao.OpenGl;
    using Tao.Platform.Windows;
    
    namespace OwnExample
    {
        public unsafe partial class Form1 : Form
        {
            private static float _dragPosX = (float).0, _dragPosY = (float).0, _dragPosZ = (float).0;
    
            public Form1()
            {
                InitializeComponent();
                this.simpleOpenGlControl1.InitializeContexts();
                C_OGL.AssociateOGL(this.simpleOpenGlControl1);
                C_OGL.InitializeOGL();
                C_OGL.ReShapeOGL();
                C_OGL.Render();
            }
    
            private void simpleOpenGlControl1_SizeChanged(object sender, EventArgs e)
            {
                C_OGL.ReShapeOGL();
                C_OGL.Render();
            }
    
            private void simpleOpenGlControl1_MouseWheel(object sender, MouseEventArgs e)
            {
                double s = System.Math.Exp((double)e.Delta * 0.001);
                double px, py, pz;
    
                C_OGL.UpdateOGLMatrix();
                C_OGL.pos(&px, &py, &pz, e.X, e.Y, C_OGL.ViewPort);
                Gl.glScalef((float)s, (float)s, (float)s);
    
                C_OGL.Render();
                C_OGL.OGL.Refresh();
            }
    
            private void simpleOpenGlControl1_MouseMove(object sender, MouseEventArgs e)
            {
                double px, py, pz;
                int x = e.X, y = e.Y;
                int dx = x - C_OGL.MouseX;
                int dy = y - C_OGL.MouseY;
    
                C_OGL.UpdateOGLMatrix();
                C_OGL.pos(&px, &py, &pz, x, y, C_OGL.ViewPort);
    
                toolStripStatusLabel1.Text = "Cursor-position (x/y/z): " + px.ToString() + " / " + py.ToString() + " / " + pz.ToString();
    
                if (e.Button == System.Windows.Forms.MouseButtons.Right)
                {
                    Gl.glMatrixMode(Gl.GL_MODELVIEW);
                    Gl.glLoadIdentity();
                    //Gl.glTranslatef((float)px - _dragPosX, (float)py - _dragPosY, (float)pz - _dragPosZ); Hier lag der Fehler!
                    Gl.glTranslatef((float)px - _dragPosX, (float)py - _dragPosY, (float).0);
                    Gl.glMultMatrixd(C_OGL.ModelViewMatrix);
                }
                else if (e.Button == System.Windows.Forms.MouseButtons.Left){
                    double ax, ay, az;
                    double bx, by, bz;
                    double angle;
                    double[] _MatrixInverse = new double[16];
                    C_OGL.InvertMatrixd(C_OGL.ModelViewMatrix, _MatrixInverse);
    
                    ax = dy;
                    ay = dx;
                    az = 0.0;
                    angle = C_OGL.vlen(ax, ay, az) / (double)(C_OGL.ViewPort[2] + 1) * 180.0;
    
                    bx = _MatrixInverse[0] * ax + _MatrixInverse[4] * ay + _MatrixInverse[8] * az;
                    by = _MatrixInverse[1] * ax + _MatrixInverse[5] * ay + _MatrixInverse[9] * az;
                    bz = _MatrixInverse[2] * ax + _MatrixInverse[6] * ay + _MatrixInverse[10] * az;
    
                    Gl.glRotatef((float)angle, (float)bx, (float)by, (float)bz);
                }
    
                _dragPosX = (float)px;
                _dragPosY = (float)py;
                _dragPosZ = (float)pz;
    
                C_OGL.Render();
                C_OGL.OGL.Refresh();
                C_OGL.MouseX = x;
                C_OGL.MouseY = y;
            }
        }
    }
    

    Klasse C_OLG:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Tao.OpenGl;
    using Tao.Platform.Windows;
    
    namespace OwnExample
    {
        public static unsafe class C_OGL
        {
            public static int w = 0, h = 0;
            public static SimpleOpenGlControl OGL = null;
            private static double xMin = -.75, xMax = .75;
            private static double yMin = -.5, yMax = 1.2;
            private static double zMin = -1.0, zMax = 0.5;
    
            public static double OGLleft = .0, OGLright = .0, OGLtop = .0, OGLbottom = .0;
            public static double OGLzNear = -10.0, OGLzFar = 10.0;
    
            public static double[] ModelViewMatrix = new double[16];
            public static double[] ProjectionMatrix = new double[16];
            public static double[] InvModelViewMatrix = new double[16];
            public static int[] ViewPort = new int[4];
            public static int MouseX = 0, MouseY = 0;
            public static void AssociateOGL(SimpleOpenGlControl fOGL)
            {
                OGL = fOGL;
            }
    
            public static void ClearScreen()
            {
                Gl.glClearColor((float)1.0, (float)1.0, (float)1.0, (float)1.0);
                Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
            }
    
            public static void Render()
            {
                double[] ColRed = new double[4] { 1.0, 0.0, 0.0, 1.0 };
                double[] ColGreen = new double[4] { 0.0, 1.0, 0.0, 1.0 };
                double[] ColBlue = new double[4] { 0.0, 0.0, 1.0, 1.0 };
    
                ClearScreen();
    
    #region DrawCube
                Gl.glColor4dv(ColRed);
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMin, zMin);
                Gl.glVertex3d(xMin, yMin, zMax);
                Gl.glVertex3d(xMin, yMax, zMax);
                Gl.glVertex3d(xMin, yMax, zMin);
                Gl.glEnd();
    
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMax, yMin, zMin);
                Gl.glVertex3d(xMax, yMin, zMax);
                Gl.glVertex3d(xMax, yMax, zMax);
                Gl.glVertex3d(xMax, yMax, zMin);
                Gl.glEnd();
    
                Gl.glColor4dv(ColGreen);
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMax, zMin);
                Gl.glVertex3d(xMin, yMax, zMax);
                Gl.glVertex3d(xMax, yMax, zMax);
                Gl.glVertex3d(xMax, yMax, zMin);
                Gl.glEnd();
    
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMin, zMin);
                Gl.glVertex3d(xMin, yMin, zMax);
                Gl.glVertex3d(xMax, yMin, zMax);
                Gl.glVertex3d(xMax, yMin, zMin);
                Gl.glEnd();
    
                Gl.glColor4dv(ColBlue);
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMax, zMin);
                Gl.glVertex3d(xMax, yMax, zMin);
                Gl.glVertex3d(xMax, yMin, zMin);
                Gl.glVertex3d(xMin, yMin, zMin);
                Gl.glEnd();
    
                Gl.glBegin(Gl.GL_QUADS);
                Gl.glVertex3d(xMin, yMax, zMax);
                Gl.glVertex3d(xMax, yMax, zMax);
                Gl.glVertex3d(xMax, yMin, zMax);
                Gl.glVertex3d(xMin, yMin, zMax);
                Gl.glEnd();
    #endregion DrawCube
    
                Gl.glFinish();
            }
    
            public static void UpdateOGLMatrix()
            {
                Gl.glGetIntegerv(Gl.GL_VIEWPORT, ViewPort);
                Gl.glGetDoublev(Gl.GL_MODELVIEW_MATRIX, ModelViewMatrix);
                Gl.glGetDoublev(Gl.GL_PROJECTION_MATRIX, ProjectionMatrix);
            }
    
            public static void InitializeOGL()
            {
                Gl.glEnable(Gl.GL_DOUBLEBUFFER);
                Gl.glEnable(Gl.GL_DEPTH_TEST);
            }
    
            public static void ReShapeOGL()
            {
                Gl.glViewport(0, 0, OGL.Size.Width, OGL.Size.Height);
    
                OGLtop = 1.0;
                OGLbottom = -1.0;
                OGLleft = -(double)OGL.Size.Width / (double)OGL.Size.Height;
                OGLright = -OGLleft;
    
                Gl.glMatrixMode(Gl.GL_PROJECTION);
                Gl.glLoadIdentity();
                Gl.glOrtho(OGLleft, OGLright, OGLbottom, OGLtop, OGLzNear, OGLzFar);
    
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
            }
    
            public static void pos(double *px,double *py,double *pz, int x, int y, int[] viewport)
            {
                *px = (double)(x-viewport[0])/(double)(viewport[2]);
                *py = (double)(y-viewport[1])/(double)(viewport[3]);
    
                *px = OGLleft + (*px)*(OGLright-OGLleft);
                *py = OGLtop  + (*py)*(OGLbottom-OGLtop);
                *pz = OGLzNear;
            }
    
            public static double vlen(double x, double y, double z) { return System.Math.Sqrt(x * x + y * y + z * z); }
    
            public static bool InvertMatrixd(double[] m, double[] invOut)
            {
                double[] inv = new double[16];
                double det;
                int i;
                inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15]
                + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
                inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15]
                - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
                inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15]
                + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
                inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14]
                - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
                inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15]
                - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
                inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15]
                + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
                inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15]
                - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
                inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14]
                + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
                inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15]
                + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
                inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15]
                - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
                inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15]
                + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
                inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14]
                - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
                inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11]
                - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
                inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11]
                + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
                inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11]
                - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
                inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10]
                + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
                det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
                if (det == 0)
                    return false;
                det = 1.0 / det;
                for (i = 0; i < 16; i++)
                    invOut[i] = inv[i] * det;
                return true;
            }
        }
    }
    

    Und wer das einfach kopieren will: Ihr müsst natürlich noch einen Verweis auf Tao.OpenGl und Tao.Platform.Window erstellen.


Anmelden zum Antworten