SWRenderer: Perspektivenkorrektur -> Wie oft?

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
DerAlbi
Establishment
Beiträge: 269
Registriert: 20.05.2011, 05:37

SWRenderer: Perspektivenkorrektur -> Wie oft?

Beitrag von DerAlbi »

Hallo,
Ich baue gerade einen SoftwareRenderer für ein portables Gerät. Zielarchitektur ist also kein x86. Hab 120MHz, ein wenig SIMD und eine DSP-Mul Einheit zur Verfügung. Ebenso hab ich keine ernstzunehmende Division und allenfalls Fixkomma (dafür für Fixkomma eine extrem optimierte Template-Lib selbstgeschrieben). Füllen muss ich 240x320 Pixel. Ziel sind 15FPS bei 200Tri. isher habe ich noch keinen Zbuffer. Der braucht mehr Leistung als erwartet, deswegen wieder entfernt.

Die ganze Vertex-Transformationspipeline steht schon. Clipping klappt soweit auch: Einerseits Culling andererseits Abschneiden der 3ecke die über den Framebuffer hinausgehen.
Da ich das Abschneiden der überstehenden 3ecke vor der 2D Projektion mache, kann ich die neu einzufügenden Vertices aus linearer Interpolation der Originale bestimmen ohne dass dabei perspektivische Fehler auftreten -> die projektion zu 2D folgt ja erst später. (Habs mit ScreenSpace-Clipping auch probiert. Das bekomme ich perspektivisch nicht in den Griff. Im ProjectionSpace ist es zwar schwerer zu Clippen, aber die Resultate sind dafür korrekter)

Es kommt nun also vor, dass durch Schneiden eines 3ecks mit dem Bildschirmrand neue 3ecke entstehen.
Wenn ich nun eine Textur ohne Perspektivenkorrektur drauflege sieht das furchtbar aus: bei Kamerabewegung entstehen ständig neue oder sich ändernde 3ecke die wiederum Texturknickkanten mit sich bringen. Das sorgt schon bei leichter Blickänderung zu extremen Textursprüngen. HÄSSLICH.

Ausweg: Perspektivische Korrektur. Da die neu eingefügten Vertices perspektifisch korrekt sind, Lege ich die textur nun auch perspektifisch korrekt auf die 3ecke drauf. Zwischen zwei benachbarten 3ecken sind die Texturkoordinaten damit "flüssig" verteilt. Perspektivische Korrektur ist eh der einzige Weg Textren ernsthaft zu mappen :-)

Perspektifisch korrekte interpolation ist jedoch extrem teuer. Es benötigt pro interpolation nach ein wenig Optimierung 1 Division, mehere Multiplikationen und eine zusätzliche Variable im Vertex die zu allem Überfluss auch noch interpoliert werden muss. Genauers dazu ist auch erstmal egal: ES IST LANGSAM.

Lösung: Perspektifisch korrekte Stützpunkte im 3eck errechen und zwischen denen dann linear interpolieren. Sehr gut. Gesagt, getan. Ist schneller und steht der absoluten perfekten Perspektivenkorrektur optisch um nix nach, aber noch nicht optimal.
->Ein 3eck dessen Normale direkt zur Kamera zeigt braucht gar nicht korrigiert werden.
->Kleine 3ecke die weit weg sind und eh nicht aus vielen Punkten bestehen brauchen auch nicht korrigiert werden. Der Entstehende Fehler ist im SubPixelbereich bzw liegt Wenig Texturfläche auf wenig Framebuffer. Der Fehler ist halt gering.
->Flächenmäßig kleine (aber extrem lange (dafür schmale)) 3ecke müssen sehr stark korrigiert werden. je mehr die Normale weg von der Kamera zeigt.
->Die Liste geht noch weiter: und hier fängt das Problem an :-)

Also: Das mit der Normale hab ich schon gelößt. Je mehr eine Normale in x-Richtung oder y-Richtung zeigt, desto enger wird das Raster der korrekten Stützpunkte in diese Richtung. Das ist schon ok, aber bei weitem noch nicht optimal.
Rendere ich damit ein Fullscreen Rechteck aus 2 Dreicken ist alles wunderbar.
Rendere ich damit aber ein Fullscreen Rechteck mit 10x10 Punkten, dann sind die Stützpunkte immernoch genauso eng unterteilt. Dabei sind die 3ecke aber viiiel kleiner. Zwischen Affinen und Korrektem Mapping ist kein Unterschied zu sehen.. Logisch, da die Textuverzerrung pro 3eck wesentlich kleiner geworden ist.
Das ist natürlich verschwendete Rechenleistung. (und die ist verdammt knapp für die Auflösung)

Ich bekomme es nicht hin, die gesamten aufgeführten Punkte in eine Formel zu packen. Ich fühle mich ein wenig Hilflos :-(
Hier ist das was ich bisher habe:

Code: Alles auswählen

void CRasterizer::RenderVertexBuffer(COutputVertex* VertexInput, int NumPrimitives)
{
	for(int i = 0; i < NumPrimitives; i++)
	{
		CRasterizerVertex in[3];
		COutputVertex* out[3] = {&VertexInput[i*3+0], &VertexInput[i*3+1], &VertexInput[i*3+2]};

		for(int j = 0; j < 3; j++)
		{
			//Projektion und [-1..1] -> [0..Res]
			in[j].X = MAKE_INT(out[j]->p.x/out[j]->p.w *xRes/2 + Fixpoint(xRes/2) );
			in[j].Y = MAKE_INT(out[j]->p.y/out[j]->p.w *yRes/2 + Fixpoint(yRes/2) );

			//Inverse Z position -> für Perspektiven korrektur
			in[j].zorginv = InterpolationFixpoint(1.0) / (out[j]->p.z - 1);
			in[j].t = out[j]->t; //TexturKoord
			in[j].c = out[j]->c; //VertexFarbe
		}
		//3eckseiten
		CVector3D s1 = ( (out[0]->p*(Fixpoint(1.0)/out[0]->p.w)) - (out[1]->p*(Fixpoint(1.0)/out[1]->p.w))).DicardW();
		CVector3D s2 = ( (out[0]->p*(Fixpoint(1.0)/out[0]->p.w)) - (out[2]->p*(Fixpoint(1.0)/out[2]->p.w))).DicardW();
		//3ecknormale
		CVector3D Normal =  CVector3D::Cross(s1, s2);
		int F = IntSqrt(MAKE_INT(Normal.AbsSq()*(xRes*yRes)) ); //Fläche Ausrechnen.. wozu auch immer.
		Normal = Normal.Normalize();

		Fixpoint Quality = 250;
		Normal.x = Abs(Normal.x); //Unabhängig von Richtung - Nur winkel zählt -> Abs
		Normal.x *= Quality/Fixpoint(xRes); //Unabhänig von ZielAuflößung
		Normal.y = Abs(Normal.y);
		Normal.y *= Quality/Fixpoint(yRes);
		int xQ = MAKE_INT((Fixpoint(1.0)/(Normal.x+Fixpoint(0.001))));
		int yQ = MAKE_INT((Fixpoint(1.0)/(Normal.y+Fixpoint(0.001))));
		//             Koordianten 	   Raster X      Y
		DrawTriCorrect(in, in+1, in+2, Min(xQ, 128), Min(yQ, 128));
	}
}
Was ist eigentlich mit meiner Einrückung los?
Ziel: Wenn ich ein gerades FullscreenRechteck zeichne, soll der Korrekte Mapper den Affinen Mapper nicht wesentlich unterliegen. (Nur mal so zur vorstellung: Der Affine Mapper braucht bei 2 3ecken 42 Takte pro berechneten Pixel (Texturiert, Coloriert)) Der korrekte Mapper braucht bisher 62 Takte. Neben Codeoptimierung (was auch noch Thema sein soll) hilft es erstmal den Rechenaufwand überhaupt zu minimieren.

Wer tolle Ideen hat, die perspektivisch korrekten Stützpunkte intelligent aufzuteilen: Schießt los!

MFG
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: SWRenderer: Perspektivenkorrektur -> Wie oft?

Beitrag von Jörg »

"back in the days" wurden Stuetzstellen alle 8 Pixel verwendet, unabhaengig von der Flaechennormale, um eine FPU-Division parallel zu 8 linear interpolierten Pixeln auszufuehren.
Mit SSE-Einsatz duerfte sich das wohl aendern. Eventuell liefern die paar Brocken ueber Pixomatic-Interna von M. Abrash ein paar mehr Hinweise?
Oder Du renderst auf Linien mit konstantem Z, dann sparst Du Dir die Divisionen pro Pixel ganz (bezahlst aber mit mehr Cache-Misses).
Antworten