PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Software-Rasterizer: Near/Far-Clipping


Coda
2007-01-28, 20:33:00
Huhu Leute. Jetzt muss ich auch mal ne Frage stellen, ich hoffe irgendjemand hier kann mir helfen.

Ich bastel grad nen kleinen Software-Rasterizer zum Spaß. Funktioniert soweit auch alles gut, nur hab ich nen Problem wenn Vertices auf die Kamera-Plane fallen (d.h. z=0 im Kamera-Raum). Dann is nämlich w=0 und damit bekomm ich Unendlichkeiten wenn ich die perspektivische Division durchführe.

Man kann auch nicht einfach nach der perspektivischen Division clippen deshalb, weil die Werte mit w=0 einfach Müll ergeben.

Muss man also die Dreiecke noch gegen w<0 clippen? Und wenn ja, wie? Weil w ist ja nicht linear im Screenspace, dann müsste ich 1/w interpolieren beim clippen und dann wieder 1/1/w rechnen oder?

Demirug
2007-01-28, 20:56:44
Per Definition liegen Punkte mit W=0 in der Unendlichkeit und nicht auf der Kamera Plane. Bist du sicher das du nicht irgendwo vorher schon was verdreht hast? In aller Regel sollte nämlich beim Einsatz einer gebräuchlicher Transformation Matrix W=1 heraus kommen.

Coda
2007-01-28, 21:12:00
Okay minimaler Testfall, damit vielleicht besser ersichtlich wird was ich meine:

int main()
{
const float aspect_ratio = 4.0f/3.0f;
const float fov = 70.0f*(pi/360.0f)*2.0f;
const float znear = 0.1f;
const float zfar = 10.0f;

Matrix4f projection_matrix = IDENTITY4F;

const float scaley = 1.0f/tan(fov*0.5f);
const float scalex = scaley / aspect_ratio;

// x = scalex
projection_matrix[0][0] = scalex;

// y = scaley
projection_matrix[1][1] = scaley;

// z = zfar/(zfar-znear)*z' -znear*zfar/(zfar-znear)*w'
projection_matrix[2][2] = zfar/(zfar-znear);
projection_matrix[3][2] = -znear*zfar/(zfar-znear);

// w = z'
projection_matrix[2][3] = 1.0f;
projection_matrix[3][3] = 0.0f;

Vector4f point1 = makeVector4f(2.0f,2.0f,0.1f,1.0f);
Vector4f point2 = makeVector4f(2.0f,2.0f,10.0f,1.0f);
Vector4f point3 = makeVector4f(2.0f,2.0f,0.0f,1.0f);
Vector4f point4 = makeVector4f(2.0f,2.0f,-1.0f,1.0f);

Vector3f transformed_point1 = projectHomogeneous4To3(projection_matrix * point1);
Vector3f transformed_point2 = projectHomogeneous4To3(projection_matrix * point2);
Vector3f transformed_point3 = projectHomogeneous4To3(projection_matrix * point3);
Vector3f transformed_point4 = projectHomogeneous4To3(projection_matrix * point4);

OutputVector(transformed_point1);
OutputVector(transformed_point2);
OutputVector(transformed_point3);
OutputVector(transformed_point4);
}

Ausgabe:

( 21.4222 28.563 0 )
( 0.214222 0.28563 1 )
( 1.#INF 1.#INF -1.#INF ) <- Problem
( -2.14222 -2.8563 1.11111 )

Danach kann ich ja schlecht noch clippen, wenn bei Punkten auf der Kamera-Plane so ein Scheiß rauskommt.

Xmas
2007-01-28, 23:42:08
Per Definition liegen Punkte mit W=0 in der Unendlichkeit und nicht auf der Kamera Plane. Bist du sicher das du nicht irgendwo vorher schon was verdreht hast? In aller Regel sollte nämlich beim Einsatz einer gebräuchlicher Transformation Matrix W=1 heraus kommen.
Ich denke Coda meint im Clipspace, nicht im Viewspace.

Für eine einheitliche Terminologie:

Model/Object Space
-> Model-to-World ->
World Space
-> World-to-View ->
View/Camera/Eye Space
-> Projektion ->
Clip Space (in OpenGL liegt Z in [-W, W], in D3D liegt Z in [0, W])
-> Perspektivdivision ->
Normalized Device Coordinates (NDC; in OpenGL liegt Z in [-1, 1], in D3D liegt Z in [0, 1])
-> Viewport-Transformation ->
Screen/Window Space


Coda, die Kante mit den Viewspace-Punkten A (3, 3, 0, 1) und B (2, 2, 1, 1) sollte ja in deinem Fall am Punkt C (2.9, 2.9, 0.1, 1) geclippt werden. Im Clipspace sind diese Punkte:
A (3, 3, 0, 1) -> A' (3.2133, 4.2845, -0.1010, 0)
B (2, 2, 1, 1) -> B' (2.1422, 2.8563, 0.9091, 1)
C (2.9, 2.9, 0.1, 1) -> C' (3.1062, 4.1416, 0, 0.1)

Da die Anwendung der Projektionsmatrix eine lineare Operation ist, liegen diese Punkte natürlich weiterhin auf einer 4D-Geraden. Der Schnittpunkt C' der Kante mit Zclip = 0 (was Zview = Znear entspricht) ist dann, sofern sich die Vorzeichen von A'z und B'z unterscheiden:
C' = A' * (abs(B'z)/(abs(A'z)+abs(B'z))) + B' * (abs(A'z)/(abs(A'z)+abs(B'z)))

Coda
2007-01-28, 23:57:15
Danke für die Hilfe. Ich hab's jetzt so gelöst, dass ich bevor ich die perspektivische Division mache das Dreieck vorher gegen w=znear clippe. Theoretisch könnte ich auch noch um Arbeit für den Rasterizer zu sparen gegen w=zfar clippen, aber das fängt auch der Z-Buffer schon auf.

Noch ne kleine Frage, falls es jemand auswendig weiß: Stimmt es, dass beim Clipping eines Dreiecks gegen die Clipplanes maximal 7 Vertices entstehen können?

micki
2007-01-29, 00:17:57
Danke für die Hilfe. Ich hab's jetzt so gelöst, dass ich bevor ich die perspektivische Division mache das Dreieck vorher gegen w=znear clippe. Theoretisch könnte ich auch noch um Arbeit für den Rasterizer zu sparen gegen w=zfar clippen, aber das fängt auch der Z-Buffer schon auf.Ja, beim software rasterizer bietet es sich im an alles im Post-projective-spase zu klippen (nach der projektion, vor der division).


Noch ne kleine Frage, falls es jemand auswendig weiß: Stimmt es, dass beim Clipping eines Dreiecks gegen die Clipplanes maximal 7 Vertices entstehen können?Du kannst davon ausgehen, dass pro ebene gegen die du clippst, ein vertex hinzukommen kann.

Xmas
2007-01-29, 02:19:42
Ja, ein Neuneck ist möglich.

Coda
2007-01-29, 14:34:46
Ja, beim software rasterizer bietet es sich im an alles im Post-projective-spase zu klippen (nach der projektion, vor der division).

Also die Seiten sind nach der Division aber einfacher, weil sie dann nicht mehr "schief" sind ;)

Xmas
2007-01-29, 14:38:08
Also die Seiten sind nach der Division aber einfacher, weil sie dann nicht mehr "schief" sind ;)
Wieso schief?

Coda
2007-01-29, 14:39:34
Weil der View-Frustum nunmal kein Würfel ist vor der Division?

Xmas
2007-01-29, 15:07:45
Nunja, ob man nun gegen X=W oder X=1 clipt ...