protected override void _CollectMesh(Matrix4 transMat, int w, int h, RenderType rt, List <IPosLight> lights, AddPixelHandler handler) { if (_pointList.Count != VertexNumber) { return; } GraphPragma.DrawTriangle(transMat, _pointList[0], _pointList[1], _pointList[2], MaterialName, w, h, rt, lights, handler); }
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; } }
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); }
protected bool _HandleOnePoint(Matrix4 transformMat, int w, int h, AddPixelHandler handler) { int pointCount = _pointList.Count; if (pointCount < 2) { // 只有一个点就画一个点; for (int i = 0; i < pointCount; ++i) { Vertex vertex = _pointList[i]; // 将3d坐标投影到2d空间; Vertex2D point = GraphPragma.ProjectToScreen(vertex.Position, transformMat, (float)w, (float)h); point.color = vertex.Color; // 添加像素点; if (null != handler) { handler(point.x, point.y, 0, vertex.Color); } } return(true); } return(false); }
protected override void _CollectMesh(Matrix4 transMat, int w, int h, RenderType rt, List <IPosLight> lights, AddPixelHandler handler) { if (_pointList.Count % 2 != 0) { return; } Camera camera = Camera.Default; if (null == camera) { return; } int pointCount = _pointList.Count - 1; for (int i = 0; i < pointCount; i += 2) { Vertex v0 = _pointList[i]; Vertex v1 = _pointList[i + 1]; Vertex2D p0 = GraphPragma.BuildVertex2D(v0, transMat, camera.Pos, lights, w, h); Vertex2D p1 = GraphPragma.BuildVertex2D(v1, transMat, camera.Pos, lights, w, h); Line.DrawLine(p0, p1, handler, DrawLineType.Bresenham, SoftDevice.Default.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; } } }
protected virtual void _CollectMesh(Matrix4 transMat, int w, int h, RenderType rt, List <IPosLight> lights, AddPixelHandler handler) { Camera camera = Camera.Default; if (null == camera) { return; } Vertex vertex1, vertex2; Vertex2D point1, point2; int pointCount = _pointList.Count - 1; for (int i = 0; i < pointCount; ++i) { vertex1 = _pointList[i]; vertex2 = _pointList[i + 1]; // 将3d坐标投影到2d空间; point1 = GraphPragma.BuildVertex2D(vertex1, transMat, camera.Pos, lights, w, h); point2 = GraphPragma.BuildVertex2D(vertex2, transMat, camera.Pos, lights, w, h); // 计算线段; Line.DrawLine(point1, point2, handler, DrawLineType.Bresenham, SoftDevice.Default.ZTest); } vertex1 = _pointList[_pointList.Count - 1]; vertex2 = _pointList[0]; point1 = GraphPragma.BuildVertex2D(vertex1, transMat, camera.Pos, lights, w, h); point2 = GraphPragma.BuildVertex2D(vertex2, transMat, camera.Pos, lights, w, h); Line.DrawLine(point1, point2, handler, DrawLineType.Bresenham, SoftDevice.Default.ZTest); }
public void CollectVertex(Matrix4 transMat, int w, int h, RenderType rt, List <IPosLight> lights, AddPixelHandler handler) { if (_HandleOnePoint(transMat, w, h, handler)) { return; } // 多于一个点就可以连线了; _CollectMesh(transMat, w, h, rt, lights, handler); }
public static void DrawTriangle(Matrix4 transMat, Vertex v0, Vertex v1, Vertex v2, string matName, int w, int h, RenderType rt, List <IPosLight> lights, AddPixelHandler handler) { Camera camera = Camera.Default; if (null == camera || (rt != RenderType.WireFrame && camera.BackfaceBeCulled(v0.worldPosition, v1.worldPosition, v2.worldPosition))) { // 剔除掉了v0-v1-v2组成的三角形; return; } Material mat = MaterialManager.Instance[matName]; // 裁剪,在摄像机空间中进行; // 将顶点变换到摄像机空间; Vector3 viewPos0 = camera.viewMatrix * v0.worldPosition; Vector3 viewPos1 = camera.viewMatrix * v1.worldPosition; Vector3 viewPos2 = camera.viewMatrix * v2.worldPosition; bool p0Inside = false, p1Inside = false, p2Inside = false; int outsideNum = camera.VisibleTest(viewPos0, viewPos1, viewPos2, ref p0Inside, ref p1Inside, ref p2Inside); if (outsideNum >= Shape.Triangle.VertexNumber) { // 三个点都在视距外,整个裁剪掉; return; } // 只会有2种情况; if (outsideNum == 1) { Vector3 newv0, newv1, newv2; // 重排顶点顺序; Shape.Triangle.SortVertexByViewInfo(true, viewPos0, viewPos1, viewPos2, p0Inside, p1Inside, p2Inside, ref v0, ref v1, ref v2, out newv0, out newv1, out newv2); // v0-v2,插值计算v02; Vertex newv02 = Vertex.Origin; MathUtil.IntersectVertexByDist(v0, v2, newv0, newv2, camera.Near, (pos, norm, uv, color) => { newv02 = new Vertex(pos, norm, color, uv); }); // v1-v2,插值计算v12; Vertex newv12 = Vertex.Origin; MathUtil.IntersectVertexByDist(v1, v2, newv1, newv2, camera.Near, (pos, norm, uv, color) => { newv02 = new Vertex(pos, norm, color, uv); }); // 新三角形 v0-v02-v12; DrawTriangle(transMat, v0, newv02, newv12, mat.Texture, w, h, rt, lights, handler); // 新三角形 v0-v12-v1; DrawTriangle(transMat, v0, newv12, v1, mat.Texture, w, h, rt, lights, handler); } else if (outsideNum == 2) { Vector3 newv0, newv1, newv2; // 重排顶点顺序 Shape.Triangle.SortVertexByViewInfo(false, viewPos0, viewPos1, viewPos2, p0Inside, p1Inside, p2Inside, ref v0, ref v1, ref v2, out newv0, out newv1, out newv2); // v0-v1,插值计算v01; MathUtil.IntersectVertexByDist(v0, v1, newv0, newv1, camera.Near, (pos, norm, uv, color) => { v1 = new Vertex(pos, norm, color, uv); }); // v0-v2,插值计算v02; MathUtil.IntersectVertexByDist(v0, v2, newv0, newv2, camera.Near, (pos, norm, uv, color) => { v2 = new Vertex(pos, norm, color, uv); }); // 新三角形 v0-v1-v2; DrawTriangle(transMat, v0, v1, v2, mat.Texture, w, h, rt, lights, handler); } else { // 无需裁剪,三角形 v0-v1-v2; DrawTriangle(transMat, v0, v1, v2, mat.Texture, w, h, rt, lights, handler); } }
public static void DrawTriangle(Matrix4 transMat, Vertex v0, Vertex v1, Vertex v2, Texture tex, int width, int height, RenderType rt, List <IPosLight> lights, AddPixelHandler handler) { Camera camera = Camera.Default; if (null == camera) { return; } // 将3d坐标投影到2d空间; Vertex2D p0 = BuildVertex2D(v0, transMat, camera.Pos, lights, width, height); Vertex2D p1 = BuildVertex2D(v1, transMat, camera.Pos, lights, width, height); Vertex2D p2 = BuildVertex2D(v2, transMat, camera.Pos, lights, width, height); switch (rt) { case RenderType.WireFrame: // 计算线段; Line.DrawLine(p0, p1, handler, DrawLineType.Bresenham, SoftDevice.Default.ZTest); Line.DrawLine(p1, p2, handler, DrawLineType.Bresenham, SoftDevice.Default.ZTest); Line.DrawLine(p2, p0, handler, DrawLineType.Bresenham, SoftDevice.Default.ZTest); break; case RenderType.Solid: // 填充三角形; _VertexPragma(tex, p0, p1, p2, handler); break; } }
private static void _VertexPragma(Texture tex, Vertex2D p1, Vertex2D p2, Vertex2D p3, AddPixelHandler handler) { // 检测顶点序列并进行排序; if (!Shape.Triangle.CheckAndSortVertexSequence(ref p1, ref p2, ref p3)) { return; } // 排序后p1总在上方,p3总在最下方,也就是说扫描时是从[p1.y-p3.y]生成横向扫描线; // 接下来需要判断p2在p1的左面还是右面; float dP1P2, dP1P3 = 0; if (p2.y - p1.y > 0) { dP1P2 = (float)(p2.x - p1.x) / (float)(p2.y - p1.y); } else { dP1P2 = 0; // p1和p2在同一水平线; } if (p3.y - p1.y > 0) { dP1P3 = (float)(p3.x - p1.x) / (float)(p3.y - p1.y); } else { dP1P3 = 0; } // 开始进行纵向扫描; if (dP1P2 > dP1P3) { // 在右侧时的情况,横向扫描线从p1-p3进入; // P1 ; // |\ ; // |_\p2 ; // | / ; // |/ ; // p3 ; Parallel.For(p1.y, p3.y + 1, y => { if (y < p2.y) { // 横向扫描上半部分,扫描线从p1-p2离开; _PixelPragma(tex, y, p1, p3, p1, p2, handler); } else { // 横向扫描下半部分,扫描线从p2-p3离开; _PixelPragma(tex, y, p1, p3, p2, p3, handler); } }); } else { // 在左侧时的情况; // P1 ; // /| ; // p2/_| ; // \ | ; // \| ; // p3 ; Parallel.For(p1.y, p3.y + 1, y => { if (y < p2.y) { // 横向扫描上半部分,扫描线从p1-p2进入,从p1-p3离开; _PixelPragma(tex, y, p1, p2, p1, p3, handler); } else { // 横向扫描上半部分,扫描线从p2-p3进入,从p1-p3离开; _PixelPragma(tex, y, p2, p3, p1, p3, handler); } }); } }
private static void _PixelPragma(Texture tex, int y, Vertex2D pa, Vertex2D pb, Vertex2D pc, Vertex2D pd, AddPixelHandler handler) { // 计算y位置上横向扫描线的起始和结束; SoftDevice device = SoftDevice.Default; if (null == device) { return; } HorizonScanLine scanLine = default(HorizonScanLine); if (!HorizonScanLine.InterpolateWithVertex2D(y, pa, pb, pc, pd, LightUtil.enableLightings, ref scanLine)) { return; } int leftX = scanLine.left; int rightX = scanLine.right; // 有可能出现pb.x > pd.x的情况,这里做下容错; if (leftX > rightX) { scanLine.SwapLeftRight(); } // 开始横向扫描生成像素点; bool usePerZ = device.PerspectiveCorrection; float invxLength = scanLine.InvLength; Vector2 uv = Vector2.zero; Color surfaceColor = Color.Zero; for (var x = leftX; x < rightX; x++) { float gradient = (float)(x - leftX) * invxLength; if (gradient < 0) { gradient = 0; } else if (gradient > 1) { gradient = 1; } float z = scanLine.leftZ + (scanLine.rightZ - scanLine.leftZ) * gradient; // 提前做ztest; if (!device.ZTest(x, y, z)) { continue; } float invZ = 0f; if (z <= MathUtil.Epsilon && z >= -MathUtil.Epsilon) { invZ = 1f; } else { invZ = 1f / z; } // 纹理映射; if (MaterialManager.enableTextures) { if (null != tex) { uv = scanLine.leftUV + (scanLine.rightUV - scanLine.leftUV) * gradient; // 这里使用透视修正后,离的足够近也会出问题; if (usePerZ) { surfaceColor = tex.GetColor(uv.x * invZ, uv.y * invZ); } else { surfaceColor = tex.GetColor(uv.x, uv.y); } } } else { surfaceColor = scanLine.leftColor + (scanLine.rightColor - scanLine.leftColor) * gradient; } if (LightUtil.enableLightings) { Color diffuse = MathUtil.Interpolate(scanLine.leftDiffuse, scanLine.rightDiffuse, gradient); if (usePerZ) { diffuse *= invZ; } surfaceColor = Color.Multiply(surfaceColor, diffuse); } if (null != handler) { handler(x, y, z, surfaceColor); } } }