Raytracing



  • Hi, ich bin gerade dabei in meiner Freizeit einen kleinen raytracer zu schreiben.

    Leider hab ich beim intersection test mit dem dreieck ein bischen Probleme.
    Die Kanten sind unsauber und dass sieht dann so aus http://www.urbsch.at/files/hmpf.png. Ich kann mir gerade nicht vorstellen woran das liegen kann.

    Hoffe jemand hatte schonmal ein änliches Problem. Code ist leider ziemlich verteil daher schlecht zu posten..

    Gruss



  • Hi,

    ich würde dir ja gerne mitteilen welcher der 7857863874658436 möglichen Fehler in deinem Programm zu diesem Ergebnis führt aber leider ist meine Kristallkugel gerade zur Reperatur.


  • Mod

    poste bitte die schnittpunkt funktion fuers dreieck (darum geht's dir doch, oder?) dann kann man etwas dazu sagen 😉



  • Hmmm.
    Also laut meine Kristallkugel könnte es an am Fließkomma-Datentyp liegen.
    Diese Szene ist doch sicherlich sehr künstlich (also runde Dezimalzahlen), was
    Kamera-Position, Blickrichtung und Vertexposition angeht. Baue einfach mal
    einen Schwellenwert dafür, ob dieser Strahl das Dreieck trifft odr nicht.



  • Hi, also ich hab mal von float auf double umgestelt, sieht schon erheblich besser aus aber noch immer nicht perfekt. Ich kann mir aber irgendwie nicht vorstellen das float schon zu ungenau ist.

    Hier mal die schnittpunktfunktion. (ja ist irgendwo aus dem internet geklaut ;))

    bool Intersects(Ray &ray)
    {
    	//double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
    	Vector3D edge1, edge2, tvec, pvec, qvec;
    	double det,inv_det;
    	double u, v;
    
    	// find vectors for two edges sharing vert0 
    	//SUB(edge1, vert1, vert0);
    	edge1 = two - one;
    	//SUB(edge2, vert2, vert0);
    	edge2 = three - one;
    
    	// begin calculating determinant - also used to calculate U parameter 
    	//CROSS(pvec, dir, edge2);
    	pvec = ray.direction.cross(edge2);
    
    	// if determinant is near zero, ray lies in plane of triangle 
    	//det = DOT(edge1, pvec);
    	det = edge1.dot(pvec);
    
    	if (det > -EPSILON && det < EPSILON)
    		return false;
    	inv_det = 1.0 / det;
    
    	// calculate distance from vert0 to ray origin 
    	//SUB(tvec, orig, vert0);
    	tvec = ray.origin - one;
    
    	// calculate U parameter and test bounds 
    	//*u = DOT(tvec, pvec) * inv_det;
    	u = tvec.dot(pvec) * inv_det;
    	//if (*u < 0.0 || *u > 1.0)
    	if (u < 0.0 || u > 1.0)
    		return false;
    
    	// prepare to test V parameter 
    	//CROSS(qvec, tvec, edge1);
    	qvec = tvec.cross(edge1);
    
    	// calculate V parameter and test bounds 
    	//*v = DOT(dir, qvec) * inv_det;
    	v = ray.direction.dot(qvec) * inv_det;
    	//if (*v < 0.0 || *u + *v > 1.0)
    	if (v < 0.0 || u + v > 1.0)
    		return false;
    
    	// calculate t, ray intersects triangle 
    	//*t = DOT(edge2, qvec) * inv_det;
    	ray.t = edge2.dot(qvec) * (float)inv_det;
    
    	return true;
    }
    


  • Das mit den "doubles" war zwar gut gedacht, aber bringt nicht wirklich viel.
    Nimm "floats".

    Das einzige was du machen kannst ist, statt

    u < 0.0 || u > 1.0
    

    das zu nehmen

    u < -threshold || u > 1.0 + threshold
    

    Natürlich bei v auch. Und threshold entsprechend balancieren.



  • Also ist das eher ein generelles problem mit Dreiecken?



  • foofel schrieb:

    Also ist das eher ein generelles problem mit Dreiecken?

    eher ein generelles problem bei vergleichen mit fließpunktzahlen 🙂


  • Mod

    das sieht zu kaputt aus als dass das ein float problem waere. bei float ungenaugikeiten wuerde man vielleicht mal ein pixel falsch haben, aber nicht einen komplett zersaegten rand bei einem dreieck.



  • stimmt auch wieder 🙂



  • rapso schrieb:

    das sieht zu kaputt aus [...] vielleicht mal ein pixel falsch

    Was meinst du damit?

    Diese Funktion ist korrekt, erstes weil er sie nicht selber geschrieben hat 😃
    und zweitens sind 99,9% der Pixel korrekt. Das einzige, was nicht okay ist, ist
    der Rand bzw. wie es bei Fließkommazahlen so ist, die Grenzbereiche. Das
    einzige was du dagegen machen kannst, ist Schwellenwerte einzubauen.


  • Mod

    Chuck schrieb:

    rapso schrieb:

    das sieht zu kaputt aus [...] vielleicht mal ein pixel falsch

    Was meinst du damit?

    was verstehst du daran nicht?

    Diese Funktion ist korrekt, erstes weil er sie nicht selber geschrieben hat 😃

    wo liest du dass diese funktion inkorrekt ist? ich denke diese moeller ray-triangle intersection ist schon zu recht patentiert ist.

    und zweitens sind 99,9% der Pixel korrekt.

    bei float sollten es 99.999% sein, also quasi vielleicht mal ein pixel.

    Das einzige, was nicht okay ist, ist
    der Rand bzw. wie es bei Fließkommazahlen so ist, die Grenzbereiche.

    rand und graenzbereiche sind verschiedene dinge. und ja, der rand ist inkorrekt, weit ueber das mass von ueblicher float ungenauigkeit.

    Das einzige was du dagegen machen kannst, ist Schwellenwerte einzubauen.

    Es ist ein wenig stupide ohne den fehler zu wissen auf gut glueck irgendwelche hacks einzubauen. das naechste mal wird er ein transparentes objekt aus polygonen machen wollen und wird ploetzlich ueberlapende raender haben weil er ueberall ein epsilon eingebaut hat oder...
    🙄

    einfach nach ein paar anderen raytracing versuchen googlen:
    http://inst.eecs.berkeley.edu/~cs184/fa07/raytrace_journal.php
    http://pippin.gimp.org/plug-ins/gluas/examples/raytrace.png
    http://janalepon.com/raytrace/
    und dann sieht man dass diese korrekt aussehen.

    da hilft nur debuggen, z.b. mal nen anderen ray-triangle test klauen und ausprobieren, vielleicht geht was beim ray-setup schief, vielleicht ...vielleicht...



  • Ich werd mal schauen was ich sonst noch machen kann, danke erstmal für die hilfe 🙂



  • Hi,

    möglicherweise hilft Supersampling.

    Bei Pixeln bei denen das Ergebnis ob es zum Objekt gehört oder nicht sehr knapp ausfällt könntest du mehrere Strahen pro Pixel losschicken, die leicht versetzt parallel sind also so:

    |------|
    | x  x |
    | x  x |   <= Pixel mit 4 Stellen an denen der Strahl berechnet wird.
    |------|
    

    Dann kannst du einfach das Ergebnis (gehört zum Dreieck oder nicht) nehmen was öfter vorkommt und der Rand des Dreiecks müßte etwas einheitlicher aussehen.

    Noch besser wäre eine adaptive Lösung indem du die Unterschiede der Ergebnisse des Strahltests berechnest und danach weiter unterteilst:

    |------------------
    |                 |
    |  x    |  x      |
    |                 |
    | -  -  | -  -  - |
    |   x      x | x  |
    |       |  -   -  |
    |       |  x | x  |
    |-----------------|
    

    Oder einfach stochastisch (zufallsbasiert)über das Pixel verteilen

    |------------------
    |          x    x |
    |   x             |
    |                 |
    | x        x      |
    |  x              |
    |        x     x x|
    |-----------------|
    

Anmelden zum Antworten