[SlimDX] Verzerrung bei Rückprojektion


#1
Hallo zusammen

Ich habe momentan ein merkwürdiges Problem was die Rückprojektion (Vector3.Unproject) der Mauskoordinaten in die Objektkoordinaten anbelangt.

Grundsätzlich habe ich dies schon diverse Male implementiert und auch nie Probleme damit gehabt, allerdings musste ich jetzt feststellen, dass etwas nicht ganz so läuft wie ich das gerne habe.

Folgender Code kümmert sich darum:
C#:
        public void UpdateMouseTerrainPos()
        {
            System.Drawing.Point pt = System.Windows.Forms.Cursor.Position;
            pt = mRenderWindow.PointToClient(pt);

            var ptNear = Vector3.Unproject(new Vector3(pt.X, pt.Y, 0), Device.Viewport.X, Device.Viewport.Y,
                Device.Viewport.Width, Device.Viewport.Height, Device.Viewport.MinZ, Device.Viewport.MaxZ,
                Device.GetTransform(TransformState.View) * Device.GetTransform(TransformState.Projection));

            var ptFar = Vector3.Unproject(new Vector3(pt.X, pt.Y, 1), Device.Viewport.X, Device.Viewport.Y,
                Device.Viewport.Width, Device.Viewport.Height, Device.Viewport.MinZ, Device.Viewport.MaxZ,
                Device.GetTransform(TransformState.View) * Device.GetTransform(TransformState.Projection));

            Ray ray = new Ray(ptNear, Vector3.Normalize((ptFar - ptNear)));
            float distance = 0;
            bool hit = ADT.ADTManager.Intersect(ray, ref distance);
            ShaderCollection.TerrainShader.SetValue("DrawMouse", hit);
            if (hit)
            {
                ShaderCollection.TerrainShader.SetValue("MousePosition", ray.Position + distance * ray.Direction);
            }
        }
Mir ist bewusst, dass der letzte Parameter eigentlich world * view * proj wäre, allerdings ist bei mir world immer die Identitätsmatrix, daher lasse ich diese gleich weg.

Interessant ist nun das Verhalten, das ich in der Applikation feststelle:
1. Die Position der Maus ist immer leicht nach rechts und nach oben verschoben, das hängt allerdings ganz vom Winkel ab in dem ich auf das Terrain schaue. Trifft der "Strahl" der Maus praktisch senkrecht auf das Terrain auf passt es ziemlich gut, trifft er eher flach auf ist die Verschiebung grösser.

2. Bewege ich die Maus hoch und runter geht der Kreis flüssig mit, verschiebt sich also mit dem Mauszeiger. Bewege ich die Maus links und rechts ist es jedoch komplett anders. Der Kreis bleibt etwa 10 Pixel lang am gleichen Ort und hüpft dann an den neuen Ort. Dieses Verhalten ist mir absolut unerklärlich, denn ich konnte feststellen, dass die Position des Mauszeigers korrekt ist und auch richtig sich ändert, aber bei Unproject nur alle 10 Pixel ein neuer Wert produziert wird.

Hat jemand von euch eine Ahnung, woran das liegen könnte?

Gruss
Cromon
 
#2
Ich habe nun einiges nachgeforscht und auf folgendes Update gekommen:
Punkt 1 hat sich erledigt, er ist nämlich auf Punkt 2 zurückzuführen und es stimmt nicht immer überein weil das hin und her hüpft.

Punkt 2:
Aus irgendeinem Grund macht die Engine hier etwas sehr komisches und inkonsistentes mit meinen floats. Folgeder Ausschnitt:
C#:
            var mat = invProj * invView;
            float v = nearPos.X * mat.M12 + nearPos.Y * mat.M22 + nearPos.Z * mat.M32 + mat.M42;
            float v2 = nearPos.X * mat.M11 + nearPos.Y * mat.M21 + nearPos.Z * mat.M31 + mat.M41;
            float v3 = nearPos.X * mat.M13 + nearPos.Y * mat.M23 + nearPos.Z * mat.M33 + mat.M43;
            Console.WriteLine(v.ToString("0.0000") + "/" + v2.ToString("0.0000") + "/" + v3.ToString("0.0000"));
Interessant ist nun folgende Tatsache:
v und v2 werden auf 1 Nachkommastelle gerundet dargestellt wenn ich die Maus bewege (und offensichtlich auch für die weiteren Rechnungen so behandelt) v3 jedoch ist auf die 4 Stellen gerundet. Das deckt sich auch genau mit dem angezeigten Verhalten, denn v ist verantwortlich für die horizontale Bewegung, v3 für die vertikale.

Wie um alles in der Welt kann denn sowas passieren? Denn zu allem Unglück zeigt mir der Debugger für v die ungerundeten Werte an (bsp war folgendermassen: Debugger: 13.672, Ausgabe: 13.7, weitere Berechnungen auch alle mit 13.7).

/Edit:
Ich habe nun testweise folgendes gemacht:
C#:
            double v = nearPos.X * mat.M12 + nearPos.Y * mat.M22 + nearPos.Z * mat.M32 + mat.M42;
            double v2 = nearPos.X * mat.M11 + nearPos.Y * mat.M21 + nearPos.Z * mat.M31 + mat.M41;
            double v3 = nearPos.X * mat.M13 + nearPos.Y * mat.M23 + nearPos.Z * mat.M33 + mat.M43;
            double w = 1.0 / ((((nearPos.X * mat.M14) + (nearPos.Y * mat.M24)) + (nearPos.Z * mat.M34)) + mat.M44);
            v *= w;
            v2 *= w;
            v3 *= w;
Mit anderen Worten: Anstatt float double verwendet. Dann sind v, v2 und v3 akkurat (wir reden hier nur von 4 Nachkommastellen!!). Sobald ich jedoch v in ein float caste fällt sämtliche Genauigkeit weg und es wird wieder absolut unlogisch gerundet. Das ganze gilt NICHT für v3, da wird weiterhin genau genug gerechnet, was jedoch auffällt ist, dass es insgesamt genau immer 7 Stellen sind, die genau berechnet werden.
 
Zuletzt bearbeitet: