Ich versuch gerade, nen kleinen raytracer zu schreiben. Wollte grad Dreiecke implementieren, funktioniet aber nicht ganz so, wie ich mir das vorstell.
Im Konstruktor berechne ich eine Matrix, die das Dreieck auf das Dreieck A = (-1, 0, 0) B = (1, 0, 0) C = (0, 0, 1) abbildet. Da wird vermutlich der Fehler liegen, ich find ihn bloß nicht. Bei der Schnittpunkt berechnung multiplizier ich den Strahl mit der Matrix (origin mit der homogenen, direction mit der affinen). Damit muss ich nur noch prüfen, ob der Schnittpunkt (mit der Ebene, auf der das Dreieck liegt) im Dreieck liegt, was recht einfach sein sollte, weils nur ein ganz bestimmtes Dreieck ist (das ich mir extra so ausgesucht hab) Den Rest machen die Matrizen... oder jedenfalls hab ich mir das so vorgestellt.
Nur: die Translation wird bei Origin großzügig ignoriert. Da Origin normalerweise im Punkt (0, 0, 0) lieg, liegts auch nach der Transformation noch in diesem Punkt. Hab mir zuerst gedacht, Vector3d.Transform macht halt keine Translation, und deswegen Vector4d.Transform benutzt, und die W Koordinate auf 1.0 gesetzt. Ich kann aber nach wie vor nix erkennen. Und das Problem mit der Translation bleibt auch.
Code:
public class Triangle : Intersectable { public Vertex A; public Vertex B; public Vertex C; public Matrix4d Transformations; public Matrix4d Affine;
public override double Intersect(Ray ray) { ray.Origin = Vector4d.Transform(new Vector4d(ray.Origin, 1.0d), Transformations).Xyz; //Translation wird ignoriert!?! ray.Direction = Vector3d.Transform(ray.Direction, Affine); //Skalierung wird berücksichtigt, daher ist Rückskalierung nicht nötig if (ray.Direction.Y == 0.0d) { return -1.0d; } double distance = -ray.Origin.Y / ray.Direction.Y; //liegt auf XZ Ebene Vector3d Pos = ray.Origin + ray.Direction * distance; double absPosX = Pos.X < 0.0d ? -Pos.X : Pos.X; if (absPosX + Pos.Z > 1.0d || Pos.Z < 0.0d) { return -1.0d; //nicht getroffen } return distance; }
public override Vertex Evaluate(Vector3d position, Ray ray) { Vector3d pos = Vector3d.Transform(position, Transformations); double ab = (pos.X + 1.0d) * 0.5d; double aPart = ab - pos.Z * 0.5; double bPart = (1.0d - ab) - pos.Z * 0.5d; float a = (float)aPart; float b = (float)bPart; float c = (float)pos.Z; return Vertex.Create(position, A.Normal * aPart + B.Normal * bPart + C.Normal * pos.Z, A.Diffuse * a + B.Diffuse * b + C.Diffuse * c, A.Specular * a + B.Specular * b + C.Specular * c); }
public Triangle(Vertex _A, Vertex _B, Vertex _C) { A = _A; B = _B; C = _C; Vector3d AB = (_B.Pos - _A.Pos) * 0.5d; Vector3d Pos = (_A.Pos + _B.Pos) * 0.5d; Vector3d Height = _C.Pos - Pos; Vector3d N = Vector3d.Normalize(Vector3d.Cross(AB, Height)); Transformations = new Matrix4d(AB.X, AB.Y, AB.Z, Pos.X, N.X, N.Y, N.Z, Pos.Y, Height.X, Height.Y, Height.Z, Pos.Z, 0.0d, 0.0d, 0.0d, 1.0d); Affine = Transformations; Affine.Row0.W = 0.0d; Affine.Row1.W = 0.0d; Affine.Row2.W = 0.0d; Affine.Row3.W = 1.0d; Affine.Row3.Z = 0.0d; Affine.Row3.Y = 0.0d; Affine.Row3.X = 0.0d; Transformations = Matrix4d.Invert(Transformations); Affine = Matrix4d.Invert(Affine); //Transformationen berechnen, die das Dreieck A = (-1, 0, 0) B = (1, 0, 0) C = (0, 0, 1) auf das Angegebene Dreieck abbilden, und diese dann umkehren. } }
Um eine Richtung zu transformieren brauchst du die 3x3 große NormalMatrix. Dabei handelt es sich um den Rotationsanteil der Transformationsmatrix, also den 3x3-Teil links oben. Die NormalMatrix muss zudem invertiert und transponiert werden.
Sofern du ausschließlich Rotation und Translation in deiner Transformationsmatrix hast ist die NormalMatrix orthonormal, d.h. die Operationen "invertieren" und "transponieren" heben sich gegenseitig auf. Aus deinem Kommentar "Skalierung wird berücksichtigt" schließe ich aber, dass du eine Skalierung in der Matrix hast, weshalb die Matrix nicht mehr orthonormal ist.
Des weiteren ist die Transformation mit der NormalMatrix nicht Längen erhaltend, d.h. eine Richtung muss ggf. erneut normalisiert werden.
Um eine Richtung zu transformieren brauchst du die 3x3 große NormalMatrix.
Nur Matrix3d gibts nicht ==> ich benutz halt Matrix4d und setz den Rest auf Identity
Zitat:
Des weiteren ist die Transformation mit der NormalMatrix nicht Längen erhaltend, d.h. eine Richtung muss ggf. erneut normalisiert werden.
Also, das war eigentlich Absicht, dass die Richting nicht normalisiert wird. Der Sinn davon ist, dass distance richtig bleibt, trotz Transformation. Und die (hier vereinfachte) Schnittpunktberechnung zwischen Gerade und Ebene funktioniert unabhängig von der Länge des Richtungsvektors. Sollte eigentlich.
Zitat:
Die NormalMatrix muss zudem invertiert und transponiert werden.
Habs jetzt nach dem Invertieren noch transponiert, sieht anders aus, aber nicht so, wies aussehen soll. Außerdem ist da (zumindest unter anderem) bezüglich Origin irgendwo ein Fehler, und Origin sieht diese Matrix nie.
Der Sinn davon ist, dass distance richtig bleibt, trotz Transformation.
Die Länge des Vektors ändert sich. D.h. wenn du die Länge behalten willst musst du dir vorher die Länge merken und den Vektor nach der Transformation wieder auf die richtige Länge setzen.
Wenn es hier um eine Kante/Strecke geht, also ein Strahl mit Anfang und Ende ist es ggf. einfacher beide Endpunkte zu transformieren. Dann kannst du dir den ganzen Kram mit der NormalMatrix sparen.
Zitat:
Nur Matrix3d gibts nicht ==> ich benutz halt Matrix4d und setz den Rest auf Identity
Klar, geht auch.
Zitat:
Habs jetzt nach dem Invertieren noch transponiert, sieht anders aus, aber nicht so, wies aussehen soll.
Da du die Transformationsmatrix invertierst musst du die Normalmatrix auch von der invertierten Transformationsmatrix berechnen. Spricht zweimal invertieren (=keinmal) und einmal transponieren.
Die Länge des Vektors ändert sich. D.h. wenn du die Länge behalten willst musst du dir vorher die Länge merken und den Vektor nach der Transformation wieder auf die richtige Länge setzen.
Schnittpunkt = Origin + Direction * Distance. Normalerweise hat Direction Länge 1, daher die Bezeichnung Distance. Nur wegen den den Transformationen hats halt nicht mehr die Länge 1. Aber deswegen soll idealerweise trotzdem die richtige Distance berechnet werden, deswegen nicht Normalize.
Mitglieder in diesem Forum: 0 Mitglieder und 8 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.