2016-11-12 5 views
2

Ich schreibe einen Raytracer in Java, und ich war in der Lage, die Verfolgung von Kugeln zu verfolgen, aber ich glaube, ich habe etwas falsch damit, wie ich Dreiecke zeichne.Raytracing-Dreiecke

Hier ist der grundlegende Algorithmus, wie ich es verstehe:

  1. zuerst fest, ob der Strahl auch die schneidet Ebene, dass das Dreieck ist.
  2. Alle Punkte so einschneiden, dass sie sich in der gleichen Ebene wie das Dreieck befinden (als Beispiel für die Ebene xy).
  3. Bestimmen Sie, ob der potenzielle Schnittpunkt innerhalb oder außerhalb des Dreiecks liegt, basierend auf der Anzahl der Polygonkanten, die Sie kreuzen, wenn Sie einen Strahl in einer beliebigen Richtung entlang der neuen Ebene senden.

Nun, hier ist meine Implementierung dass (insbesondere der erste Punkt):

public Vector getIntersectionVector(Ray ray) 
{ 
    Vector planeIntersectionVector = getPlaneIntersectionVector(ray, getPlaneNormal()); 
    if (planeIntersectionVector != null) 
    { 
     if (isIntersectionVectorInsideTriangle(planeIntersectionVector)) 
     { 
      return planeIntersectionVector; 
     } 
     else 
     { 
      return null; 
     } 
    } 
    else 
    { 
     return null; 
    } 
} 

Wo getPlaceIntersectionVector() ist:

private Vector getPlaneIntersectionVector(Ray ray, Vector planeNormal) 
{ 
    double vd = planeNormal.dotProduct(ray.getDirection()); 
    //(p_n \dot r_d) == 0, parallel. (p_n \dot r_d) > 0 Plane normal pointing away from ray. 
    if (vd >= 0) 
    { 
     return null; 
    } 
    double distance = planeNormal.distance(0d, 0d, 0d); 
    double vo = -(planeNormal.dotProduct(ray.getOrigin()) + distance); 
    double intersectionDistance = vo/vd; 

    //intersectionDistance <= 0 means the "intersection" is behind the ray, so not a real intersection 
    return (intersectionDistance <= 0) ? null : ray.getLocation(intersectionDistance); 
} 

die im Grunde diese nachzuahmen versucht:
Plane Intersection

Und das:
Ray intersection

Wo t der Abstand entlang des Strahls ist, dass der Punkt-Hits, r o der Ursprung des Strahls ist, r d ist die Richtung des Strahls, p n zur Ebene verweist Normale des Dreiecks/Ebene, und d ist der Abstand von der Ebene, die das Dreieck auf dem Ursprung ist (0,0,0)

Mache ich das falsch? Wenn ich den Strahl vom ersten Pixel im Bild (0,0) aussende, sehe ich, dass die intersectionDistance (oder t) fast 1100 ist, was mir intuitiv intuitiv falsch erscheint. Ich würde denken, dass der Schnittpunkt viel näher wäre.

Hier sind die relevanten Daten: Ray Herkunft (0,0,1), Ray Direction ist ungefähr (0.000917, -0.4689, -0.8833).
Dreieck hat Ecken wie (-0.2, 0.1, 0.1), (-0.2, -0.5, 0.2), (-0.2, 0.1, -0.3), die das Flugzeug normal (-1, 0, 0) macht.
Nach meinem Code, der Ray schneidet das Flugzeug 1090 Entfernung entfernt, die wie ich schon erwähnt, scheint mir falsch. Die Szene ist in jeder Richtung nur -1,0 bis 1,0, was bedeutet, dass die Kreuzung sehr weit entfernt ist.
Mache ich die Flugzeugkreuzung falsch?

Bitte lassen Sie mich wissen, wo Punkte zu klären, und wenn Sie weitere Informationen benötigen.

Antwort

1

Das Problem ist, diese Zeile:

double distance = planeNormal.distance(0d, 0d, 0d); 

Eine Ebene, die von einem normalen und einem Abstand von der Ebene zu dem Ursprung definiert ist.Der Abstand eines Vektors vom Ursprung ist die Länge eines Vektors, also berechnen Sie dort nur die Länge der Ebenennormalen (die immer 1,0 ist, wenn sie normalisiert wurde).

Die Entfernung der Ebene vom Ursprung ist eine zusätzliche Information, die in Ihre Funktion eingegeben werden muss, Sie können sie nicht einfach aus der Norm berechnen, weil sie unabhängig davon ist (Sie können viele Ebenen haben) mit Normalen, die in der gleichen Richtung in unterschiedlichen Entfernungen vom Ursprung zeigen).

So Ihre Funktion etwas wie folgt definieren:

private Vector getPlaneIntersectionVector(Ray ray, Vector planeNormal, double planeDistance) 

und es so etwas nennen:

Vector planeIntersectionVector = getPlaneIntersectionVector(ray, getPlaneNormal(), getPlaneDistance()); 

Dann können Sie vo wie folgt berechnen:

double vo = -(planeNormal.dotProduct(ray.getOrigin()) + planeDistance); 
+0

Angenommen, ich habe die Ebene von der Normalen des Dreiecks definiert. Wie würde ich in diesem Fall die Entfernung vom Flugzeug zum Ursprung bekommen? Von [dieser Antwort] (http://math.stackexchange.com/a/651535/375627) dachte ich, dass es nur das Punktprodukt zwischen der Normalen und einem Vektor in der Ebene ist (in diesem Fall einer der Eckpunkte)), aber das scheint falsch zu sein, denn jetzt ist die Kreuzung etwa 218. –

+0

"Ich dachte, dass es nur das Skalarprodukt zwischen der Normalen und einem Vektor in der Ebene war" - das sollte stimmen. Überprüfen Sie, ob der normale Vektor Ihres Flugzeugs normalisiert ist – samgak

+0

Sind Sie wirklich sicher, dass das Ergebnis falsch ist? Der Schnittpunktabstand ist * in Richtung der Strahlrichtung *, nicht der Abstand des nächsten Punktes in der Ebene vom Strahlenursprung. Da dein Strahl fast senkrecht zur Normalen der Ebene ist (er hat nur einen Wert von 0,000917 in Richtung der Flächennormalen), musst du relativ weit in diese Richtung fahren, bevor du dich überschneidest. – samgak

1

Etwas anders Ansatz:

Lassen Sie sich Dreieckvertices sind V0, V1, V2
Kantenvektoren

A = V1-V0 
B = V2 - V0 

Ray parametrische Gleichung hat (wie Sie geschrieben)

P = R0 + t * Rd 

Von der anderen Seite, hat Schnittpunkt parametrischen Koordinaten u, v in dem Dreiecksebene

P = V0 + u * A + v * B 

So können Sie System von drei linearen schreiben Gleichung für x, y, z Koordinaten und lösen Sie es für t, u, v. Wenn determinant ius ungleich Null ist (Strahl ist nicht parallel zur Ebene) und t >=0 und u, v, u+v im Bereich 0..1 liegen, dann ist P innerhalb eines Dreiecks.

R0.X + t * Rd.X = V0.X + u * A.X + v * B.X 
R0.Y + t * Rd.Y = V0.Y + u * A.Y + v * B.Y 
R0.Z + t * Rd.Z = V0.Z + u * A.Z + v * B.Z