public void DrawTriangle(Vertex v1, Vertex v2, Vertex v3, Color4 color) { if (v1.Coordinates.Y > v2.Coordinates.Y) { var temp = v2; v2 = v1; v1 = temp; } if (v2.Coordinates.Y > v3.Coordinates.Y) { var temp = v2; v2 = v3; v3 = temp; } if (v1.Coordinates.Y > v2.Coordinates.Y) { var temp = v2; v2 = v1; v1 = temp; } Vector3 p1 = v1.Coordinates; Vector3 p2 = v2.Coordinates; Vector3 p3 = v3.Coordinates; // Light position Vector3 lightPos = new Vector3(0, 10, 10); float nl1 = ComputeNDotL(v1.WorldCoordinates, v1.Normal, lightPos); float nl2 = ComputeNDotL(v2.WorldCoordinates, v2.Normal, lightPos); float nl3 = ComputeNDotL(v3.WorldCoordinates, v3.Normal, lightPos); var data = new ScanLineData { }; float dP1P2, dP1P3; // Computing slopes 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++) { data.currentY = y; if (y < p2.Y) { data.ndotla = nl1; data.ndotlb = nl3; data.ndotlc = nl1; data.ndotld = nl2; data.ua = v1.TextureCoordinates.X; data.ub = v3.TextureCoordinates.X; data.uc = v1.TextureCoordinates.X; data.ud = v2.TextureCoordinates.X; data.va = v1.TextureCoordinates.Y; data.vb = v3.TextureCoordinates.Y; data.vc = v1.TextureCoordinates.Y; data.vd = v2.TextureCoordinates.Y; ProcessScanLine(data, v1, v3, v1, v2, color); } else { data.ndotla = nl1; data.ndotlb = nl3; data.ndotlc = nl2; data.ndotld = nl3; data.ua = v1.TextureCoordinates.X; data.ub = v3.TextureCoordinates.X; data.uc = v2.TextureCoordinates.X; data.ud = v3.TextureCoordinates.X; data.va = v1.TextureCoordinates.Y; data.vb = v3.TextureCoordinates.Y; data.vc = v2.TextureCoordinates.Y; data.vd = v3.TextureCoordinates.Y; ProcessScanLine(data, v1, v3, v2, v3, color); } } } else { for (var y = (int)p1.Y; y <= (int)p3.Y; y++) { data.currentY = y; if (y < p2.Y) { data.ndotla = nl1; data.ndotlb = nl2; data.ndotlc = nl1; data.ndotld = nl3; data.ua = v1.TextureCoordinates.X; data.ub = v2.TextureCoordinates.X; data.uc = v1.TextureCoordinates.X; data.ud = v3.TextureCoordinates.X; data.va = v1.TextureCoordinates.Y; data.vb = v2.TextureCoordinates.Y; data.vc = v1.TextureCoordinates.Y; data.vd = v3.TextureCoordinates.Y; ProcessScanLine(data, v1, v2, v1, v3, color); } else { data.ndotla = nl2; data.ndotlb = nl3; data.ndotlc = nl1; data.ndotld = nl3; data.ua = v2.TextureCoordinates.X; data.ub = v3.TextureCoordinates.X; data.uc = v1.TextureCoordinates.X; data.ud = v3.TextureCoordinates.X; data.va = v2.TextureCoordinates.Y; data.vb = v3.TextureCoordinates.Y; data.vc = v1.TextureCoordinates.Y; data.vd = v3.TextureCoordinates.Y; ProcessScanLine(data, v2, v3, v1, v3, color); } } } }
// drawing line between 2 points from left to right // papb -> pcpd // pa, pb, pc, pd must then be sorted before void ProcessScanLine(ScanLineData data, Vertex va, Vertex vb, Vertex vc, Vertex vd, Color4 color) { Vector3 pa = va.Coordinates; Vector3 pb = vb.Coordinates; Vector3 pc = vc.Coordinates; Vector3 pd = vd.Coordinates; 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); // starting Z & ending Z float z1 = Interpolate(pa.Z, pb.Z, gradient1); float z2 = Interpolate(pc.Z, pd.Z, gradient2); // Interpolating normals on Y var snl = Interpolate(data.ndotla, data.ndotlb, gradient1); var enl = Interpolate(data.ndotlc, data.ndotld, gradient2); var su = Interpolate(data.ua, data.ub, gradient1); var eu = Interpolate(data.uc, data.ud, gradient2); var sv = Interpolate(data.va, data.vb, gradient1); var ev = Interpolate(data.vc, data.vd, gradient2); for (var x = sx; x < ex; x++) { float gradient = (x - sx) / (float)(ex - sx); var z = Interpolate(z1, z2, gradient); var ndotl = Interpolate(snl, enl, gradient); var u = Interpolate(su, eu, gradient); var v = Interpolate(sv, ev, gradient); Color4 textureColor; textureColor = new Color4(1, 1, 1, 1); DrawPoint(new Vector3(x, data.currentY, z), color * ndotl); } }