Пример #1
0
        public void DrawTriangle(Vertex v1, Vertex v2, Vertex v3, Color4 color)
        {
            // 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;
            }

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

            // Light position 
            Vector3 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
            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 { };

            // computing lines' directions
            float dP1P2, dP1P3;

            // http://en.wikipedia.org/wiki/Slope
            // 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;
                        ProcessScanLine(data, v1, v3, v1, v2, color);
                    }
                    else
                    {
                        data.ndotla = nl1;
                        data.ndotlb = nl3;
                        data.ndotlc = nl2;
                        data.ndotld = nl3;
                        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;
                        ProcessScanLine(data, v1, v2, v1, v3, color);
                    }
                    else
                    {
                        data.ndotla = nl2;
                        data.ndotlb = nl3;
                        data.ndotlc = nl1;
                        data.ndotld = nl3;
                        ProcessScanLine(data, v2, v3, v1, v3, color);
                    }
                }
            }
        }
Пример #2
0
        // 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;

            // 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;

            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);

            var snl = Interpolate(data.ndotla, data.ndotlb, gradient1);
            var enl = Interpolate(data.ndotlc, data.ndotld, gradient2);

            // drawing a line from left (sx) to right (ex) 
            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);
                // 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);
            }
        }
Пример #3
0
        // Project takes some 3D coordinates and transform them
        // in 2D coordinates using the transformation matrix
        // It also transform the same coordinates and the norma to the vertex 
        // in the 3D world
        public Vertex Project(Vertex vertex, Matrix transMat, Matrix world)
        {
            // transforming the coordinates into 2D space
            var point2d = Vector3.TransformCoordinate(vertex.Coordinates, transMat);
            // transforming the coordinates & the normal to the vertex in the 3D world
            var point3dWorld = Vector3.TransformCoordinate(vertex.Coordinates, world);
            var normal3dWorld = Vector3.TransformCoordinate(vertex.Normal, world);

            // The transformed coordinates will be based on coordinate system
            // starting on the center of the screen. But drawing on screen normally starts
            // from top left. We then need to transform them again to have x:0, y:0 on top left.
            var x = point2d.X * renderWidth + renderWidth / 2.0f;
            var y = -point2d.Y * renderHeight + renderHeight / 2.0f;

            return new Vertex
            {
                Coordinates = new Vector3(x, y, point2d.Z),
                Normal = normal3dWorld,
                WorldCoordinates = point3dWorld
            };
        }
Пример #4
0
 public Mesh(string name, int verticesCount, int facesCount)
 {
     Vertices = new Vertex[verticesCount];
     Faces = new Face[facesCount];
     Name = name;
 }
Пример #5
0
        public static Mesh LoadOBJ(string objFile)
        {
            StreamReader   reader   = new StreamReader(File.OpenRead(objFile));
            List <Vector3> vertices = new List <Vector3>();
            List <Vector3> normals  = new List <Vector3>();
            List <Vector2> uvs      = new List <Vector2>();
            List <Tuple <int, int, int>[]> faces = new List <Tuple <int, int, int>[]>();

            while (!reader.EndOfStream)
            {
                string   line   = reader.ReadLine();
                string[] tokens = line.Split(' ').Skip(1).SkipWhile(t => t == string.Empty).ToArray();
                if (line.StartsWith("#"))
                {
                    continue;
                }
                else if (line.StartsWith("vn"))
                {
                    float x = float.Parse(tokens[0]);
                    float y = float.Parse(tokens[1]);
                    float z = float.Parse(tokens[2]);
                    normals.Add(new Vector3(x, y, z));
                }
                else if (line.StartsWith("vt"))
                {
                    float x = float.Parse(tokens[0]);
                    float y = float.Parse(tokens[1]);
                    uvs.Add(new Vector2(x, y));
                }
                else if (line.StartsWith("v"))
                {
                    float x = float.Parse(tokens[0]);
                    float y = float.Parse(tokens[1]);
                    float z = float.Parse(tokens[2]);
                    vertices.Add(new Vector3(x, y, z));
                }
                else if (line.StartsWith("f"))
                {
                    Tuple <int, int, int> v1 = ParseIndicies(tokens[0]);
                    Tuple <int, int, int> v2 = ParseIndicies(tokens[1]);
                    Tuple <int, int, int> v3 = ParseIndicies(tokens[2]);
                    faces.Add(new Tuple <int, int, int>[3] {
                        v1, v2, v3
                    });
                    if (tokens.Length > 3)
                    {
                        Tuple <int, int, int> v4 = ParseIndicies(tokens[3]);
                        faces.Add(new Tuple <int, int, int>[3] {
                            v1, v3, v4
                        });
                    }
                }
            }

            List <Vertex> modelVerts = new List <Vertex>();
            List <Face>   modelFaces = new List <Face>();

            for (int i = 0; i < faces.Count; i++)
            {
                Vertex[] faceVerts = new Vertex[3];
                for (int j = 0; j < 3; j++)
                {
                    int vertIdx = faces[i][j].Item1;
                    int uvIdx   = faces[i][j].Item2;
                    int normIdx = faces[i][j].Item3;
                    faceVerts[j] = new Vertex
                    {
                        Coordinates        = vertices[vertIdx],
                        Normal             = (normIdx == -1) ? Vector3.Zero : normals[normIdx],
                        TextureCoordinates = (uvIdx == -1) ? Vector2.Zero : uvs[uvIdx]
                    };
                }
                modelVerts.AddRange(faceVerts);
                modelFaces.Add(new Face
                {
                    A = i * 3 + 0,
                    B = i * 3 + 1,
                    C = i * 3 + 2
                });
            }

            Mesh mesh = new Mesh("objMesh", modelVerts.Count, modelFaces.Count);

            modelVerts.CopyTo(mesh.Vertices);
            modelFaces.CopyTo(mesh.Faces);

            mesh.ComputeFacesNormals();

            return(mesh);
        }
Пример #6
0
 public Mesh(string name, int verticesCount, int facesCount)
 {
     Vertices = new Vertex[verticesCount];
     Faces    = new Face[facesCount];
     Name     = name;
 }