private static (byte R, byte G, byte B, byte A) GetPixelColor(Triangle3DElement triangle, Point3D correspPoint, Camera camera, List <ILightSource> lights, List <double> obstructions) { NormalizedVector3D normal = triangle.GetNormalAt(correspPoint); byte R = 0; byte G = 0; byte B = 0; byte A = 0; for (int i = 0; i < triangle.Fill.Count; i++) { Colour col = triangle.Fill[i].GetColour(correspPoint, normal, camera, lights, obstructions); if (col.A == 1) { R = (byte)(col.R * 255); G = (byte)(col.G * 255); B = (byte)(col.B * 255); A = (byte)(col.A * 255); } else { BlendFront(ref R, ref G, ref B, ref A, (byte)(col.R * 255), (byte)(col.G * 255), (byte)(col.B * 255), (byte)(col.A * 255)); } } return(R, G, B, A); }
private static (byte R, byte G, byte B, byte A) GetPixelColorWithShadow(Triangle3DElement triangle, List <ILightSource> lights, IEnumerable <Triangle3DElement> shadowers, Point3D correspPoint, Camera camera) { List <double> pixelObstructions = new List <double>(lights.Count); for (int i = 0; i < lights.Count; i++) { if (!lights[i].CastsShadow) { pixelObstructions.Add(0); } else { pixelObstructions.Add(lights[i].GetObstruction(correspPoint, from el in shadowers where el != triangle select el)); } } byte R = 0; byte G = 0; byte B = 0; byte A = 0; NormalizedVector3D normal = triangle.GetNormalAt(correspPoint); for (int i = 0; i < triangle.Fill.Count; i++) { Colour col = triangle.Fill[i].GetColour(correspPoint, normal, camera, lights, pixelObstructions); if (col.A == 1) { R = (byte)(col.R * 255); G = (byte)(col.G * 255); B = (byte)(col.B * 255); A = (byte)(col.A * 255); } else { BlendFront(ref R, ref G, ref B, ref A, (byte)(col.R * 255), (byte)(col.G * 255), (byte)(col.B * 255), (byte)(col.A * 255)); } } return(R, G, B, A); }
private unsafe void FillTriangle(byte *imageData, Triangle3DElement triangle, Camera camera, List <ILightSource> lights, List <double> obstructions) { Point[] triangle2D = triangle.GetProjection(); int minX = int.MaxValue; int minY = int.MaxValue; int maxX = int.MinValue; int maxY = int.MinValue; for (int i = 0; i < triangle2D.Length; i++) { triangle2D[i] = new Point((triangle2D[i].X - camera.TopLeft.X) / camera.Size.Width * this.RenderWidth, (triangle2D[i].Y - camera.TopLeft.Y) / camera.Size.Height * this.RenderHeight); minX = Math.Min(minX, (int)triangle2D[i].X); minY = Math.Min(minY, (int)triangle2D[i].Y); maxX = Math.Max(maxX, (int)Math.Ceiling(triangle2D[i].X)); maxY = Math.Max(maxY, (int)Math.Ceiling(triangle2D[i].Y)); } minX = Math.Max(minX, 0); minY = Math.Max(minY, 0); maxX = Math.Min(maxX, this.RenderWidth - 1); maxY = Math.Min(maxY, this.RenderHeight - 1); int totalPixels = (maxX - minX + 1) * (maxY - minY + 1); Parallel.For(0, totalPixels, index => { int y = index / (maxX - minX + 1) + minY; int x = index % (maxX - minX + 1) + minX; if (Intersections2D.PointInTriangle(x, y, triangle2D[0], triangle2D[1], triangle2D[2])) { Point3D correspPoint = camera.Deproject(new Point((double)x / this.RenderWidth * camera.Size.Width + camera.TopLeft.X, (double)y / this.RenderHeight * camera.Size.Height + camera.TopLeft.Y), triangle); double zDepth = camera.ZDepth(correspPoint); int prevZIndexBuffer = ZIndexBuffer[y * RenderWidth + x]; if (prevZIndexBuffer < triangle.ZIndex || (prevZIndexBuffer == triangle.ZIndex && ZBuffer[y * RenderWidth + x] > zDepth)) { byte R = 0; byte G = 0; byte B = 0; byte A = 0; for (int i = 0; i < triangle.Fill.Count; i++) { Colour col = triangle.Fill[i].GetColour(correspPoint, triangle.GetNormalAt(correspPoint), camera, lights, obstructions); if (col.A == 1) { R = (byte)(col.R * 255); G = (byte)(col.G * 255); B = (byte)(col.B * 255); A = (byte)(col.A * 255); } else { BlendFront(ref R, ref G, ref B, ref A, (byte)(col.R * 255), (byte)(col.G * 255), (byte)(col.B * 255), (byte)(col.A * 255)); } } if (A == 255) { imageData[y * RenderWidth * 4 + x * 4] = R; imageData[y * RenderWidth * 4 + x * 4 + 1] = G; imageData[y * RenderWidth * 4 + x * 4 + 2] = B; imageData[y * RenderWidth * 4 + x * 4 + 3] = A; } else { BlendFront(ref imageData[y * RenderWidth * 4 + x * 4], ref imageData[y * RenderWidth * 4 + x * 4 + 1], ref imageData[y * RenderWidth * 4 + x * 4 + 2], ref imageData[y * RenderWidth * 4 + x * 4 + 3], R, G, B, A); } ZBuffer[y * RenderWidth + x] = zDepth; ZIndexBuffer[y * RenderWidth + x] = triangle.ZIndex; } else if (imageData[y * RenderWidth * 4 + x * 4 + 3] < 255) { byte R = 0; byte G = 0; byte B = 0; byte A = 0; for (int i = 0; i < triangle.Fill.Count; i++) { Colour col = triangle.Fill[i].GetColour(correspPoint, triangle.GetNormalAt(correspPoint), camera, lights, obstructions); if (col.A == 1) { R = (byte)(col.R * 255); G = (byte)(col.G * 255); B = (byte)(col.B * 255); A = (byte)(col.A * 255); } else { BlendFront(ref R, ref G, ref B, ref A, (byte)(col.R * 255), (byte)(col.G * 255), (byte)(col.B * 255), (byte)(col.A * 255)); } } BlendBack(R, G, B, A, ref imageData[y * RenderWidth * 4 + x * 4], ref imageData[y * RenderWidth * 4 + x * 4 + 1], ref imageData[y * RenderWidth * 4 + x * 4 + 2], ref imageData[y * RenderWidth * 4 + x * 4 + 3]); } } }); }