Raytraceing Refraktion Problem

F.b

Lieutenant
Registriert
Feb. 2008
Beiträge
514
Hallo,
ich arbeite derzeit an einem Raytracer. Läuft auch ganz gut bis auf ein Problem bei der Refraktion, welches ich bisher nicht lösen konnte:
Die Refraktion sieht sehr "fleckig" aus, d.h. in den Kugeln, die man sieht, sind schwarze Punkte.
http://imageshack.us
Ich hoffe ihr habt eine Ahnung woran das liegen könnte. Die Refraktionsstrahlen werden nach dem Beispiel in diesem Tutorial berechnet.
 
Hm, vielleicht mehr Samples pro Pixel verwenden? Kenn mich leider kaum/gar nicht mit Raytracer-Programmierung aus...

Interessant wäre auch der Brechungsindex deiner 4. Kugel (die aus "Glas"), vielleicht ist da ein etwas unmöglicher Wert dabei? Auch wäre es interessant mit welcher Genauigkeit von Floats du deine Szene berechnest - vielleicht hilft double precision weiter?
 
das mit mehreren strahlen pro pixel wär ne möglichkeit, es sollte aber auch so funktionieren.
Der Brechungsindex liegt bei 1.6 und es wird schon alles mit double precision berechnet. daran liegts auch nicht
 
Kannst du uns den Abschnitt zeigen, wo er die Refraktion berechnet? Manchmal sieht man den Wald vor lauter Bäumen nicht. Da hilft es immer, wenn andere drüberschauen.
 
sorry, hab ich vergessen;)
Hier der Code:
Code:
public ColorRGB rek(Ray ray, Primitive pr, ColorRGB acc, Point3D inter, int count, double oldr) {
		if(count < 0)
			return acc;
		ColorRGB amb = new ColorRGB(pr.getMat().c.red*pr.getMat().amb*(1-(pr.getMat().refl+pr.getMat().refr)),
				pr.getMat().c.green*pr.getMat().amb*(1-(pr.getMat().refl+pr.getMat().refr)),
				pr.getMat().c.blue*pr.getMat().amb*(1-(pr.getMat().refl+pr.getMat().refr)));
		ColorRGB oc = new ColorRGB(pr.getMat().c.red*(1-(pr.getMat().refl+pr.getMat().refr)),
				pr.getMat().c.green*(1-(pr.getMat().refl+pr.getMat().refr)),
				pr.getMat().c.blue*(1-(pr.getMat().refl+pr.getMat().refr)));
		for(int i = 0; i < l.size(); i++) {
			if(pr.shadowed(inter, v, l.elementAt(i)) != true) {
				acc.add(pr.shade(oc, ray, inter, l.elementAt(i)));
			}
			else {
				acc.add(amb);
			}
		}
		Vector3D normale = new Vector3D(inter.x-pr.getPos().x,inter.y-pr.getPos().y,inter.z-pr.getPos().z);
		if(pr.getMat().refl > 0) {
			Vector3D toView = new Vector3D(ray.origin.x - inter.x,ray.origin.y - inter.y,ray.origin.z - inter.z);
			double winkel = toView.dotProduct(normale);
			Vector3D reflect = new Vector3D((-toView.x+2*normale.x*winkel-inter.x),
					(-toView.y+2*normale.y*winkel-inter.x),
					(-toView.z+2*normale.z*winkel-inter.x));
			Ray r2 = new Ray(inter,reflect);
			Primitive p2;
			Point3D in;
			Vector v1 = getNearestIntersection(r2);
			in = (Point3D) v1.elementAt(0);
			p2 = (Primitive) v1.elementAt(1);
			ColorRGB ne = new ColorRGB(0,0,0);
			if(p2 != null) {
				int co = count-1;
				ColorRGB next = rek(r2,p2,acc,in,co,oldr);
				ne = new ColorRGB(next.red*pr.getMat().refl,
						next.green*pr.getMat().refl,
						next.blue*pr.getMat().refl);
				acc.add(ne);
			}
		}
		if(pr.getMat().refr > 0) {
			double rindex = pr.getMat().brind;
			double n = oldr/rindex;
			if(inter.inside) {
				normale = new Vector3D(normale.x*-1,normale.y*-1,normale.z*-1);
			}
			double cos1 = -1*ray.direction.dotProduct(normale);
			double cos2 = 1.0 - n*n * (1.0 - cos1*cos1);
			if(cos2 > 0) {
				Vector3D t = new Vector3D(n*ray.direction.x + (n*cos1 - Math.sqrt(cos2))*normale.x,
						n*ray.direction.y + (n*cos1 - Math.sqrt(cos2))*normale.y,
						n*ray.direction.z + (n*cos1 - Math.sqrt(cos2))*normale.z);
				Ray r2 = new Ray(inter,t);
				Primitive p2;
				Point3D in;
				Vector v1 = getNearestIntersection(r2);
				in = (Point3D) v1.elementAt(0);
				p2 = (Primitive) v1.elementAt(1);
				ColorRGB ne = new ColorRGB(0,0,0);
				if(p2 != null) {
					int co = count-1;
					ColorRGB next = rek(r2,p2,acc,in,co,rindex);
					ne = new ColorRGB(next.red*pr.getMat().refr,
							next.green*pr.getMat().refr,
							next.blue*pr.getMat().refr);
					ColorRGB absorb = new ColorRGB(pr.getMat().c.red*0.15*-in.dist,
							pr.getMat().c.green*0.15*-in.dist,
							pr.getMat().c.blue*0.15*-in.dist);
					ColorRGB transp = new ColorRGB(Math.exp(absorb.red),
							Math.exp(absorb.green),
							Math.exp(absorb.blue));
					ne = new ColorRGB(ne.red*transp.red,
							ne.green*transp.red,
							ne.blue*transp.red);
					acc.add(ne);
				}
			}
		}
		return acc;
	}
 
pr.getMat().refr
Was sagt das aus? Ob das Licht gebrochen werden soll? werden soll?

Ziemlich viel Mathe hier. Hast du schon mal den Debug-Modus probiert und nachgerechnet, warum an einigen Stellen das Licht nicht gebrochen wird?
 
pr ist das Primitiv, also hier die Kugel, die im vorherigen Durchlauf getroffen wurde. getMat() gibt ein Material-Objekt des Primitivs zurück und in refr wird gespeichert, wieviel des Lichts gebrochen werden soll(0 bis 1).

EDIT: Der Debugger hat mir gesagt, dass ein paar Strahlen schon beim in-die-Kugel-gebrochen-werden die Kugel nicht treffen(warum auch immer). Einen Fehler in der Schnittpunktüberprüfung habe ich ausgeschlossen, da ich bereits 2 verschiedene Methoden dafür getestet habe, ohne Unterschiede.
 
Zuletzt bearbeitet:
Du musst weiter prüfen. Jeden kleinen Schritt, auch den kleinsten. Ich habe auch schon mal 8 Stunden nach einem Fehler gesucht, bis ich mitbekommen habe, dass eigentlich nur ein Zeichen gefehlt hat.
Der Debugger hat mir gesagt, dass ein paar Strahlen schon beim in-die-Kugel-gebrochen-werden die Kugel nicht treffen(warum auch immer).
Das ist doch schon mal ein Ansatzpunkt. Vermutlich ist die eigentlich Berechnung der Lichtbrechung i.O., aber die Kollisionsabfrage wohl nicht.
 
Verwendest du eine Beschleunigungsstruktur zum Finden der geschnittenen Primitive? Wenn ja, welche? Vermute mal auch, dass es mit der Schnittberechnung nicht so ganz funktioniert. Evtl. ein Rundungsfehler den man auf den ersten Blick nicht erkennt.

EDIT:
Verstehe einen Teil nicht so ganz:

Code:
		Vector3D reflect = new Vector3D((-toView.x+2*normale.x*winkel-inter.x),
					(-toView.y+2*normale.y*winkel-inter.x),
					(-toView.z+2*normale.z*winkel-inter.x));

toView = Richtungsvektor vom Strahlursprung zur Intersection (diesen Richtungsvektor hast du eigentlich schon im Strahl definiert, nur das dieser hier eine andere Länge hat, also warum nochmal berechnen?)
normale = Normalenvektor am Schnittpunkt
winkel = Winkel (Cosinus) zwischen Richtungsvektor toView und Normale am Schnittpunkt
inter = Intersection / Schnittpunkt des Strahls am Primitive
Soweit richtig?

Dann meine Frage: Für den Richtungsvektor des Reflektionsstrahls verwendest du in der Berechnung von x, y und z immer "inter.x". Ist das so richtig? Ich hätte jetzt eher folgendes erwartet:

Code:
		Vector3D reflect = new Vector3D((-toView.x+2*normale.x*winkel-[B]inter.x[/B]),
					(-toView.y+2*normale.y*winkel-[B]inter.y[/B]),
					(-toView.z+2*normale.z*winkel-[B]inter.z[/B]));

EDIT 2: Sehe gerade das es im Reflection Teil deines Codes passiert und somit auf dein Brechungsproblem wahrscheinlich keine Auswirkungen hat. BTW: Was für eine Sprache verwendest du? Würde mal auf Java tippen.
 
Zuletzt bearbeitet:
Der Code ist in der Tat sehr mathematisch. Vielleicht solltest du da mal ein paar Kommentare einfügen, sonst weisst du in paar Monaten nicht mehr was der Code genau tut.
 
Poste mal den Code für getNearestIntersection(Ray r) sowie die Deklaration von Ray und Vektor:
Code:
Vector v1 = getNearestIntersection(r2);
 
@ rossibaer: das sollte in der tat nicht so sein, danke für den tipp;) und ja, es ist java
toView is der gleiche Vektor wie ray.direction, nur von der Intersection zum Augpunkt. das ist nötig, weil es andernfalls zu berechnugsfehlern kommt

beschleunigunstechniken für die schnittpunktberechnung nutze ich nicht, ich dachte es sollten erstmal die grundlegenden sachen funktionieren. hier erstmal getNearestIntersection:
Code:
public Vector getNearestIntersection(Ray ray) {
		Point3D p = new Point3D(0,0,0,Double.POSITIVE_INFINITY,false);
		Primitive pr = null;
		Point3D inter = null;
		for(int i = 0; i < v.size(); i++) {
			inter = v.elementAt(i).checkCollision(ray);
			if(inter != null && inter.dist < p.dist) {
				p = inter;
				pr = v.elementAt(i);
			}
		}
		Vector v = new Vector();
		v.add(p);
		v.add(pr);
		return v;
	}

ich nutze hier nen Vector zum Rückgeben der Werte weil java leider keine referenzparameter unterstützt:(

Hier die methode checkCollision:
Code:
public Point3D checkCollision(Ray ray) {
    	Point3D p = null;
    	ray.direction.normalize();
    	double a = 0;
    	double b = 0;
    	Point3D v = new Point3D(ray.origin.x-pos.x,ray.origin.y-pos.y,ray.origin.z-pos.z);
    	b = -1 * ray.direction.dotProduct(v);
		a = (b*b) - v.dotProduct(v) + r2;
		
		boolean in = false;
		
		if(a > 0) {
			a = Math.sqrt(a);
			double i1 = b - a;
			double i2 = b + a;
			if(i2 > 0) {
				if(i1 < 0) {
					i1 = i2;
					in = true;
				}
			}
			if(i1 > 0) {
				p = new Point3D(ray.origin.x+i1*ray.direction.x,
						ray.origin.y+i1*ray.direction.y,
						ray.origin.z+i1*ray.direction.z,Math.sqrt(
								(i1*ray.direction.x*i1*ray.direction.x)+
								(i1*ray.direction.y*i1*ray.direction.y)+
								(i1*ray.direction.z*i1*ray.direction.z)),in);
			}
		}
       return p;
}
 
Zuletzt bearbeitet:
Hab den Code etwas optimiert und dachte ich hätte den Fehler schon ..

Naja, hier die optimierte Funktion:
Code:
public ColorRGB rek(Ray ray, Primitive pr, ColorRGB acc, Point3D inter, int count, double oldr) {
	if(count < 0)
		return acc;
	Material mat = pr.getMat();
	double refl = mat.refl;
	double refr = mat.refr;
	Color matc = mat.c;
	double reflfr = 1-refl+refr;
	double ambflfr = mat.amb*reflfr;
	ColorRGB camb = new ColorRGB(matc.red*ambflfr), matc.green*ambflfr), matc.blue*ambflfr);
	ColorRGB oc = new ColorRGB(matc.red*reflfr, matc.green*reflfr, matc.blue*reflfr);
	for(int i = 0; i < l.size(); i++) {
		if(pr.shadowed(inter, v, l.elementAt(i)) != true)
			acc.add(pr.shade(oc, ray, inter, l.elementAt(i)));
		else
			acc.add(camb);
	}
	Vector3D normale = new Vector3D(inter.x-pr.getPos().x,inter.y-pr.getPos().y,inter.z-pr.getPos().z);
	if(refl > 0) {
		Vector3D toView = new Vector3D(ray.origin.x - inter.x,ray.origin.y - inter.y,ray.origin.z - inter.z);
		double winkel = toView.dotProduct(normale);
		Vector3D reflect = new Vector3D((-toView.x+2*normale.x*winkel-inter.x),
				(-toView.y+2*normale.y*winkel-inter.y),
				(-toView.z+2*normale.z*winkel-inter.z));
		Ray r2 = new Ray(inter,reflect);
		Vector v1 = getNearestIntersection(r2);
		Primitive p2 = (Primitive) v1.elementAt(1);
		if(p2 != null) {
			Point3D in = (Point3D) v1.elementAt(0);
			int co = count-1;
			ColorRGB next = rek(r2,p2,acc,in,co,oldr);
			acc.add(new ColorRGB(next.red*refl, next.green*refl, next.blue*refl));
		}
	}
	if(refr > 0) {
		double rindex = mat.brind;
		double n = oldr/rindex;
		if(inter.inside) {
			normale = new Vector3D(normale.x*-1,normale.y*-1,normale.z*-1);
		}
		double cos1 = -1*ray.direction.dotProduct(normale);
		double cos2 = 1.0 - n*n * (1.0 - cos1*cos1);
		if(cos2 > 0) {
			Vector3D t = new Vector3D(n*ray.direction.x + (n*cos1 - Math.sqrt(cos2))*normale.x,
					n*ray.direction.y + (n*cos1 - Math.sqrt(cos2))*normale.y,
					n*ray.direction.z + (n*cos1 - Math.sqrt(cos2))*normale.z);
			Ray r2 = new Ray(inter,t);
			Primitive p2 = (Primitive) v1.elementAt(1);
			if(p2 != null) {
				Point3D in = (Point3D) v1.elementAt(0);
				Vector v1 = getNearestIntersection(r2);
				int co = count-1;
				ColorRGB next = rek(r2,p2,acc,in,co,rindex);
				ColorRGB ne = new ColorRGB(next.red*refr, next.green*refr, next.blue*refr);
				ColorRGB absorb = new ColorRGB(matc.red*0.15*-in.dist, matc.green*0.15*-in.dist, matc.blue*0.15*-in.dist);
				ColorRGB transp = new ColorRGB(Math.exp(absorb.red), Math.exp(absorb.green), Math.exp(absorb.blue));
				acc.add(new ColorRGB(ne.red*transp.red, ne.green*transp.red, ne.blue*transp.red));
			}
		}
	}
	return acc;
}
 
Zuletzt bearbeitet:
danke lynxx, schade dass das nicht die fehlerursache war
mir ist nochwas aufgefallen: je öfter ich ihm erlaube, den strahl zu reflektieren(was eig nur 2mal passieren sollte, da alle anderen kugeln weder reflektieren noch das licht brechen), desto geringer ist die anzahl an schwarzen punkten
EDIT: die schwarzen punkte treten neuerdings auch bei reflexionen auf. Liegt daran, dass er hier Objekte trifft, ohne dass er das sollte.
Alles was rot ist ist ein objekttreffer bei der reflexion

EDIT2: Das mit den Reflexionen lag an der Schnittpunktberechnung. Mit einer anderen funktioniert das einwandfrei. nur bei der Refraktion bringts nix
 
Zuletzt bearbeitet:
Sorry wenn ich nochmal zum Reflektionteil komme, was ja nicht dein primäres Problem ist.
Code:
Vector3D toView = new Vector3D(ray.origin.x - inter.x,ray.origin.y - inter.y,ray.origin.z - inter.z);
Hast recht, ist der Direction Vektor aber in entgegengesetzter Richtung und andere Länge. Hatte das nicht ganz durchdacht, danke für die Richtigstellung...

Nun aber zum Eigentlichen, was eher mehr Verständnisfragen sind:
Code:
Point3D p = new Point3D(0,0,0,Double.POSITIVE_INFINITY,false)
Ist der Konstruktor etwa: new Point3D(x,y,z,distance,bool) ?
Wofür steht der Boolean? Innenseite oder Aussenseite?
Im weiteren Verlauf checkst du die Primitives von einem Vektor(?) v. Um dann am Ende einen neuen lokalen Vektor v zu erstellen dem du dann zuerst den Schnittpunkt und dann das Primitive hinzufügst. Warum das? Was ist v innerhalb der for Schleife und dann als gleichbenannte lokale Variable v? Hoffe du verstehst worauf ich hinaus will.

Zu checkCollision() kann ich nur sehr wenig sagen, da es für mich fast unmöglich ist hier zu erkennen, was du da treibst, zum einen verwendest du sehr viele Variablen mit nichtssagenden Namen (a,b,c,i1,i2...), zum anderen sind eine Vielzahl der Variablen nicht in der Methode definiert, also wahrscheinlich Instanzvariablen der Klasse deren Herkunft/Verwendung nicht erkennbar ist. Zu welcher Klasse gehört die Methode? Welche Instanzvariablen hat diese Klasse?

Wie schon von den anderen geschrieben, modifiziere deinen Code möglichst sofort, sodass du ausschließlich sprechende Namen verwendest! Dann wirds leichter den Sinn dessen zu verstehen und man kann dir besser helfen. Kommentare wären auch nett, jedoch wenn du den Code so schreibst, dass er von vornherein menschenlesbar wird, brauchst du diese nicht zwingend, zumal Kommentare schnell veralten, gerade bei großen Projekten mit mehreren Beteiligten.

Grüße
Rossibaer
 
Ja, der Boolean zeigt an ob es im INneren eines Objektes ist(bei true). ist wichtig für die Richtung der Normalen.
Du hast ja recht was die Kommentare und Variablen angeht, ich bin nur etwas schreibfaul :)
Der Vector v enthält sämtliche Primitive der Szene, der Vector v1 ist nur ein Speicher für das Primitiv und den Punkt bei der Schnittpunktüberprüfung. Ist nötig weil Java maximal eine Variable aus einer Methode zurückgibt.
Hier der Intersection-Code nochmal, diesmal mit Comments und vernünftigen Variablennamen, aber etwas modifiziert, sodass das Problem bei den Reflexionen nicht mehr auftritt.
Code:
public Point3D checkCollision(Ray ray) {
    	Point3D treffer = null;
    	ray.direction.normalize();
		boolean inside = false;
// Vom Augpunkt(ray.origin) zum Kugelmittelpunkt(pos)
		Vector3D AzuK = new Vector3D(pos.x-ray.origin.x,
				pos.y-ray.origin.y,
				pos.z-ray.origin.z);
		double l2 = AzuK.dotProduct(AzuK); // Wenn l2 < Radius der Kugel²(r2) ist der Ursprung in der Kugel -> Kugel wird auf jeden Fall geschnitten
		double s = AzuK.dotProduct(ray.direction); // Wenn s < 0 -> Kugel wird nicht geschnitten
		double m2 = l2 - (s*s); // Wenn m2 > Radius der Kugel² -> Kugel wird nicht geschnitten
		if((m2 <= r2 && s >= 0)) {
			// Wenn der Ursprung außerhalb der Kugel ist sind die beiden Schnittpunkte bei ray.origin+ray.direction*(s -+ Wurzel(r2-m2))
			double q = Math.sqrt(r2-m2);
			double t1 = s - q;
			double t2 = s + q;
			if(t2 < t1 && t2 > 0) // Wenn t2 näher am Augpunkt und t2 > 0 ist wird t2 als Schnittpunkt genommen
				t1 = t2;
			if(l2 < r2) // Wenn der Ursprung des Strahks innerhalb der Kugel ist
				inside = true;
			if(t1 > 0) { // Wenn ein Schnittpunkt existiert
				treffer = new Point3D(ray.origin.x+t1*ray.direction.x,
						ray.origin.y+t1*ray.direction.y,
						ray.origin.z+t1*ray.direction.z,
						Math.sqrt( // Distanz zum Schnittpunkt
								(t1*ray.direction.x*t1*ray.direction.x)+
								(t1*ray.direction.y*t1*ray.direction.y)+
								(t1*ray.direction.z*t1*ray.direction.z)),inside);
			}
		}
		return treffer;
    }
Hier wird das ganze wunderbar erklärt: http://www-gs.informatik.tu-cottbus.de/projektstudium2006/doku/Strahlen_in_der_CG.pdf
 
Hab mal wieder ein paar grundsätzliche Fragen um deinen Code zu verstehen:

in der Funktion/Methode rek() verwendest du 2 globale Variablen "l" und "v", beide vom Typ "Vektor".
Heißt das nun:
Vektor ist in Java eine Auflistung, Array oder sowas?
l sind die Lichter in der Szene?
v sind die Primitives der Szene, d.h. die Kugeln?

Der Grund meiner Fragen ist folgender:
Ich interessiere mich zur Zeit sehr stark für Raytracing und deren Implementierung. Habe im übrigen auch dein genanntes Tutorial hoch, runter und quer gelesen, sowie diverse Literatur angeschafft und gelesen. Ich bin leider nicht mit Java vertraut, jedoch erinnert mich die Syntax extrem stark an C# was meine Stärke ist. Ich habe mir die Snippets von dir in C# Code konvertiert. War kein großer Akt, da aus den Snippets der Code sehr schnell ableitbar ist und sehr viele Sachen gleich sind. Bis auf wenige Detailänderungen (z.B. explizite Casts bei den verwendeten Vektoren l und v) konnte ich den Code so nehmen wie er ist, zum Schluß noch eine Vektor Wrapper Klasse und eine kleine Änderung bei dem Double.PositiveInfinity und schon compiliert der Code in C#. Werde mich jetzt als nächstes mit der Erstellung der Szene, d.h. die Kugeln (Position, Material etc.), Licht sowie der Darstellung in einer Windows.Form befassen um das ganze dann auch vollständig ans Leben zu bekommen. Als nächstes werde ich mir dann mal das Ganze genauer anschauen und sehen ob sich das Problem bei mir reproduzieren läßt. Wenn ja, dann könnten wir uns gegenseitig mal "befruchten" und vielleicht so eine Lösung finden...

Danke erstmal für deine Infos.

Grüße
Rossibaer

Hier noch der zumindest kompilierbare Code, den ich bisher habe: Anhang anzeigen Raytracer.zip


Edit 1:
Steht brind für Brechungsindex des Materials?
Steht amb für Absorption des Lichts vom Material?
 
Zuletzt bearbeitet: (Nachfrage Brechungsindex und Absorption statt brind und amb)
ja, l und v eintahlten alle lichtquellen bzw. objekte der szene. vektoren sind so was wie arrays mit offenen grenzen.
brind ist der BRechungsINDex, amb der ambiente anteil
EDIT: Ich musste leider feststellen, dass der reflexions- und shadingteil leider nicht so funktioniert hat, wie er sollte. Daher ein "kleines" Code-Update:
Code:
public ColorRGB rek(Ray ray, Primitive pr, ColorRGB acc, Point3D inter, int count, double oldr) {
		if(pr.isLight()) {
			acc.add(pr.getMat().c);
			return acc;
		}
		double reflection = pr.getMat().refl;
		double refraction = pr.getMat().refr;
		ColorRGB objectc = pr.getMat().c;
		Vector3D dir = ray.direction;
		double ambient = pr.getMat().amb;
		for(int i = 0; i < l.size(); i++) {
			ColorRGB occlusion = new ColorRGB(objectc);
			if(pr.shadowed(inter, v, l.elementAt(i)) != true) {
				occlusion = new ColorRGB(pr.shade(objectc, ray, inter, l.elementAt(i)));
			}
			else {
				occlusion.multi(ambient);
			}
			occlusion.multi(1-(reflection+refraction));
			acc.add(occlusion);
		}
		if(count < 0)
			return acc;
		if(reflection > 0) {
			Vector3D normale = pr.getNormal(inter);
			double winkel = dir.dotProduct(normale);
			Vector3D reflect = new Vector3D(ray.direction.x-2.0*winkel*normale.x,
					ray.direction.y-2.0*winkel*normale.y,
					ray.direction.z-2.0*winkel*normale.z);
			Ray r2 = new Ray(inter,reflect);
			Primitive p2 = null;
			Point3D in = null;
			Vector v1 = getNearestIntersection(r2);
			in = (Point3D)v1.elementAt(0);
			p2 = (Primitive)v1.elementAt(1);
			if(p2 != null) {
				int co = count-1;
				ColorRGB next = rek(r2,p2,new ColorRGB(0,0,0),in,co,oldr);
				next.multi(reflection);
				acc.add(next);
			}
		} 
		if(refraction > 0) {
			Vector3D normale = pr.getNormal(inter);
			double rindex = pr.getMat().brind;
			double n = oldr/rindex;
			if(inter.inside) {
				normale.mult(-1);
			}
			double cos1 = dir.dotProduct(normale);
			double cos2 = 1.0 - n*n * (1.0 - cos1*cos1);
			if(cos2 > 0) {
				Vector3D t = new Vector3D((n*dir.x) - (n*cos1 + Math.sqrt(cos2))*normale.x,
						n*dir.y - (n*cos1 + Math.sqrt(cos2))*normale.y,
						n*dir.z - (n*cos1 + Math.sqrt(cos2))*normale.z);
				Ray r2 = new Ray(inter,t);
				Primitive p2 = null;
				Point3D in = null;
				Vector v1 = getNearestIntersection(r2);
				in = (Point3D) v1.elementAt(0);
				p2 = (Primitive) v1.elementAt(1);
				if(p2 != null) {
					int co = count-1;
					ColorRGB next = rek(r2,p2,new ColorRGB(0,0,0),in,co,rindex);
					next.multi(refraction);
					ColorRGB absorb = new ColorRGB(objectc);
					absorb.multi(-0.15*in.dist);
					ColorRGB transp = new ColorRGB(Math.exp(absorb.red),
							Math.exp(absorb.green),
							Math.exp(absorb.blue));
					transp.multi(1);
					acc.add(next);
				}
			}
		}
		return acc;
	}
Diesmal sogar mit sinnvollen Variablennamen ;)

EDIT2: Raaahhhh! Fehler gefunden :pcangry:
In der Schnittpunktmethode checkCollision() darf für die Distanzermittlung des Schnittpunktes Ray.direction nicht normalisiert sein! Ohne sieht's dann so aus:
Code:
public Point3D checkCollision(Ray ray) {
    	Point3D treffer = null;
    	Vector3D dir = new Vector3D(ray.direction);
    	Point3D or = new Point3D(ray.origin);
    	dir.normalize();
		boolean inside = false;
		// Vom Augpunkt(ray.origin) zum Kugelmittelpunkt(pos)
		Vector3D AzuK = new Vector3D(pos.x-or.x,
				pos.y-or.y,
				pos.z-or.z);
		double l2 = AzuK.dotProduct(AzuK); // Wenn l2 < Radius der Kugel²(r2) ist der Ursprung in der Kugel -> Kugel wird auf jeden Fall geschnitten
		double s = AzuK.dotProduct(dir); // Wenn s < 0 -> Kugel wird nicht geschnitten
		double m2 = l2 - (s*s); // Wenn m2 > Radius der Kugel² -> Kugel wird nicht geschnitten
		if((m2 <= r2 && s >= 0)) {
			// Wenn der Ursprung außerhalb der Kugel ist sind die beiden Schnittpunkte bei ray.origin+ray.direction*(s -+ Wurzel(r2-m2))
			double q = Math.sqrt(r2-m2);
			double t1 = s - q;
			double t2 = s + q;
			if(t2 < t1 && t2 > 0) // Wenn t2 näher am Augpunkt und t2 > 0 ist wird t2 als Schnittpunkt genommen
				t1 = t2;
			if(l2 < r2) // Wenn der Ursprung des Strahks innerhalb der Kugel ist
				inside = true;
			if(t1 > 0) { // Wenn ein Schnittpunkt existiert
				treffer = new Point3D(or.x+t1*ray.direction.x,
						or.y+t1*ray.direction.y,
						or.z+t1*ray.direction.z,
						Math.sqrt( // Distanz zum Schnittpunkt
								(t1*ray.direction.x*t1*ray.direction.x)+
								(t1*ray.direction.y*t1*ray.direction.y)+
								(t1*ray.direction.z*t1*ray.direction.z)),inside);
			}
		}
		return treffer;
    }

*freufreufreu* :D
 
Zuletzt bearbeitet:
Na, was hab ich gesagt? Immer weiter suchen, irgendwann stößt man auf jeden Fehler. ;)


Glückwunsch :)
 
F.b schrieb:
Code:
...
				if(p2 != null) {
					int co = count-1;
					ColorRGB next = rek(r2,p2,new ColorRGB(0,0,0),in,co,rindex);
					next.multi(refraction);
					ColorRGB absorb = new ColorRGB(objectc);
					absorb.multi(-0.15*in.dist);
					ColorRGB transp = new ColorRGB(Math.exp(absorb.red),
							Math.exp(absorb.green),
							Math.exp(absorb.blue));
					transp.multi(1);
					acc.add(next);
				}
ColorRGB absorb = .. bis inkl. transp.multi(1); sind funktionslos/keine Auswirkung.
 
Zurück
Oben