public static void DrawDDALine(Vertex2D p1, Vertex2D p2, AddPixelHandler handler, ZTestHandler zTest) { var dist = (p1 - p2).Length2D; // 如果长度小于2像素就只是一个点; if (dist < 2) { if (null != zTest && !zTest(p1.x, p1.y, p1.depth)) { return; } handler?.Invoke(p1.x, p1.y, p1.depth, p1.color); return; } // 绘制中心点; Vertex2D center = p1 + (p2 - p1) / 2; float depth = MathUtil.Interpolate(p1.depth, center.depth, 0.5f); if (null != zTest && !zTest(center.x, center.y, depth)) { return; } // 颜色线性插值; Color clr = Color.FromArgb( (p1.color.a + p2.color.a) * 0.5f, (p1.color.r + p2.color.r) * 0.5f, (p1.color.g + p2.color.g) * 0.5f, (p1.color.b + p2.color.b) * 0.5f); if (null != handler) { handler(center.x, center.y, MathUtil.Interpolate(p1.depth, center.depth, 0.5f), clr); } // 前半段递归; DrawDDALine(p1, center, handler, zTest); // 后半段递归; DrawDDALine(center, p2, handler, zTest); }
public static void DrawBresenhamLine(Vertex2D p1, Vertex2D p2, AddPixelHandler handler, ZTestHandler zTest) { // Bresenham’s line algorithm; int x1 = p1.x; int y1 = p1.y; int x2 = p2.x; int y2 = p2.y; var dx = Math.Abs(x2 - x1); var dy = Math.Abs(y2 - y1); var sx = (x1 < x2) ? 1 : -1; var sy = (y1 < y2) ? 1 : -1; var err = dx - dy; float totalLen = (p1 - p2).SqrLength2D; if (totalLen <= 0f) { return; } float invTotalLen = 1f / totalLen; float p1x = p1.x; float p1y = p1.y; float p1d = p1.depth; float p2d = p2.depth; Color p1c = p1.color; Color p2c = p2.color; while (true) { float p1x1 = p1x - x1; float p1y1 = p1y - y1; float len = p1x1 * p1x1 + p1y1 * p1y1; float ratio = len * invTotalLen; // MathUtil.Clamp(len / totalLen); ratio = ratio < 0 ? 0 : ratio; ratio = ratio > 1 ? 1 : ratio; float z1 = p1d + (p2d - p1d) * ratio; //MathUtil.Interpolate(p1.Depth, p2.Depth, ratio); if (null != zTest && zTest(x1, y1, z1)) { float a = p1c.a * ratio + p2c.a * (1f - ratio); float r = p1c.r * ratio + p2c.r * (1f - ratio); float g = p1c.g * ratio + p2c.g * (1f - ratio); float b = p1c.b * ratio + p2c.b * (1f - ratio); Color clr = Color.FromArgb(a, r, g, b); if (null != handler) { handler(x1, y1, z1, clr); } } if ((x1 == x2) && (y1 == y2)) { break; } int e2 = 2 * err; if (e2 > -dy) { err -= dy; x1 += sx; } if (e2 < dx) { err += dx; y1 += sy; } } }
public static void DrawLine(Vertex2D p1, Vertex2D p2, AddPixelHandler handler, DrawLineType drawType, ZTestHandler zTest) { switch (drawType) { case DrawLineType.DDA: DrawDDALine(p1, p2, handler, zTest); break; case DrawLineType.Bresenham: DrawBresenhamLine(p1, p2, handler, zTest); break; } }