Ray tracing - Kugeln sind keine Kugeln



  • Hallo.

    Aus aktuellem Anlass (im Dezember gab es einen Ray tracing jam, der Thread ist leider verschwunden) hatte ich wieder 'mal Lust auf Ray tracing. Sehr weit bin ich noch nicht, da ich alles unnötig kompliziert mache, aber das erste Bild habe ich schon einmal. Mein Problem ist, dass es so aussieht, als wenn ein Fischaugeneffekt darauf angewandt wurde.

    Hier ist ein Beispiel. Zwar sind alle Kugeln gleich gross, jedoch ist die hellblaue näher an der Kamera als die rote. Die rote ist weiter weg und näher an der Bildmitte, weswegen sie beinahe rund erscheint. Die hellblaue hingegen sieht alles Andere als rund aus.

    Meine Render-Funktion sieht so aus:

    void Render(Image& Destination, Scene const& Scene, Camera const& Camera)
    {
    	const Angle PixelAngleX = Camera.FovX / Destination.Width();
    	const Angle PixelAngleY = Camera.FovY / Destination.Height();
    
    	for(SizeType X = 0; X < Destination.Width(); ++X)
    	{
    		LA::RotationMatrix<FloatT, 3> YTransform(LA::Y, PixelAngleX * X + PixelAngleX / 2 - Camera.FovX / 2);
    
    		for(SizeType Y = 0; Y < Destination.Height(); ++Y)
    		{
    			LA::RotationMatrix<FloatT, 3> XTransform(LA::X, PixelAngleY * Y + PixelAngleY / 2 - Camera.FovY / 2);
    
    			Ray PixelRay(Camera.Orientation.Origin, Normalize(YTransform * XTransform * Camera.Orientation.Direction));
    			Intersection Intersection = Scene.GetIntersection(PixelRay);
    
    			if(Intersection.HitObject == 0)
    			{
    				Destination(X, Y) = Scene.BackgroundColor;
    			}
    			else
    			{
    				Destination(X, Y) = Intersection.HitObject->GetMaterial(Intersection.GetRelativePosition()).SurfaceColor;
    			}
    		}
    	}
    }
    

    Irgendetwas sagt mir, dass ich nicht für jedes Pixel denselben Winkel nehmen darf, aber ich kann mir keine Formel denken damit das Bild nicht verzerrt ist. Hatte jemand schon einmal etwas Ähnliches?

    Gruss.


  • Mod

    asfdlol schrieb:

    Aus aktuellem Anlass (im Dezember gab es einen Ray tracing jam, der Thread ist leider verschwunden)

    war nur ein vote pool und bei 4votes die mehrheitlich unmotiviert waren schien es mir wie ein rohrkrepierer.

    hatte ich wieder 'mal Lust auf Ray tracing.

    hatte die idee doch etwas fruchtbares 😃

    Sehr weit bin ich noch nicht, da ich alles unnötig kompliziert mache, aber das erste Bild habe ich schon einmal.

    ich hatte vor ein kleines framework zu basteln damit nicht jeder bei 0 anfaengt und dann eben mit sowas ewig braucht. dann haette sich jeder auf sein wunsch fokusiert (materialien, optimierung, lightquellen, kamera/linsen, etc.). naja 🙂

    Mein Problem ist, dass es so aussieht, als wenn ein Fischaugeneffekt darauf angewandt wurde.

    Hier ist ein Beispiel. Zwar sind alle Kugeln gleich gross, jedoch ist die hellblaue näher an der Kamera als die rote. Die rote ist weiter weg und näher an der Bildmitte, weswegen sie beinahe rund erscheint. Die hellblaue hingegen sieht alles Andere als rund aus.

    Meine Render-Funktion sieht so aus:

    void Render(Image& Destination, Scene const& Scene, Camera const& Camera)
    {
    	const Angle PixelAngleX = Camera.FovX / Destination.Width();
    	const Angle PixelAngleY = Camera.FovY / Destination.Height();
    
    	for(SizeType X = 0; X < Destination.Width(); ++X)
    	{
    		LA::RotationMatrix<FloatT, 3> YTransform(LA::Y, PixelAngleX * X + PixelAngleX / 2 - Camera.FovX / 2);
    
    		for(SizeType Y = 0; Y < Destination.Height(); ++Y)
    		{
    			LA::RotationMatrix<FloatT, 3> XTransform(LA::X, PixelAngleY * Y + PixelAngleY / 2 - Camera.FovY / 2);
    
    			Ray PixelRay(Camera.Orientation.Origin, Normalize(YTransform * XTransform * Camera.Orientation.Direction));
    			Intersection Intersection = Scene.GetIntersection(PixelRay);
    
    			if(Intersection.HitObject == 0)
    			{
    				Destination(X, Y) = Scene.BackgroundColor;
    			}
    			else
    			{
    				Destination(X, Y) = Intersection.HitObject->GetMaterial(Intersection.GetRelativePosition()).SurfaceColor;
    			}
    		}
    	}
    }
    

    Irgendetwas sagt mir, dass ich nicht für jedes Pixel denselben Winkel nehmen darf, aber ich kann mir keine Formel denken damit das Bild nicht verzerrt ist. Hatte jemand schon einmal etwas Ähnliches?
    Gruss.

    an sich ist deine ausgabe auf dem bildschirm, der ist ja nicht rund, sondern flach. du hast also x und y als pixelkoordinate und z ist eine konstante (wenn du x und y von -1 bis +1 nimmst und z auf 1 setzt, hast du logischerweise einen oeffnungswinkel von 90grad, bzw 2mal 45grad).

    dein bild ist an sich nicht verkehrt, kugeln werden zu ellipsen bei perspektivischer sicht. das problem ist halt nur dass du ein rundes bild renderst, auf einer flachen oberflaeche anzeigst. wirkt ungewohnt, aber solche verzerrungen hat man bei kameras auch http://en.wikipedia.org/wiki/Distortion_(optics)#Radial_distortion (du hast hier wohl die barrel distortion).



  • rapso schrieb:

    war nur ein vote pool und bei 4votes die mehrheitlich unmotiviert waren schien es mir wie ein rohrkrepierer.

    Bedauerlich. Gibt es die Möglichkeit sowas wieder zu eröffnen?

    rapso schrieb:

    Sehr weit bin ich noch nicht, da ich alles unnötig kompliziert mache, aber das erste Bild habe ich schon einmal.

    ich hatte vor ein kleines framework zu basteln damit nicht jeder bei 0 anfaengt und dann eben mit sowas ewig braucht. dann haette sich jeder auf sein wunsch fokusiert (materialien, optimierung, lightquellen, kamera/linsen, etc.). naja 🙂

    Super Idee. Ich würde ja einen Teil meiner Bibliothek zur Verfügung stellen (Matrizen, Vektoren, Farben, Bilder und Bitmaps out of the box), aber befürchte, dass sie weniger performant ist im Vergleich zu den grösseren Bibliotheken. Von Bugs und Wartbarkeit (z.B. Expression Templates sind beim Debuggen ein Graus) mal abgesehen...

    rapso schrieb:

    an sich ist deine ausgabe auf dem bildschirm, der ist ja nicht rund, sondern flach. du hast also x und y als pixelkoordinate und z ist eine konstante (wenn du x und y von -1 bis +1 nimmst und z auf 1 setzt, hast du logischerweise einen oeffnungswinkel von 90grad, bzw 2mal 45grad).

    dein bild ist an sich nicht verkehrt, kugeln werden zu ellipsen bei perspektivischer sicht. das problem ist halt nur dass du ein rundes bild renderst, auf einer flachen oberflaeche anzeigst. wirkt ungewohnt, aber solche verzerrungen hat man bei kameras auch http://en.wikipedia.org/wiki/Distortion_(optics)#Radial_distortion (du hast hier wohl die barrel distortion).

    Oh, das ist aber ein anderer Ansatz als meiner. Ich hatte ja pro Pixel eine konstante Winkeldifferenz und habe dann die Normale der Kamera anhand dieser rotiert. Du hast aber davon erzählt, pro Pixel einen Wert zu X und Y hinzuzuaddieren (und zuletzt dann zu normalisieren). Bei deinem Ansatz ist die Winkeldifferenz nicht konstant (was ich eigentlich vermutet hätte, siehe OP).

    Zwei Bilder mit derselben Szene / Kamera / FOV (90°):
    Konstanter Winkel (mein ursprünglicher Ansatz)
    Konstante Translation (was du geschildert hast)

    Meiner Meinung nach sehen beide immer noch schrecklich aus (FOV zu gross / Kamera zu nah?). Eher geht es mir aber darum, welches davon theoretisch korrekt ist. Ich vermute, dass deine Methode korrekter ist, nicht zuletzt weil da die Kugeln auch tatsächlich symmetrische Ellipsen sind (was man von meinen Sitzsäcken nicht behaupten kann).

    Danke schon mal für die Hilfe. 🙂



  • Cool, ich schreibe auch gerade eine Grafiklib in C, wo ich wirklich alles selbst programmiere, also Matrizen, Vektoren, Quaternionen, Farbräume, Bilder und 3D-Modells laden, 3D Pipeline usw. Raytracing und später OpenGL soll auch mit rein. Ich würde mich riesig über solch einen Thread hier freuen. Ich meine solch ein Projekt ist ja nicht schwer, aber wenn es nachher um Optimierungen geht, dann gibt es bestimmt den einen oder anderen guten Tipp hier.

    Freizeit habe ich ohne Ende und was gibt es besseres als diese mit seinen eigenen Projekten zu nutzen?


  • Mod

    wenn die kamera nah dran ist, kann es durchaus so verzerrt aussehen, wobei es schon sehr verzerrt ausschaut, als ob du eher fisheye haettest.

    es bietet sich an am anfang mit referenz daten zu arbeiten, beim tracen ist das klassische eine cronell box:
    http://www.graphics.cornell.edu/online/box/data.html



  • asfdlol schrieb:

    Irgendetwas sagt mir, dass ich nicht für jedes Pixel denselben Winkel nehmen darf, aber ich kann mir keine Formel denken damit das Bild nicht verzerrt ist. Hatte jemand schon einmal etwas Ähnliches?

    Konstante Winkeländerung pro Pixel ist falsch. Stell dir vor, was passiert, wenn du ein unendlich grosses Bild hast. Du siehst dann nicht hinter dich, sondern dein Sichtfeld nähert sich 180°.

    Stell dir es in 2D vor mit der Bildgeraden x=1 und dem Zentrum in (0,0). Der Punkt (x0,y0) ist (für x>1) dann der Schnittpunkt der Geraden y=y0/x0*x mit x=1, also liegt er auf (1, y0/x0).

    Umgekehrt kriegst du also den Bildpixel auf yB, wenn du den Strahl in die Richtung y=yB*x, also parallel zum Vektor (1, yB) schickst.

    In 3D ist das genau gleich, der Bildpixel (xB, yB) kommt vom Richtungsvektor (xB, yB, 1). Jetzt brauchst du nur noch Umrechnungsfaktoren von (xB, yB) in Bildkoordinaten (mal Bildbreite und dann abrunden oder so) und hast es.

    Sollte eigentlich konstante Translation sein, wie du schon probiert hast. Zeig uns mal den angepassten Code.



  • Ich liefere ein Bild der Cornell-Box so schnell wie möglich (muss erst noch den Obj-Loader soweit fertig machen, damit ich sie einlesen kann). Soll nicht heissen, dass ich aufgegeben habe, nur weil ich mich hier eine Weile nicht gemeldet habe. Danke schon mal für die Hilfe soweit!

    lutter, wie hast du mich gefunden? 😞 Vieles ist unfertig und einiges ist alt, also nicht lachen pls.


Anmelden zum Antworten