Software Rendering: Texturekoordinaten nach dem Clipping?



  • Ich habe eine Frage zum Clippen mit Homogenen Koordinaten.

    Die 3D Pipeline:
    1. Perspective Transformation -> 2. Clipping -> 3. Perspektivische Teilung (divide by w)

    Mein Frage:
    Wie werden beim Clipping wenn neue Vertices enstehen an diesen die Vertexattribute wie z. B. die Texturkoordinaten berechnet?

    ich habe es so implementiert:

    // Betrachte nur die Left Clipping Plane
    
    // ist Clipping gegen die Left Clipping Plane erforderlich?
    if (v1.position.x + v1.position.w <= 0 ||
    	v2.position.x + v2.position.w <= 0 ||
    	v3.position.x + v3.position.w <= 0)
    {
    	vertex V[3]; // Das ursprüngliche nicht geclippte Dreieck
    	V[0] = v1;V[1] = v2;V[2] = v3;
    
    	vertex T[16]; // Platz für geclippte Vertices
    	int t = 0;
    	int numVertices = 3;
    
    	// for each edge (in counter clockwise order)
    	for(int i = 0; i < numVertices; i++)
    	{
    		int j = i == numVertices - 1 ? 0 : i + 1;   // Next vertex index
    
    		if (V[i].position.x + V[i].position.w > 0) // i inside?
    		{
    			T[t++].position = V[i].position;
    			T[t-1].textureCoordinates = V[i].textureCoordinates;
    
    			if (V[j].position.x + V[j].position.w <= 0) // j outside?
    			{
    				float intersection = (-V[i].position.w - V[i].position.x) / (V[j].position.x - V[i].position.x + V[j].position.w - V[i].position.w);
    
    				T[t++].position = V[i].position + intersection * (V[j].position-V[i].position);
    				T[t-1].textureCoordinates = V[i].textureCoordinates + intersection * (V[j].textureCoordinates-V[i].textureCoordinates);
    			}
    			else
    			{
    				T[t++].position = V[j].position;
    				T[t-1].textureCoordinates = V[j].textureCoordinates;
    			}
    		}
    		else
    		{
    			// i outside
    			if (V[j].position.x + V[j].position.w > 0) // j inside
    			{
    				float intersection = (-V[i].position.w - V[i].position.x) / (V[j].position.x - V[i].position.x + V[j].position.w - V[i].position.w);
    
    				T[t++].position = V[i].position + intersection * (V[j].position-V[i].position);
    				T[t-1].textureCoordinates = V[i].textureCoordinates + intersection * (V[j].textureCoordinates-V[i].textureCoordinates);
    
    				T[t++].position = V[j].position;
    				T[t-1].textureCoordinates = V[j].textureCoordinates;
    			}
    		}
    	}
    
    	for (int i = 0; i < t; i++)
    	{
    		T[i].position = Dehomogenize(T[i].position);
    		T[i].position = viewport * T[i].position;
    		T[i].color = ImageProcessing::color3f(1,1,1);
    	}
    
    	//rasterizeTriangle(T[0],T[1],T[2]);
    
    	for (int i = 1, j = 2; i <= t-2; i++, j++)
    	{
    		if (i>=t)
    		{
    			int erreor=99;
    		}
    
    		rasterizeTriangle(T[0],T[i],T[j]);
    	}
    
    	continue;
    }
    

    http://loop.servehttp.com/~vertexwahn/uploads/clipping/software_screenshot.png
    http://loop.servehttp.com/~vertexwahn/uploads/clipping/software_screenshot_hw.png
    http://loop.servehttp.com/~vertexwahn/uploads/clipping/opengl_screenshot.png

    wie man in software_screenshot_hw.png sehen kann enstehen nach dem Clippen zwei neue Dreiecke. Ich habe die Texturkoordinaten einfach nur linear interpoliert und gehofft, dass das funktioniert - z. B. wird das hier: http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node39.html#colorclipping so beschrieben

    wie man aber an der grün eingezeichneten Line in software_screenshot_hw.png sehen kann stimmt da etwas nicht, weil ich 2 Knicke drin habe.

    Wie macht man es richtig?

    Hier habe ich noch ein Zahlenbeispeil, falls man es damit einfacher erklären kann:
    Dreieck vor dem Clippen (nach perspektivischer Transformation und vor Teilung durch w):
    v0{x=-2.0522513 y=-1.2471070 z=4.4190459 w=4.6100173}
    v1{x=-3.3797491 y=3.1782980 z=4.0984654 w=4.2900767}
    v2{x=-6.4217658 y=1.2471070 z=3.3638406 w=3.5569201}

    Nach dem Clippen gibt es folgende Vertices:
    v0{x=-2.0522513 y=-1.2471070 z=4.4190459 w=4.6100173}
    v1{x=-3.3797491 y=3.1782980 z=4.0984654 w=4.2900767}
    v2{x=-4.1132870 y=2.7126195 z=3.9213214 w=4.1132870}
    v3{x=-4.1132870 y=-0.070623040 z=3.9213212 w=4.1132870}

    Die geclippten Vertices werden zu 2 neuen Dreiecken, die komplett im Frustum liegen:
    v0 v1 v2
    v0 v2 v3

    Frage wie Vertexattribute interpolieren?



  • Is schon einige Zeit her, aber ich glaube mich dunkel erinnern zu können, dass man am besten die Attribute und w interpoliert und dann den interpolierten Wert durch das interpolierte w teilt.
    Vielleicht hilft dir das hier: http://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf



  • Perspektivisches Koorektes Interpolieren kann ich schon (ich mache es wie in dem genannten Artikel (http://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf) beschrieben):

    http://loop.servehttp.com/~vertexwahn/uploads/clipping/software_screenshot_affine.png
    http://loop.servehttp.com/~vertexwahn/uploads/clipping/software_screenshot_persective_correct.png
    http://loop.servehttp.com/~vertexwahn/uploads/clipping/opengl_screenshot2.png

    das Problem ist halt das ich nicht weiß wie man beim clippen umsetzen soll. Komischer weiße findet man dazu auch keine Literatur - in vielen Büchern/Tutorials wird halt schon z. B. im Kameraspace geclippt oder die left Clipping Plane einfach ignoriert und der Rasterisierer kümmert sich dann um Pixel die außerhalb des Sichtbaren bereiches liegen. Ich will aber mit Homogenen Koordinten Clippen und anscheinend ist das auch das was Treiber bzw. Grafikkarten intern machen.

    nehmen wir z. B. folgendes Beispiel. Koordinaten nach perspektivischer Projektion (vor perspektivscher Teilung):
    v1{x=-3.3797491 y=3.1782980 z=4.0984654 w=4.2900767}
    v2{x=-6.4217658 y=1.2471070 z=3.3638406 w=3.5569201}

    Denken wir uns eine Linie von v1 nach v2. v2 liegt außerhalb des Clipping Volumes. v1 nicht.

    zwischen v1 und v2 gibt es einen Schnittpunkt mit der Left-Clipping Plane:
    http://loop.servehttp.com/~vertexwahn/uploads/clipping/clip.png

    Der Schnittpunkt T hat die Koordianten
    T{x=-4.1132870 y=2.7126195 z=3.9213214 w=4.1132870}

    angenommen v1 hat die Farbe blau und v2 die Frabe rot - wie werden die Vertexattribute interpoliert?

    PS: In Gedenken an rapso's PS3 😉



  • Texturkoordinaten sind im World-Space linear und die Transformation in homogene Koordinaten aendert daran nichts.
    Dass der Verlauf der interpolierten Koordinaten auf den entstandenen Dreiecken nicht identisch ist wuerde ich in der Art und Weise vermuten auf die Du die Deltas entlang der Scanlines ermittelst.



  • @hellihjb:
    Der Fehler (nicht perspektivisches korrektes Texturemapping) tritt nur bei geclippten Polygonen auf - bei allen anderen funzt es ohne Probleme

    Die Tranfsformtion sieht bei mir so aus:

    v1.position =  m_Projection * m_Modelview * v1.position; 
    v2.position =  m_Projection * m_Modelview * v2.position;
    v3.position =  m_Projection * m_Modelview * v3.position;
    
    v1.rhw = 1.0f / v1.position.w;
    v2.rhw = 1.0f / v2.position.w;
    v3.rhw = 1.0f / v3.position.w;
    

    in rhw ist die z-Koordinate in Bezug auf den Viewspace gespeichert.
    Theoretisch auch so berechenbar: v1.positon.w = (m_Modelview * v1.positon).z

    Ich verwende keine Deltas anstatt Deltas auszurechnen und dann horizontale Spans zu zeichnen wo ich nur ein Delta aufaddiere rechne ich immer wieder erneut stur für jedes Pixel die baryzentrischen Koordinaten aus- diese verwende ich zum interpolieren

    // magische funktion die x und y Werte bestimmt, die im Dreieck liegen
    
    vertex output_fragment;
    output_fragment.position.x = x; // die magisch berechnet x und
    output_fragment.position.y = y; // y Werte
    output_fragment.position.z = 0;
    output_fragment.position.w = 1;
    
    // baryzentrische Interpolation				
    float alpha1 = triangleArea(output_fragment, v2, v3) / triangleArea(v1,v2,v3);
    float alpha2 = triangleArea(output_fragment, v3, v1) / triangleArea(v1,v2,v3);
    float alpha3 = triangleArea(output_fragment, v1, v2) / triangleArea(v1,v2,v3);
    
    static bool bAffineTextureMapping = false;
    	static bool bAffineTextureMapping = false;
    if(bAffineTextureMapping)
    {
    	output_fragment.textureCoordinates.x = v1.textureCoordinates.x * alpha1 + v2.textureCoordinates.x * alpha2 + v3.textureCoordinates.x * alpha3;
    	output_fragment.textureCoordinates.y = v1.textureCoordinates.y * alpha1 + v2.textureCoordinates.y * alpha2 + v3.textureCoordinates.y * alpha3;
    
    	output_fragment.color = v1.color * alpha1 + v2.color * alpha2 + v3.color * alpha3;
    }
    else
    {
    	output_fragment.textureCoordinates.x = v1.textureCoordinates.x * v1.rhw * alpha1 + v2.textureCoordinates.x * v2.rhw * alpha2 + v3.textureCoordinates.x * v3.rhw * alpha3;
    	output_fragment.textureCoordinates.y = v1.textureCoordinates.y * v1.rhw * alpha1 + v2.textureCoordinates.y * v2.rhw * alpha2 + v3.textureCoordinates.y * v3.rhw * alpha3;
    
    	output_fragment.textureCoordinates.x /= (v1.rhw * alpha1 + v2.rhw * alpha2 + v3.rhw * alpha3);
    	output_fragment.textureCoordinates.y /= (v1.rhw * alpha1 + v2.rhw * alpha2 + v3.rhw * alpha3);
    
    	output_fragment.color.red = v1.color.red * v1.rhw * alpha1 + v2.color.red * v2.rhw * alpha2 + v3.color.red * v3.rhw * alpha3;
    	output_fragment.color.green = v1.color.green * v1.rhw * alpha1 + v2.color.green * v2.rhw * alpha2 + v3.color.green * v3.rhw * alpha3;
    	output_fragment.color.blue = v1.color.blue * v1.rhw * alpha1 + v2.color.blue * v2.rhw * alpha2 + v3.color.blue * v3.rhw * alpha3;
    
    	output_fragment.color.red /= (v1.rhw * alpha1 + v2.rhw * alpha2 + v3.rhw * alpha3);
    	output_fragment.color.green /= (v1.rhw * alpha1 + v2.rhw * alpha2 + v3.rhw * alpha3);
    	output_fragment.color.blue /= (v1.rhw * alpha1 + v2.rhw * alpha2 + v3.rhw * alpha3);
    }
    

    (mir es bewusst, dass scanlines edge walking usw. schneller ist, aber mit deltas würde ich auch keine anderen Werte berechnen)



  • Nimm doch mal einen Eckpunkt der sich aus dem Clipping ergeben hat und berechne anhand Deines urspruenglichen Dreiecks die Texturkoordinaten an dieser Stelle.
    Sind die dann identisch mit den Texturkoordinaten des geclipten Eckpunktes?

    Am Rande:

    Ich will aber mit Homogenen Koordinten Clippen und anscheinend ist das auch das was Treiber bzw. Grafikkarten intern machen.

    3D-Clipping wird weitestgehend vermieden weil das Erzeugen neuer Vertices nicht besonders pipelinefreundlich ist. Es findet lediglich dann Clipping statt, wenn ein Polygon die Near-Plane schneidet (sonst koennte die perspektivische Transformation nicht stattfinden) oder ein (2D-)Eckpunkt ausserhalb des Guard-Bands liegt.
    Alle anderen Faelle lassen sich mit simplen 2D-Tests abdecken und sind im Rahmen der sowieso anfallenden Arithmetik kostenlos.



  • jetzt funktioniert es endlich!

    hab vergessenen rhw zu interpolieren und es einfach uninitialisiert gelassen - dummer weiße auch keine variable not initalized Warnung erhalten...

    Software vs. OpenGL:
    http://loop.servehttp.com/~vertexwahn/uploads/clipping/software_screenshot_cl.png http://loop.servehttp.com/~vertexwahn/uploads/clipping/opengl_screenshot_cl.png

    Das mit dem Guard-Band war mir bisher unbekannt

    Danke für eurere Hilfe!


Log in to reply