public void Render() { zTable = new double[DBitmap.Width, DBitmap.Height]; var surf = new SurfaceInfo { Ka = Ka, Kd = Kd, Ks = Ks, N_shiny = N_shiny }; ResetZTable(); var pMatrix = ProjectionMatrix; var vMatrix = SelectedCamera.ViewMatrix; foreach (var light in Lights) { light.Process(vMatrix); } foreach (var shape in Shapes) { shape.IsRender = true; var mMatrix = shape.ModelMatrix; var vmMatrix = vMatrix.Multiply(mMatrix); foreach (var side in shape.SideTriangles) { side.Process(vmMatrix); var v = side.Position; var n = side.Normal; if (side.Points[0].Z > 0 && side.Points[1].Z > 0 && side.Points[2].Z > 0) { continue; } if (n[0] * v[0] + n[1] * v[1] + n[2] * v[2] <= 0) { side.DrawSide(DBitmap, pMatrix, DBitmap.Width / 2, zTable, surf, Lights, ShadingMode); } } shape.IsRender = false; } }
public static Color PhongeIllumination(Vector <double> position, Vector <double> normal, ColorInfo colorInfo, SurfaceInfo surface, List <Light> lights) { ColorInfo outcome = new ColorInfo { R = 0, G = 0, B = 0 }; //ambient outcome.R += colorInfo.R * surface.Ka; outcome.G += colorInfo.G * surface.Ka; outcome.B += colorInfo.B * surface.Ka; foreach (var light in lights) { if (!light.IsOn) { continue; } double spotlightFactor = 1; var l = light.CalculateLVector(position); if (light.IsSpotLight) { var cos = (-light.ProcessedDirection).DotProduct(l); if (cos > 0) { spotlightFactor = Math.Pow(cos, light.P); } else { spotlightFactor = 0; } } //diffuse var lightNormalAngle = normal.DotProduct(l); var diffuseR = surface.Kd * lightNormalAngle * spotlightFactor; if (lightNormalAngle < 0) { continue; } outcome.R += colorInfo.R * diffuseR; outcome.G += colorInfo.G * diffuseR; outcome.B += colorInfo.B * diffuseR; //sepcular var v = (-position).Normalize(2); var r = 2 * lightNormalAngle * normal - l; r = r.Normalize(2); var cameraRAngle = r.DotProduct(v); if (cameraRAngle < 0) { continue; } var specularR = surface.Ks * Math.Pow(cameraRAngle, surface.N_shiny) * spotlightFactor; outcome.R += specularR; outcome.G += specularR; outcome.B += specularR; } if (outcome.R > 1) { outcome.R = 1; } if (outcome.G > 1) { outcome.G = 1; } if (outcome.B > 1) { outcome.B = 1; } return(ColorInfo2Color(outcome)); }
public static void Fill(DirectBitmap bitmap, List <Point> points, Color color, List <double> zs, double[,] Ztable, List <Vector <double> > positions, List <Vector <double> > normals, SurfaceInfo surface, List <Light> lights, ShadingMode shadingMode = ShadingMode.Flat) { int margin = 500; var maxY = points.Max(x => x.Y); if (maxY < -margin || maxY > bitmap.Height + margin) { return; } var minY = points.Min(x => x.Y); if (minY < -margin || minY > bitmap.Height + margin) { return; } var maxX = points.Max(x => x.X); if (maxX < -margin || maxX > bitmap.Width + margin) { return; } var minX = points.Min(x => x.X); if (minX < -margin || minX > bitmap.Width + margin) { return; } var etTable = new List <EdgeStruct> [maxY - minY + 1]; var area = GetAreaInv(points[0], points[1], points[2]); for (int i = 0; i < points.Count; i++) { var p1 = points[i]; var p2 = points[i + 1 == points.Count ? 0 : i + 1]; if (p1.Y == p2.Y) { continue; } if (p1.Y > p2.Y) { var tmp = p2; p2 = p1; p1 = tmp; } //double slp; var str = new EdgeStruct { YMax = p2.Y, X = p1.Y < p2.Y ? p1.X : p2.X, Slope = (double)(p1.X - p2.X) / (p1.Y - p2.Y) }; if (etTable[p1.Y - minY] == null) { etTable[p1.Y - minY] = new List <EdgeStruct>(); } etTable[p1.Y - minY].Add(str); } var aetTable = new List <EdgeStruct>(); int y = minY; Color shadingCol = color; if (shadingMode == ShadingMode.Flat) { var middle = positions[0].Add(positions[1]).Add(positions[2]).Multiply(1.0 / 3); var sideNormal = normals[0].Add(normals[1]).Add(normals[2]).Normalize(2); shadingCol = PhongeIllumination(middle, sideNormal, Color2ColorInfo(color), surface, lights); } var firstColor = Color.Blue; var secondColor = Color.Red; var thirdColor = Color.Green; if (shadingMode == ShadingMode.Gouraud) { firstColor = PhongeIllumination(positions[0], normals[0], Color2ColorInfo(color), surface, lights); secondColor = PhongeIllumination(positions[1], normals[1], Color2ColorInfo(color), surface, lights); thirdColor = PhongeIllumination(positions[2], normals[2], Color2ColorInfo(color), surface, lights); } while (y <= maxY) { if (etTable[y - minY] != null) { var tempList = etTable[y - minY]; //foreach (var edge in tempList) //{ // //if(edge.Slope < 0) // edge.X = edge.X - (edge.YMax - y) * edge.Slope; //} aetTable.AddRange(tempList); } aetTable = aetTable.OrderBy(x => x.X).ToList(); for (int i = 0; i < aetTable.Count; i += 2) { if (aetTable.Count - i == 1) { continue; } var first = aetTable[i]; var second = aetTable[i + 1]; for (int j = (int)(first.X); j < second.X; j++) { if (!(j >= 0 && j < bitmap.Width && y >= 0 && y < bitmap.Height)) { continue; } var w = GetBaricentricRatio(j, y, points[0], points[1], points[2], area); if (w.Item1 < 0 || w.Item2 < 0 || w.Item3 < 0) { continue; } var z = zs[0] * w.Item1 + zs[1] * w.Item2 + zs[2] * w.Item3; if (z < Ztable[j, y]) { Ztable[j, y] = z; if (shadingMode == ShadingMode.Gouraud) { var gR = firstColor.R * w.Item1 + secondColor.R * w.Item2 + thirdColor.R * w.Item3; var gG = firstColor.G * w.Item1 + secondColor.G * w.Item2 + thirdColor.G * w.Item3; var gB = firstColor.B * w.Item1 + secondColor.B * w.Item2 + thirdColor.B * w.Item3; shadingCol = Color.FromArgb((int)gR, (int)gG, (int)gB); } if (shadingMode == ShadingMode.Phong) { var normal = normals[0] * w.Item1 + normals[1] * w.Item2 + normals[2] * w.Item3; normal = normal.Normalize(2); var position = positions[0] * w.Item1 + positions[1] * w.Item2 + positions[2] * w.Item3; shadingCol = PhongeIllumination(position, normal, Color2ColorInfo(color), surface, lights); } bitmap.SetPixel(j, y, shadingCol); } } } foreach (var edge in aetTable.ToList()) { if (edge.YMax == y + 1) { aetTable.Remove(edge); } else { edge.X += edge.Slope; } } y++; } }
public void DrawSide(DirectBitmap bitmap, Matrix <double> projectionMatrix, int radius, double [,] zTable, SurfaceInfo surface, List <Light> lights, ShadingMode shadingMode) { var pos = GetPositions(); var norms = GetNormals(); Process(projectionMatrix, false); var convPoints = new List <Point>(); var zPoints = new List <double>(); foreach (var point in Points) { convPoints.Add(new Point((int)((point.X + 1) * radius), (int)((point.Y + 1) * radius))); zPoints.Add(point.Z); } var sMode = shadingMode; if (IsGlowing) { sMode = ShadingMode.None; } Helpers.Fill(bitmap, convPoints, paintColor, zPoints, zTable, pos, norms, surface, lights, sMode);; }