// Bresenham's line algorithm public void DrawLine(Triangle triangle, Vertex from, Vertex to) { Color lineColor = Color.RoyalBlue; int d, dx, dy, ai, bi, xi, yi; int x1 = from.projectionX, y1 = from.projectionY, x2 = to.projectionX, y2 = to.projectionY; int x = x1, y = y1; // ustalenie kierunku rysowania dx = Math.Abs(x2 - x1); xi = Math.Sign(x2 - x1); dy = Math.Abs(y2 - y1); yi = Math.Sign(y2 - y1); // pierwszy piksel SetPixel(triangle, x, y, lineColor); // oś wiodąca OX if (dx > dy) { ai = (dy - dx) * 2; bi = dy * 2; d = bi - dx; // pętla po kolejnych x while (x != x2) { // test współczynnika if (d >= 0) { x += xi; y += yi; d += ai; } else { d += bi; x += xi; } SetPixel(triangle, x, y, lineColor); } } // oś wiodąca OY else { ai = (dx - dy) * 2; bi = dx * 2; d = bi - dy; // pętla po kolejnych y while (y != y2) { // test współczynnika if (d >= 0) { x += xi; y += yi; d += ai; } else { d += bi; y += yi; } SetPixel(triangle, x, y, lineColor); } } }
public void Fill(IModel model, Triangle triangle) { var indexes = triangle.GetSortedIndexes(); var AET = new List <AETNode>(); int k = 0; Vector <double> N = null; Color constantColor = Color.Empty; Color[] gouraudColors = null; if (model is Cuboid) { N = (model as Cuboid).N(triangle); } switch (shaderType) { case ShaderType.Constant: { var coordinates = Vector <double> .Build.Dense(new double[3] { (triangle.points[0].worldX + triangle.points[1].worldX + triangle.points[2].worldX) / 3.0, (triangle.points[0].worldY + triangle.points[1].worldY + triangle.points[2].worldY) / 3.0, (triangle.points[0].worldZ + triangle.points[1].worldZ + triangle.points[2].worldZ) / 3.0 }); N = triangle.InterpolateN(0.333, 0.333, 0.333); constantColor = ColorCalculation.Phong(coordinates, N, model.Color); break; } case ShaderType.Gouraud: { gouraudColors = new Color[3] { ColorCalculation.Phong(triangle.points[0], model.Color), ColorCalculation.Phong(triangle.points[1], model.Color), ColorCalculation.Phong(triangle.points[2], model.Color) }; break; } } int lowerBound = triangle.points[indexes[0]].projectionY; int upperBound = triangle.points[indexes[2]].projectionY >= canvas.Height ? canvas.Height - 1 : triangle.points[indexes[2]].projectionY; if (lowerBound < 0) { if (upperBound < 0) { return; } lowerBound = 0; AET.Add(new AETNode(triangle.points[indexes[2]], triangle.points[indexes[0]])); if (triangle.points[indexes[1]].projectionY < 0) { AET.Add(new AETNode(triangle.points[indexes[1]], triangle.points[indexes[2]])); k = 2; } else { AET.Add(new AETNode(triangle.points[indexes[0]], triangle.points[indexes[1]])); k = 1; } foreach (var aetNode in AET) { aetNode.x += aetNode.xd * -aetNode.p1.projectionY; } AET.Sort((p1, p2) => (int)(p1.x - p2.x)); } for (int y = lowerBound; y <= upperBound; y++) { while (triangle.points[indexes[k]].projectionY == y - 1) { var prev = triangle.points[Triangle.Prev(indexes[k])]; var current = triangle.points[indexes[k]]; var next = triangle.points[Triangle.Next(indexes[k])]; if (prev.projectionY > current.projectionY) { AET.Add(new AETNode(prev, current)); } else { AET.RemoveAll(aetn => aetn.p2.projectionY == current.projectionY); } if (next.projectionY > current.projectionY) { AET.Add(new AETNode(current, next)); } else { AET.RemoveAll(aetn => aetn.p2.projectionY == current.projectionY); } k++; } if (AET.Count > 0 && AET[1].x < AET[0].x) { AET.Add(AET[0]); AET.RemoveAt(0); } for (int i = 0; i < AET.Count; i += 2) { int xLowerBound = (int)AET[i].x >= 0 ? (int)AET[i].x : 0; int xUpperBound = (int)Math.Round(AET[i + 1].x) < canvas.Width ? (int)Math.Round(AET[i + 1].x) : canvas.Width; for (int x = xLowerBound; x < xUpperBound; x++) { double w0, w1, w2; (w0, w1, w2) = triangle.GetWeights(x, y); double z = triangle.Z(w0, w1, w2); if (z >= zBuffor[x, y]) { zBuffor[x, y] = z; switch (shaderType) { case ShaderType.Constant: canvas.SetPixel(x, y, constantColor); break; case ShaderType.Gouraud: Color gouraudColor = ColorCalculation.Gouraud(gouraudColors, w0, w1, w2); canvas.SetPixel(x, y, gouraudColor); break; case ShaderType.Phong: N = triangle.InterpolateN(w0, w1, w2); Color phongColor = ColorCalculation.Phong(triangle.InterpolateXYZ(w0, w1, w2), N, model.Color); canvas.SetPixel(x, y, phongColor); break; } } } } foreach (var aetn in AET) { aetn.x += aetn.xd; } } if (drawTriangleEdges) { DrawLine(triangle, triangle.points[0], triangle.points[1]); DrawLine(triangle, triangle.points[0], triangle.points[2]); DrawLine(triangle, triangle.points[1], triangle.points[2]); } }