Ejemplo n.º 1
0
        // public void DrawLine(Vector2 point0, Vector2 point1)
        // {
        //     var dist = (point1 - point0).Length();
        //
        //     // If the distance between the 2 points is less than 2 pixels
        //     // We're exiting
        //     if (dist < 2)
        //         return;
        //
        //     // Find the middle point between first & second point
        //     Vector2 middlePoint = point0 + (point1 - point0)/2;
        //     // We draw this point on screen
        //     DrawPoint(middlePoint);
        //     // Recursive algorithm launched between first & middle point
        //     // and between middle & second point
        //     DrawLine(point0, middlePoint);
        //     DrawLine(middlePoint, point1);
        // }

        // public void DrawBLine(Vector2 point0, Vector2 point1)
        // {
        //     var x0 = (int)point0.X;
        //     var y0 = (int)point0.Y;
        //     var x1 = (int)point1.X;
        //     var y1 = (int)point1.Y;
        //
        //     var dx = Math.Abs(x1 - x0);
        //     var dy = Math.Abs(y1 - y0);
        //     var sx = (x0 < x1) ? 1 : -1;
        //     var sy = (y0 < y1) ? 1 : -1;
        //     var err = dx - dy;
        //
        //     while (true) {
        //         DrawPoint(new Vector2(x0, y0));
        //
        //         if ((x0 == x1) && (y0 == y1))
        //             break;
        //         var e2 = 2 * err;
        //         if (e2 > -dy) { err -= dy;
        //             x0 += sx;
        //         }
        //         if (e2 < dx) { err += dx;
        //             y0 += sy;
        //         }
        //     }
        // }

        // drawing line between 2 points from left to right
        // papb -> pcpd
        // pa, pb, pc, pd must then be sorted before
        private void ProcessScanLine(ScanLineData data, Vertex va, Vertex vb, Vertex vc, Vertex vd, Color4 color, Texture texture)
        {
            var pa = va.Coordinates;
            var pb = vb.Coordinates;
            var pc = vc.Coordinates;
            var pd = vd.Coordinates;

            // Thanks to current Y, we can compute the gradient to compute others values like
            // the starting X (sx) and ending X (ex) to draw between
            // if pa.Y == pb.Y or pc.Y == pd.Y, gradient is forced to 1
            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;

            var sx = (int)Interpolate(pa.X, pb.X, gradient1);
            var ex = (int)Interpolate(pc.X, pd.X, gradient2);

            // starting Z & ending Z
            var z1 = Interpolate(pa.Z, pb.Z, gradient1);
            var 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);

            // Interpolating texture coordinates on Y
            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);

            // drawing a line from left (sx) to right (ex)
            for (var x = sx; x < ex; x++)
            {
                var gradient = (x - sx) / (float)(ex - sx);

                // Interpolating Z, normal and texture coordinates on X
                var z     = Interpolate(z1, z2, gradient);
                var ndotl = Interpolate(snl, enl, gradient);
                // changing the color value using the cosine of the angle
                // between the light vector and the normal vector
                // DrawPoint(new Vector3(x, data.currentY, z), color * ndotl);

                var u = Interpolate(su, eu, gradient);
                var v = Interpolate(sv, ev, gradient);

                var textureColor = texture?.Map(u, v) ?? new Color4(1, 1, 1, 1);

                // changing the native color value using the cosine of the angle
                // between the light vector and the normal vector
                // and the texture color
                DrawPoint(new Vector3(x, data.CurrentY, z), color * ndotl * textureColor);
            }
        }
Ejemplo n.º 2
0
        private void DrawTriangle(Vertex v1, Vertex v2, Vertex v3, Color4 color, Texture texture)
        {
            // Sorting the points in order to always have this order on screen p1, p2 & p3
            // with p1 always up (thus having the Y the lowest possible to be near the top screen)
            // then p2 between p1 & p3
            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;
            }

            var p1 = v1.Coordinates;
            var p2 = v2.Coordinates;
            var p3 = v3.Coordinates;

            // Light position
            var lightPos = new Vector3(0, 10, 10);
            // computing the cos of the angle between the light vector and the normal vector
            // it will return a value between 0 and 1 that will be used as the intensity of the color
            var nl1 = ComputeNDotL(v1.WorldCoordinates, v1.Normal, lightPos);
            var nl2 = ComputeNDotL(v2.WorldCoordinates, v2.Normal, lightPos);
            var nl3 = ComputeNDotL(v3.WorldCoordinates, v3.Normal, lightPos);

            var data = new ScanLineData();


            // inverse slopes
            float dP1P2, dP1P3;

            // Computing inverse 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;
            }

            // First case where triangles are like that:
            // P1
            // -
            // --
            // - -
            // -  -
            // -   - P2
            // -  -
            // - -
            // -
            // P3
            if (dP1P2 > dP1P3)
            {
                // for (var y = (int)p1.Y; y <= (int)p3.Y; y++)
                // {
                //     if (y < p2.Y)
                //     {
                //         ProcessScanLine(y, p1, p3, p1, p2, color);
                //     }
                //     else
                //     {
                //         ProcessScanLine(y, p1, p3, p2, p3, color);
                //     }
                // }

                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;
                        ProcessScanLine(data, v1, v3, v1, v2, color, texture);
                    }
                    else
                    {
                        data.Ndotla = nl1;
                        data.Ndotlb = nl3;
                        data.Ndotlc = nl2;
                        data.Ndotld = nl3;
                        ProcessScanLine(data, v1, v3, v2, v3, color, texture);
                    }
                }
            }
            // First case where triangles are like that:
            //       P1
            //        -
            //       --
            //      - -
            //     -  -
            // P2 -   -
            //     -  -
            //      - -
            //        -
            //       P3
            else
            {
                // for (var y = (int)p1.Y; y <= (int)p3.Y; y++)
                // {
                //     if (y < p2.Y)
                //     {
                //         ProcessScanLine(y, p1, p2, p1, p3, color);
                //     }
                //     else
                //     {
                //         ProcessScanLine(y, p2, p3, p1, p3, color);
                //     }
                // }

                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;
                        ProcessScanLine(data, v1, v2, v1, v3, color, texture);
                    }
                    else
                    {
                        data.Ndotla = nl2;
                        data.Ndotlb = nl3;
                        data.Ndotlc = nl1;
                        data.Ndotld = nl3;
                        ProcessScanLine(data, v2, v3, v1, v3, color, texture);
                    }
                }
            }

            //if (dP1P2 > dP1P3)
            //{
            //    Parallel.For((int)p1.Y, (int)p3.Y + 1, y =>
            //        {
            //            if (y < p2.Y)
            //            {
            //                ProcessScanLine(y, p1, p3, p1, p2, color);
            //            }
            //            else
            //            {
            //                ProcessScanLine(y, p1, p3, p2, p3, color);
            //            }
            //        });
            //}
            //else
            //{
            //    Parallel.For((int)p1.Y, (int)p3.Y + 1, y =>
            //        {
            //            if (y < p2.Y)
            //            {
            //                ProcessScanLine(y, p1, p2, p1, p3, color);
            //            }
            //            else
            //            {
            //                ProcessScanLine(y, p2, p3, p1, p3, color);
            //            }
            //        });
            //}
        }