private void Vertical_Line(int x1, int y1, float z1, int x2, int y2, float z2, Color colour) { float z_increase_y = (z1 - z2) / (y1 - y2); if (y2 < y1) { NumericManipulation.Swap(ref y1, ref y2); NumericManipulation.Swap(ref z1, ref z2); } for (int y = y1; y <= y2; y++) { ZBufferCheck(colour, x1, y, z1); z1 += z_increase_y; } }
private void Horizontal_Line(int x1, int y1, float z1, int x2, int y2, float z2, Color colour) { float z_increase_x = (z1 - z2) / (x1 - x2); if (x2 < x1) { NumericManipulation.Swap(ref x1, ref x2); NumericManipulation.Swap(ref z1, ref z2); } for (int x = x1; x <= x2; x++) { ZBufferCheck(colour, x, y1, z1); z1 += z_increase_x; } }
private void CalculateDepth( Face face, int meshDimension, ref Matrix4x4 modelToView) { // Reset the vertices to model space values face.ResetVertices(); // Move the face from model space to view space face.ApplyMatrix(modelToView); if (meshDimension == 3) { // Discard the face if it is not visible from the light's point of view if ((Vector3D)face.p1 * Vector3D.NormalFromPlane((Vector3D)face.p1, (Vector3D)face.p2, (Vector3D)face.p3) >= 0) { return; } } // Clip the face in view space Queue <Face> faceClip = new(); faceClip.Enqueue(face); if (!Clipping.ClipFaces(faceClip, ViewClippingPlanes)) { return; } // Move the new triangles from view space to screen space, including a correction for perspective foreach (Face clippedFace in faceClip) { clippedFace.ApplyMatrix(ViewToScreen); if (this is PointLight or Spotlight) { clippedFace.p1 /= clippedFace.p1.w; clippedFace.p2 /= clippedFace.p2.w; clippedFace.p3 /= clippedFace.p3.w; } } // Clip the face in screen space if (Settings.Screen_Space_Clip && !Clipping.ClipFaces(faceClip, ScreenClippingPlanes)) { return; } foreach (Face clippedFace in faceClip) { // Don't draw anything if the face is flat if ((clippedFace.p1.x == clippedFace.p2.x && clippedFace.p2.x == clippedFace.p3.x) || (clippedFace.p1.y == clippedFace.p2.y && clippedFace.p2.y == clippedFace.p3.y)) { continue; } // Move the new triangles from screen space to window space clippedFace.ApplyMatrix(ScreenToWindow); // Round the vertices int x1 = clippedFace.p1.x.RoundToInt(); int y1 = clippedFace.p1.y.RoundToInt(); float z1 = clippedFace.p1.z; int x2 = clippedFace.p2.x.RoundToInt(); int y2 = clippedFace.p2.y.RoundToInt(); float z2 = clippedFace.p2.z; int x3 = clippedFace.p3.x.RoundToInt(); int y3 = clippedFace.p3.y.RoundToInt(); float z3 = clippedFace.p3.z; // Sort the vertices by their y-co-ordinate NumericManipulation.SortByY ( ref x1, ref y1, ref z1, ref x2, ref y2, ref z2, ref x3, ref y3, ref z3 ); // Interpolate each point in the triangle Interpolation.InterpolateTriangle ( MeshDepthFromLight, null, x1, y1, z1, x2, y2, z2, x3, y3, z3 ); } }
private void AddFaceToZBuffer( Face face, int meshDimension, ref Matrix4x4 modelToView, ref Matrix4x4 viewToScreen, ref Matrix4x4 screenToWindow) { // Reset the vertices to model space values face.ResetVertices(); // Draw outline if needed ?? if (face.DrawOutline) { DrawEdge(face.p1, face.p2, Color.Black, ref modelToView, ref viewToScreen); DrawEdge(face.p1, face.p3, Color.Black, ref modelToView, ref viewToScreen); DrawEdge(face.p2, face.p3, Color.Black, ref modelToView, ref viewToScreen); } // Move the face from model space to view space face.ApplyMatrix(modelToView); if (meshDimension == 3) { // Discard the face if it is not visible from the camera's point of view if ((Vector3D)face.p1 * Vector3D.NormalFromPlane((Vector3D)face.p1, (Vector3D)face.p2, (Vector3D)face.p3) >= 0) { return; } } // Clip the face in view space Queue <Face> faceClip = new(); faceClip.Enqueue(face); if (!Clipping.ClipFaces(faceClip, this.ViewClippingPlanes)) { return; } // Move the new triangles from view space to screen space, including a correction for perspective foreach (Face clippedFace in faceClip) { clippedFace.ApplyMatrix(viewToScreen); if (this is PerspectiveCamera) { clippedFace.p1 /= clippedFace.p1.w; clippedFace.p2 /= clippedFace.p2.w; clippedFace.p3 /= clippedFace.p3.w; if (face.HasTexture) { clippedFace.t1 /= clippedFace.p1.w; clippedFace.t2 /= clippedFace.p2.w; clippedFace.t3 /= clippedFace.p3.w; } } } // Clip the face in screen space if (Settings.Screen_Space_Clip && !Clipping.ClipFaces(faceClip, ScreenClippingPlanes)) { return; } // anything outside cube? foreach (Face clippedFace in faceClip) { // Skip the face if it is flat if ((clippedFace.p1.x == clippedFace.p2.x && clippedFace.p2.x == clippedFace.p3.x) || (clippedFace.p1.y == clippedFace.p2.y && clippedFace.p2.y == clippedFace.p3.y)) { continue; } // Move the new triangles from screen space to window space clippedFace.ApplyMatrix(screenToWindow); // Round the vertices int x1 = clippedFace.p1.x.RoundToInt(); int y1 = clippedFace.p1.y.RoundToInt(); float z1 = clippedFace.p1.z; int x2 = clippedFace.p2.x.RoundToInt(); int y2 = clippedFace.p2.y.RoundToInt(); float z2 = clippedFace.p2.z; int x3 = clippedFace.p3.x.RoundToInt(); int y3 = clippedFace.p3.y.RoundToInt(); float z3 = clippedFace.p3.z; // Check if the face has a texture if (face.HasTexture) { // Scale the texture co-ordinates int textureWidth = face.Texture_Object.File.Width - 1; int textureHeight = face.Texture_Object.File.Height - 1; // afterwards? float tx1 = face.T1.x * textureWidth; float ty1 = face.T1.y * textureHeight; float tz1 = face.T1.z; float tx2 = face.T2.x * textureWidth; float ty2 = face.T2.y * textureHeight; float tz2 = face.T2.z; float tx3 = face.T3.x * textureWidth; float ty3 = face.T3.y * textureHeight; float tz3 = face.T3.z; // Sort the vertices by their y-co-ordinate NumericManipulation.TexturedSortByY ( ref x1, ref y1, ref tx1, ref ty1, ref tz1, ref x2, ref y2, ref tx2, ref ty2, ref tz2, ref x3, ref y3, ref tx3, ref ty3, ref tz3 ); // Generate z-buffer Textured_Triangle ( face.Texture_Object.File, x1, y1, tx1, ty1, tz1, x2, y2, tx2, ty2, tz2, x3, y3, tx3, ty3, tz3 ); } else { // Sort the vertices by their y-co-ordinate NumericManipulation.SortByY ( ref x1, ref y1, ref z1, ref x2, ref y2, ref z2, ref x3, ref y3, ref z3 ); // Generate z-buffer Interpolation.InterpolateTriangle ( ZBufferCheck, face.Colour, x1, y1, z1, x2, y2, z2, x3, y3, z3 ); } } }
// floats or ints for everything? Should it take an average of texels (or pixels in method above)? private void Textured_Triangle(Bitmap texture, int x1, int y1, float tx1, float ty1, float tz1, int x2, int y2, float tx2, float ty2, float tz2, int x3, int y3, float tx3, float ty3, float tz3) { // Create steps float dy_step_1 = y1 - y2; float dy_step_2 = y1 - y3; float dy_step_3 = y2 - y3; float x_step_1 = 0, tx_step_1 = 0, ty_step_1 = 0, tz_step_1 = 0; float x_step_3 = 0, tx_step_3 = 0, ty_step_3 = 0, tz_step_3 = 0; if (dy_step_1 != 0) { x_step_1 = (x1 - x2) / dy_step_1; // dx from point 1 to point 2 tx_step_1 = (tx1 - tx2) / dy_step_1; // dtx from point 1 to point 2 ty_step_1 = (ty1 - ty2) / dy_step_1; // dty from point 1 to point 2 tz_step_1 = (tz1 - tz2) / dy_step_1; // dtz from point 1 to point 2 } float x_step_2 = (x1 - x3) / dy_step_2; // dx from point 1 to point 3 float tx_step_2 = (tx1 - tx3) / dy_step_2; // dtx from point 1 to point 3 float ty_step_2 = (ty1 - ty3) / dy_step_2; // dty from point 1 to point 3 float tz_step_2 = (tz1 - tz3) / dy_step_2; // dtz from point 1 to point 3 if (dy_step_3 != 0) { x_step_3 = (x2 - x3) / dy_step_3; // dx from point 2 to point 3 tx_step_3 = (tx2 - tx3) / dy_step_3; // dtx from point 2 to point 3 ty_step_3 = (ty2 - ty3) / dy_step_3; // dty from point 2 to point 3 tz_step_3 = (tz2 - tz3) / dy_step_3; // dtz from point 2 to point 3 } // Draw a flat-bottom triangle if (dy_step_1 != 0) { for (int y = y2; y <= y1; y++) { int sx = ((y - y2) * x_step_1 + x2).RoundToInt(); int ex = ((y - y3) * x_step_2 + x3).RoundToInt(); float stx = (y - y2) * tx_step_1 + tx2; float sty = (y - y2) * ty_step_1 + ty2; float stz = (y - y2) * tz_step_1 + tz2; float etx = (y - y3) * tx_step_2 + tx3; float ety = (y - y3) * ty_step_2 + ty3; float etz = (y - y3) * tz_step_2 + tz3; // ? if (sx > ex) { NumericManipulation.Swap(ref sx, ref ex); NumericManipulation.Swap(ref stx, ref etx); NumericManipulation.Swap(ref sty, ref ety); NumericManipulation.Swap(ref stz, ref etz); } float t = 0, t_step = 1f / (ex - sx); for (int x = sx; x <= ex; x++) { int tx = (stx + t * (etx - stx)).RoundToInt(); int ty = (sty + t * (ety - sty)).RoundToInt(); float tz = stz + t * (etz - stz); TexturedCheckAgainstZBuffer(texture, x, y, tz, tx, ty); t += t_step; } } } // Draw a flat-top triangle if (dy_step_3 != 0) { for (int y = y3; y <= y2; y++) { int sx = ((y - y3) * x_step_3 + x3).RoundToInt(); int ex = ((y - y3) * x_step_2 + x3).RoundToInt(); float stx = (y - y3) * tx_step_3 + tx3; float sty = (y - y3) * ty_step_3 + ty3; float stz = (y - y3) * tz_step_3 + tz3; float etx = (y - y3) * tx_step_2 + tx3; float ety = (y - y3) * ty_step_2 + ty3; float etz = (y - y3) * tz_step_2 + tz3; if (sx > ex) { NumericManipulation.Swap(ref sx, ref ex); NumericManipulation.Swap(ref stx, ref etx); NumericManipulation.Swap(ref sty, ref ety); NumericManipulation.Swap(ref stz, ref etz); } float t = 0, t_step = 1f / (ex - sx); for (int x = sx; x <= ex; x++) { int tx = (stx + t * (etx - stx)).RoundToInt(); int ty = (sty + t * (ety - sty)).RoundToInt(); float tz = stz + t * (etz - stz); TexturedCheckAgainstZBuffer(texture, x, y, tz, tx, ty); t += t_step; } } } }