public static List <List <Vector2i> > ScanAlignY(List <Vector2i> poly) { List <List <Vector2i> > results = new List <List <Vector2i> >(); Vector2i max = new Vector2i(int.MinValue, int.MinValue); Vector2i min = new Vector2i(int.MaxValue, int.MaxValue); foreach (Vector2i v in poly) { max = Vector2i.Max(v, max); min = Vector2i.Min(v, min); } List <Vector2i> trans = poly.Select(t => { return(t - min); }).ToList(); int height = max[1] - min[1]; List <ScanEdge> scanLines = new List <ScanEdge>(); int count = trans.Count; int count1 = count - 1; for (int i = 0; i < count; ++i) { Vector2i ps = trans[i]; int post = (i + 1) % count; Vector2i pe = trans[post]; if (ps[1] == pe[1]) // 水平 去掉 { Vector2i hori = Vector2i.GetVector2i(ps[0], pe[0]); List <Vector2i> result = new List <Vector2i>(); for (int hi = hori[0]; hi <= hori[1]; ++hi) { result.Add(new Vector2i(hi, ps[1])); } if (result.Count > 0) { result = result.Select(t => { return(t + min); }).ToList(); results.Add(result); } continue; } int pre = (i + count1) % count; Vector2i pss = trans[pre]; int ppost = (post + 1) % count; Vector2i pee = trans[ppost]; double dx = (ps[0] - pe[0]) * 1.0f / (ps[1] - pe[1]); bool yiG0 = ps[1] < pe[1]; double startX = yiG0 ? ps[0] : pe[0]; int ymin = yiG0 ? ps[1] : pe[1]; int ymax = yiG0 ? pe[1] : ps[1]; if (pe[1] > ps[1]) { if (pee[1] >= pe[1]) { ymax -= 1; } } else { if (pss[1] >= ps[1]) { ymax -= 1; } } ScanEdge ep = new ScanEdge(); ep.mMinY = ymin; ep.mMaxY = ymax; ep.mStartX = startX; ep.mDx = dx; scanLines.Add(ep); } for (int i = 0; i < height; ++i) { List <Vector2i> result = new List <Vector2i>(); List <ScanEdge> tmp = scanLines.FindAll(delegate(ScanEdge line) { return(line.Include(i)); }); tmp.Sort((e1, e2) => { //此处可以不考虑 斜率。 x相等时,不用考虑谁在前谁在后 return(e1.mStartX.CompareTo(e2.mStartX)); }); if (tmp.Count % 2 != 0) { throw new Exception("必须是偶数"); } for (int idx = 0; idx < tmp.Count; idx += 2) { int next = idx + 1; int x1 = (int)tmp[idx].mStartX; int x2 = (int)tmp[next].mStartX; if (x1 > x2) { continue; } for (int xi = x1; xi <= x2; ++xi) { result.Add(new Vector2i(xi, i)); } tmp[idx].Increase(); tmp[next].Increase(); } scanLines.RemoveAll((t) => t.mMaxY == i); if (result.Count > 0) { result = result.Select(t => { return(t + min); }).ToList(); results.Add(result); } } return(results); }
protected void DrawScreenSpaceTriangleInterpolated(PreparedTriangle triangle) { WriteableBitmap rt = _renderWindow.Framebuffer; if (triangle.GetScreenSpaceDirection() != VisibleTriangleDirection) { return; } var triangleArea = CalculateTriangleArea( triangle.Vertices[0].X, triangle.Vertices[0].Y, triangle.Vertices[1].X, triangle.Vertices[1].Y, triangle.Vertices[2].X, triangle.Vertices[2].Y); var vertexX = new double[] { triangle.Vertices[0].X, triangle.Vertices[1].X, triangle.Vertices[2].X }; var vertexY = new double[] { triangle.Vertices[0].Y, triangle.Vertices[1].Y, triangle.Vertices[2].Y }; var scanEdges = new List <ScanEdge>(); for (int current = 0; current < 3; ++current) { int next = (current + 1) % 3; double higherx, highery; double lowerx, lowery; if (vertexY[current] < vertexY[next]) { higherx = vertexX[current]; highery = vertexY[current]; lowerx = vertexX[next]; lowery = vertexY[next]; } else { higherx = vertexX[next]; highery = vertexY[next]; lowerx = vertexX[current]; lowery = vertexY[current]; } int minY = (int)highery; int maxY = (int)lowery; //int startX = (int)higherx; //int endX = (int)lowerx; if (minY == maxY) { continue; } var scanEdge = new ScanEdge(); scanEdge.MinimalY = (int)Math.Ceiling(highery); scanEdge.MaximalY = (int)Math.Ceiling(lowery); scanEdge.X = higherx; scanEdge.XSlope = (lowerx - higherx) / ((double)(lowery - highery)); scanEdges.Add(scanEdge); } if (scanEdges.Count == 0) { return; } scanEdges = scanEdges.OrderBy(t => t.MinimalY).ToList(); int scanEdgesActivated = 0; var startY = Math.Max(scanEdges.Min(t => t.MinimalY), 0); var endY = Math.Min(scanEdges.Max(t => t.MaximalY), rt.PixelHeight - 1); var activeEdges = new List <ScanEdge>(); for (var y = startY; y <= endY; ++y) { activeEdges = activeEdges.Where(t => y < t.MaximalY).ToList(); while (scanEdgesActivated < scanEdges.Count) { if (y < scanEdges[scanEdgesActivated].MinimalY) { break; } activeEdges.Add(scanEdges[scanEdgesActivated]); ++scanEdgesActivated; } activeEdges = activeEdges.OrderBy(t => t.X).ToList(); for (int i = 0; i < activeEdges.Count - 1; i += 2) { int startX = (int)Math.Ceiling(Math.Max(activeEdges[i].X, 0)); int endX = (int)Math.Floor(Math.Min(activeEdges[i + 1].X, rt.PixelWidth - 1)); for (int x = startX; x <= endX; ++x) { var aArea = CalculateTriangleArea( x, y, triangle.Vertices[1].X, triangle.Vertices[1].Y, triangle.Vertices[2].X, triangle.Vertices[2].Y); var bArea = CalculateTriangleArea( triangle.Vertices[0].X, triangle.Vertices[0].Y, x, y, triangle.Vertices[2].X, triangle.Vertices[2].Y); var cArea = CalculateTriangleArea( triangle.Vertices[0].X, triangle.Vertices[0].Y, triangle.Vertices[1].X, triangle.Vertices[1].Y, x, y); var fa = Math.Min(aArea / triangleArea, 1.0); var fb = Math.Min(bArea / triangleArea, 1.0); var fc = Math.Min(cArea / triangleArea, 1.0); if (fa + fb + fc > 1.0) { int lowestAreaIndex = 0; double lowestArea = fa; if (lowestArea > fb) { lowestAreaIndex = 1; lowestArea = fb; } if (lowestArea > fc) { lowestAreaIndex = 2; lowestArea = fc; } switch (lowestAreaIndex) { case 0: fa = 1.0 - fb - fc; break; case 1: fb = 1.0 - fa - fc; break; case 2: fc = 1.0 - fa - fb; break; } } var z = fa * triangle.Vertices[0].Z + fb * triangle.Vertices[1].Z + fc * triangle.Vertices[2].Z; if (z <= 1.0) { continue; } if (_zBuffer[x, y] > z) { continue; } _zBuffer[x, y] = z; // Pixel Shader Color outputColor = InterpolateColor( fa, triangle.Vertices[0].VertexColor, fb, triangle.Vertices[1].VertexColor, fc, triangle.Vertices[2].VertexColor); if (TexturingEnabled && Material.DiffuseTexture != null) { var u = fa * triangle.Vertices[0].U + fb * triangle.Vertices[1].U + fc * triangle.Vertices[2].U; var v = fa * triangle.Vertices[0].V + fb * triangle.Vertices[1].V + fc * triangle.Vertices[2].V; u = Math.Min(Math.Max(u, 0.0), 1.0); v = Math.Min(Math.Max(v, 0.0), 1.0); Color texColor = Material.DiffuseTexture.GetPixel((int)(u * Material.DiffuseTexture.PixelWidth), (int)(v * Material.DiffuseTexture.PixelHeight)); outputColor = MultiplyColors(outputColor, texColor); } // End of pixel shader rt.SetPixel(x, y, outputColor); } } activeEdges.ForEach(t => t.X += t.XSlope); } }