public void DrawTriangle_PS(Vertex v1, Vertex v2, Vertex v3, Color color, double Time, Vector3 viewerPos, bool blin = false) { if (v1.Position.y > v2.Position.y) { Swap(ref v1, ref v2); } if (v2.Position.y > v3.Position.y) { Swap(ref v2, ref v3); } if (v1.Position.y > v2.Position.y) { Swap(ref v1, ref v2); } var p1 = v1.Position; var p2 = v2.Position; var p3 = v3.Position; var wp1 = v1.WorldPosition; var wp2 = v2.WorldPosition; var wp3 = v3.WorldPosition; Vector3 lightPos = LP; var data = new ScanLineDataPhong { }; double dP1P2, dP1P3; if (p2.y - p1.y > 0) { dP1P2 = (p2.x - p1.x) / (p2.y - p1.y); } else { dP1P2 = 0; } if (p3.y - p1.y > 0) { dP1P3 = (p3.x - p1.x) / (p3.y - p1.y); } else { dP1P3 = 0; } if (dP1P2 > dP1P3) { for (var y = (int)p1.y; y <= (int)p3.y; y++) { double gradient = (y - p1.y) / (double)(p3.y - p1.y); data.currentWorldY = Interpolate(wp1.y, wp3.y, gradient); data.currentY = y; if (y < p2.y) { data.Na = v1.Normal; data.Nb = v3.Normal; data.Nc = v1.Normal; data.Nd = v2.Normal; ProcessScanLine_PS(data, v1, v3, v1, v2, color, lightPos, viewerPos, blin); } else { data.Na = v1.Normal; data.Nb = v3.Normal; data.Nc = v2.Normal; data.Nd = v3.Normal; ProcessScanLine_PS(data, v1, v3, v2, v3, color, lightPos, viewerPos, blin); } } } else { for (var y = (int)p1.y; y <= (int)p3.y; y++) { double gradient = (y - p1.y) / (double)(p3.y - p1.y); data.currentWorldY = Interpolate(wp1.y, wp3.y, gradient); data.currentY = y; if (y < p2.y) { data.Na = v1.Normal; data.Nb = v2.Normal; data.Nc = v1.Normal; data.Nd = v3.Normal; ProcessScanLine_PS(data, v1, v2, v1, v3, color, lightPos, viewerPos, blin); } else { data.Na = v2.Normal; data.Nb = v3.Normal; data.Nc = v1.Normal; data.Nd = v3.Normal; ProcessScanLine_PS(data, v2, v3, v1, v3, color, lightPos, viewerPos, blin); } } } }
void ProcessScanLine_PS(ScanLineDataPhong data, Vertex A, Vertex B, Vertex C, Vertex D, Color color, Vector3 lightPosition, Vector3 viewerPosition, bool blin) { var pa = A.Position; var pb = B.Position; var pc = C.Position; var pd = D.Position; var wpa = A.WorldPosition; var wpb = B.WorldPosition; var wpc = C.WorldPosition; var wpd = D.WorldPosition; var gradient1 = pa.y != pb.y ? (data.currentY - pa.y) / (pb.y - pa.y) : 1; var gradient2 = pc.y != pd.y ? (data.currentY - pc.y) / (pd.y - pc.y) : 1; int sx = (int)Interpolate(pa.x, pb.x, gradient1); int ex = (int)Interpolate(pc.x, pd.x, gradient2); int swx = (int)Interpolate(wpa.x, wpb.x, gradient1); int ewx = (int)Interpolate(wpc.x, wpd.x, gradient2); double z1 = Interpolate(pa.z, pb.z, gradient1); double z2 = Interpolate(pc.z, pd.z, gradient2); double wz1 = Interpolate(wpa.z, wpb.z, gradient1); double wz2 = Interpolate(wpc.z, wpd.z, gradient2); var sN = InterpolateVector(data.Na, data.Nb, gradient1); var eN = InterpolateVector(data.Nc, data.Nd, gradient2); for (var x = sx; x < ex; x++) { double gradient = (x - sx) / (double)(ex - sx); var z = Interpolate(z1, z2, gradient); var position = new Vector3(x, data.currentY, z); var wx = Interpolate(swx, ewx, gradient); var wy = data.currentWorldY; var wz = Interpolate(wz1, wz2, gradient); var wPosition = new Vector3(wx, wy, wz); var N = InterpolateVector(sN, eN, gradient); var NoL = Compute_NoL(wPosition, N, lightPosition); byte r = 0, g = 0, b = 0; if (blin) { var H = Compute_H(wPosition, viewerPosition, lightPosition); H.Normalize(); var Nnorm = N; Nnorm.Normalize(); var NoH = Vector3.Dot(Nnorm, H); NoH = Math.Pow(NoH, alpha); r = Limit(kd * color.R * NoL + ks * color.R * NoH); g = Limit(kd * color.R * NoL + ks * color.R * NoH); b = Limit(kd * color.R * NoL + ks * color.R * NoH); } else { var R = Compute_R(wPosition, N, lightPosition); R.Normalize(); var V = viewerPosition - wPosition; V.Normalize(); var RoV = OverZero(Vector3.Dot(R, V)); RoV = Math.Pow(RoV, alpha); r = Limit(kd * color.R * NoL + ks * color.R * RoV); g = Limit(kd * color.R * NoL + ks * color.R * RoV); b = Limit(kd * color.R * NoL + ks * color.R * RoV); } var shadedColor = Color.FromArgb(color.A, r, g, b); DrawPoint(position, shadedColor); } }