Пример #1
0
 /// <summary>
 /// Translates each Vertices.Default's position vector by the specified amounts in the x, y, and z directions.
 /// </summary>
 /// <param name="vertices">Any array of vertices.</param>
 /// <param name="x">The x-position offset to be applied.</param>
 /// <param name="y">The y-position offset to be applied.</param>
 /// <param name="z">The z-position offset to be applied.</param>
 /// <returns>The translated Vertices.Default array.</returns>
 public static Vertex.Default[] Translate(this Vertex.Default[] vertices, float x, float y, float z)
 {
     Vertex.Default[] translated = new Vertex.Default[vertices.Length];
     Vector3 translation = new Vector3(x, y, z);
     for (int a = 0; a < vertices.Length; a++)
     {
         translated[a] = vertices[a];
         translated[a].Position += translation;
     }
     return translated;
 }
Пример #2
0
        /// <summary>
        /// Generates a geodesic sphere of unit radius centered on (0, 0, 0). Vertices are not shared.
        /// <para> </para>
        /// Spheres are generated by tessellating icosahedron geometry and setting all vertices to unit distance from the origin <para/>
        /// in model space. Higher tessellation factors increase the smoothness of the sphere but quickly become computationally <para/>
        /// expensive. It is therefore recommended that this parameter not exceed a value of 8.
        /// </summary>
        /// <param name="n">The number of tessellations to perform on the icosahedron geometry.</param>
        /// <returns>The Vertex.Default array that constructs the sphere.</returns>
        public static Vertex.Default[] Sphere(uint n)
        {
            Vertex.Default[] icoVerts = Icosahedron();
            List<Vertex.Default> vertices = new List<Vertex.Default>();
            for (int a = 0; a < icoVerts.Length; a += 3)
            {
                Vertex.Default[] verts = new Vertex.Default[] { icoVerts[a], icoVerts[a + 1], icoVerts[a + 2] };

                for (int b = 0; b < n; b++)
                    verts = Tessellate(verts);

                for (int b = 0; b < verts.Length; b++)
                    verts[b].Position.Normalize();

                CalculateSphericalUV(ref verts);
                vertices.AddRange(verts);

                //for (int b = 0; b < verts.Length; b++)
                //{
                //	verts[b].Position.Normalize();
                //	CalculateSphericalUV(ref verts[b]);
                //	vertices.Add(verts[b]);
                //}
            }

            Vertex.Default[] sphere = vertices.ToArray();
            Vertex.Default.CalculateVertexNormals(ref sphere);
            return sphere;
        }
Пример #3
0
        /// <summary>
        /// Subdivides one or more triangles into four new triangles with unshared vertices.
        /// <para> </para>
        /// This function tessellates a triangle into four equal-sized, new triangles whose vertices are coplanar with the original. <para/>
        /// Thus, for every three inputted vertices, 12 vertices are returned since vertices are not shared. To create additional <para/>
        /// subdivisions, simply call this function repeatedly on the output.
        /// </summary>
        /// <param name="vertices">A list of vertices that sequentially build triangles.</param>
        /// <returns>A new list of vertices representing the tessellated version of the input triangles.</returns>
        public static Vertex.Default[] Tessellate(this Vertex.Default[] vertices)
        {
            if (vertices.Length % 3 != 0)
                throw new ArgumentException("The number of inputted vertices must be a multiple of 3 so as to constitute a triangle list.");

            int nTriangles = vertices.Length / 3;

            int idx = 0;
            Vertex.Default[] tessellated = new Vertex.Default[nTriangles * 12];
            for (int a = 0; a < vertices.Length; a += 3)
            {
                var p1 = vertices[a].Position + (0.5f * (vertices[a + 1].Position - vertices[a].Position));
                var p2 = vertices[a].Position + (0.5f * (vertices[a + 2].Position - vertices[a].Position));
                var p3 = vertices[a + 1].Position + (0.5f * (vertices[a + 2].Position - vertices[a + 1].Position));

                var v01 = new Vertex.Default(p1.X, p1.Y, p1.Z);
                var v02 = new Vertex.Default(p2.X, p2.Y, p2.Z);
                var v12 = new Vertex.Default(p3.X, p3.Y, p3.Z);

                tessellated[idx++] = vertices[a];
                tessellated[idx++] = v01;
                tessellated[idx++] = v02;

                tessellated[idx++] = v01;
                tessellated[idx++] = vertices[a + 1];
                tessellated[idx++] = v12;

                tessellated[idx++] = v01;
                tessellated[idx++] = v12;
                tessellated[idx++] = v02;

                tessellated[idx++] = v02;
                tessellated[idx++] = v12;
                tessellated[idx++] = vertices[a + 2];
            }

            return tessellated;
        }
Пример #4
0
        /// <summary>
        /// Rotates each Vertices.Default's position vector by the specified angles around the x, y, and z axes.
        /// </summary>
        /// <param name="vertices">Any array of vertices.</param>
        /// <param name="pitch">The x-axis rotation angle in radians to be applied.</param>
        /// <param name="yaw">The y-axis rotation angle in radians to be applied.</param>
        /// <param name="roll">The z-axis rotation angle in radians to be applied.</param>
        /// <returns>The rotated Vertices.Default array.</returns>
        public static Vertex.Default[] Rotate(this Vertex.Default[] vertices, float pitch, float yaw, float roll)
        {
            Vertex.Default[] rotated = new Vertex.Default[vertices.Length];

            Vector3 position;
            Matrix3x3 transform = YawTransform(yaw) * PitchTransform(pitch) * RollTransform(roll);
            for (int a = 0; a < vertices.Length; a++)
            {
                rotated[a] = vertices[a];
                position = rotated[a].Position;
                rotated[a].Position.X = Vector3.Dot(transform.Row1, position);
                rotated[a].Position.Y = Vector3.Dot(transform.Row2, position);
                rotated[a].Position.Z = Vector3.Dot(transform.Row3, position);

                rotated[a].Normal.X = Vector3.Dot(transform.Row1, rotated[a].Normal);
                rotated[a].Normal.Y = Vector3.Dot(transform.Row2, rotated[a].Normal);
                rotated[a].Normal.Z = Vector3.Dot(transform.Row3, rotated[a].Normal);
                rotated[a].Normal.Normalize();
            }
            return rotated;
        }
Пример #5
0
 /// <summary>
 /// Scales each Vertices.Default's position vector by the specified amounts in the x, y, and z directions.
 /// </summary>
 /// <param name="vertices">Any array of vertices.</param>
 /// <param name="x">The x-position multiplier to be applied.</param>
 /// <param name="y">The y-position multiplier to be applied.</param>
 /// <param name="z">The z-position multiplier to be applied.</param>
 /// <returns>The scaled Vertices.Default array.</returns>
 public static Vertex.Default[] Scale(this Vertex.Default[] vertices, float x, float y, float z)
 {
     Vertex.Default[] scaled = new Vertex.Default[vertices.Length];
     for (int a = 0; a < vertices.Length; a++)
     {
         scaled[a] = vertices[a];
         scaled[a].Position.X *= x;
         scaled[a].Position.Y *= y;
         scaled[a].Position.Z *= z;
     }
     return scaled;
 }
Пример #6
0
        /// <summary>
        /// Generates a regular icosahedron of unit radius centered on (0, 0, 0). Vertices are shared.
        /// </summary>
        /// <returns>The Vertex.Default array that constructs the icosahedron.</returns>
        public static Vertex.Default[] Icosahedron()
        {
            Vertex.Default[] v = new Vertex.Default[]
            {
                new Vertex.Default( 0.525731f,			0,  0.850651f), // 1
                new Vertex.Default(-0.525731f,			0,  0.850651f), // 0
                new Vertex.Default(			0,  0.850651f,  0.525731f), // 4

                new Vertex.Default(			0,  0.850651f,  0.525731f), // 4
                new Vertex.Default(-0.525731f,			0,  0.850651f),	// 0
                new Vertex.Default(-0.850651f,  0.525731f,			0), // 9

                new Vertex.Default(			0,  0.850651f,  0.525731f), // 4
                new Vertex.Default(-0.850651f,  0.525731f,			0), // 9
                new Vertex.Default(			0,  0.850651f, -0.525731f), // 5

                new Vertex.Default( 0.850651f,  0.525731f,			0), // 8
                new Vertex.Default(			0,  0.850651f,  0.525731f), // 4
                new Vertex.Default(			0,  0.850651f, -0.525731f), // 5

                new Vertex.Default( 0.525731f,			0,  0.850651f), // 1
                new Vertex.Default(			0,  0.850651f,  0.525731f), // 4
                new Vertex.Default( 0.850651f,  0.525731f,			0), // 8

                new Vertex.Default( 0.525731f,			0,  0.850651f), // 1
                new Vertex.Default( 0.850651f,  0.525731f,			0), // 8
                new Vertex.Default( 0.850651f, -0.525731f,			0), // 10

                new Vertex.Default( 0.850651f, -0.525731f,			0), // 10
                new Vertex.Default( 0.850651f,  0.525731f,			0), // 8
                new Vertex.Default( 0.525731f,			0, -0.850651f), // 3

                new Vertex.Default( 0.850651f,  0.525731f,			0), // 8
                new Vertex.Default(			0,  0.850651f, -0.525731f), // 5
                new Vertex.Default( 0.525731f,			0, -0.850651f), // 3

                new Vertex.Default( 0.525731f,			0, -0.850651f), // 3
                new Vertex.Default(			0,  0.850651f, -0.525731f), // 5
                new Vertex.Default(-0.525731f,			0, -0.850651f), // 2

                new Vertex.Default( 0.525731f,			0, -0.850651f), // 3
                new Vertex.Default(-0.525731f,			0, -0.850651f), // 2
                new Vertex.Default(			0, -0.850651f, -0.525731f), // 7

                new Vertex.Default( 0.525731f,			0, -0.850651f), // 3
                new Vertex.Default(			0, -0.850651f, -0.525731f), // 7
                new Vertex.Default( 0.850651f, -0.525731f,			0), // 10

                new Vertex.Default( 0.850651f, -0.525731f,			0), // 10
                new Vertex.Default(			0, -0.850651f, -0.525731f), // 7
                new Vertex.Default(			0, -0.850651f,  0.525731f), // 6

                new Vertex.Default(			0, -0.850651f,  0.525731f), // 6
                new Vertex.Default(			0, -0.850651f, -0.525731f), // 7
                new Vertex.Default(-0.850651f, -0.525731f,			0), // 11

                new Vertex.Default(			0, -0.850651f,  0.525731f), // 6
                new Vertex.Default(-0.850651f, -0.525731f,			0), // 11
                new Vertex.Default(-0.525731f,			0,  0.850651f),	// 0

                new Vertex.Default(			0, -0.850651f,  0.525731f), // 6
                new Vertex.Default(-0.525731f,			0,  0.850651f),	// 0
                new Vertex.Default( 0.525731f,			0,  0.850651f), // 1

                new Vertex.Default( 0.850651f, -0.525731f,			0), // 10
                new Vertex.Default(			0, -0.850651f,  0.525731f), // 6
                new Vertex.Default( 0.525731f,			0,  0.850651f), // 1

                new Vertex.Default(-0.850651f, -0.525731f,			0), // 11
                new Vertex.Default(-0.850651f,  0.525731f,			0), // 9
                new Vertex.Default(-0.525731f,			0,  0.850651f),	// 0

                new Vertex.Default(-0.525731f,			0, -0.850651f), // 2
                new Vertex.Default(-0.850651f,  0.525731f,			0), // 9
                new Vertex.Default(-0.850651f, -0.525731f,			0), // 11

                new Vertex.Default(			0,  0.850651f, -0.525731f), // 5
                new Vertex.Default(-0.850651f,  0.525731f,			0), // 9
                new Vertex.Default(-0.525731f,			0, -0.850651f), // 2

                new Vertex.Default(-0.850651f, -0.525731f,			0), // 11
                new Vertex.Default(			0, -0.850651f, -0.525731f), // 7
                new Vertex.Default(-0.525731f,			0, -0.850651f), // 2
            };

            CalculateSphericalUV(ref v);
            Vertex.Default.CalculateVertexNormals(ref v);
            return v;
        }
Пример #7
0
        /// <summary>
        /// Generates a regular icosahedron of unit radius centered on (0, 0, 0). Vertices are shared.
        /// </summary>
        /// <param name="indices">An ordered list of indices that tell the GPU how to construct the icosahedron.</param>
        /// <returns>The Vertex.Default array that constructs the icosahedron.</returns>
        public static Vertex.Default[] Icosahedron(out uint[] indices)
        {
            indices = new uint[]
            {
                1,0,4,  4,0,9,  4,9,5,  8,4,5,  1,4,8,
                1,8,10, 10,8,3, 8,5,3,  3,5,2,  3,2,7,
                3,7,10, 10,7,6, 6,7,11, 6,11,0, 6,0,1,
                10,6,1, 11,9,0, 2,9,11, 5,9,2,  11,7,2
            };

            var vertices = new Vertex.Default[]
            {
                new Vertex.Default(-0.525731f,			0,  0.850651f), // 0
                new Vertex.Default( 0.525731f,			0,  0.850651f), // 1
                new Vertex.Default(-0.525731f,			0, -0.850651f), // 2
                new Vertex.Default( 0.525731f,			0, -0.850651f), // 3
                new Vertex.Default(			0,  0.850651f,  0.525731f), // 4
                new Vertex.Default(			0,  0.850651f, -0.525731f), // 5
                new Vertex.Default(			0, -0.850651f,  0.525731f), // 6
                new Vertex.Default(			0, -0.850651f, -0.525731f), // 7
                new Vertex.Default( 0.850651f,  0.525731f,			0), // 8
                new Vertex.Default(-0.850651f,  0.525731f,			0), // 9
                new Vertex.Default( 0.850651f, -0.525731f,			0), // 10
                new Vertex.Default(-0.850651f, -0.525731f,			0), // 11
            };

            CalculateSphericalUV(ref vertices);
            Vertex.Default.CalculateVertexNormals(ref vertices, indices);
            return vertices;
        }
Пример #8
0
        /// <summary>
        /// Generates an evenly distributed grid of vertices that plot the elevations found in the inputted heightmap.
        /// <para> </para>
        /// This function generates a grid of vertices where each vertex represents an element of the inputted heightmap matrix. The <para/> 
        /// output is a flattened series of vertices that are ordered by the secondary ouput indices. Together these produce <para/>
        /// counterclockwise wound triangles that can be used to build a mesh. The flattened vertex array proceeds sequentially along <para/>
        /// columns and then along rows (i.e. in row-major form) of the heightmap after it has been flipped across the row dimension. <para/>
        /// This is done so that the appearance of a rendered mesh matches how the heightmap would apepar in image space. Normal <para/>
        /// vectors are generated automatically by this function.
        /// </summary>
        /// <param name="indices">An ordered list of indices that tell the GPU how to construct the heightmap.</param>
        /// <param name="heightmap">A matrix of elevation values for each X and Y coordinate pair.</param>
        /// <returns>An array of vertices that can be used to generate a 3D mesh of the heightmap.</returns>
        public static Vertex.Default[] Heightmap(out uint[] indices, float[,] heightmap)
        {
            heightmap = heightmap.Flip();

            int h = heightmap.GetLength(0);
            int w = heightmap.GetLength(1);
            int numel = h * w;

            indices = new uint[(h - 1) * (w - 1) * 6];
            Vertex.Default[] vertices = new Vertex.Default[numel];
            List<Vector3>[] norms = new List<Vector3>[numel];

            // Initialize the vertices corresponding with the first row of the heightmap
            for (int a = 0; a < w; a++)
            {
                vertices[a] = new Vertex.Default(a, heightmap[0, a], 0);
                norms[a] = new List<Vector3>();
            }

            // Initialize the vertices corresponding with the first column of the heightmap
            for (int a = 1; a < h; a++)
            {
                vertices[a * w] = new Vertex.Default(0, heightmap[a, 0], a);
                norms[a * w] = new List<Vector3>();
            }

            float u, v;
            uint idxIDs = 0;
            uint idxLL, idxLR, idxUL, idxUR;
            Vector3 diff1, diff2;
            for (int a = 0; a < h - 1; a++)
                for (int b = 0; b < w - 1; b++)
                {
                    // Calculate vertex linear array indices (combinations of Upper, Lower, Left, Right)
                    idxLL = (uint)(a * w + b);
                    idxLR = (uint)(a * w + b + 1);
                    idxUL = (uint)((a + 1) * w + b);
                    idxUR = (uint)((a + 1) * w + b + 1);

                    // Set the position & texture coordinates of the next lower-right vertex (others initialized by previous passes)
                    u = (float)b / (float)w;
                    v = (float)a / (float)h;
                    vertices[idxUR] = new Vertex.Default(b + 1, heightmap[a + 1, b + 1], a + 1, 0, 0, 0, u, v);
                    norms[idxUR] = new List<Vector3>();

                    // Determine the indices of counterclockwise winding
                    indices[idxIDs] = idxUL;
                    indices[idxIDs + 1] = idxLL;
                    indices[idxIDs + 2] = idxLR;
                    indices[idxIDs + 3] = idxUL;
                    indices[idxIDs + 4] = idxLR;
                    indices[idxIDs + 5] = idxUR;
                    idxIDs += 6;

                    // Add normals for the upper-left vertex
                    diff1 = vertices[idxUL].Position - vertices[idxLL].Position;
                    diff2 = vertices[idxUR].Position - vertices[idxLL].Position;
                    norms[idxLL].Add(Vector3.Normalize(Vector3.Cross(diff1, diff2)));

                    // Add normals for the upper-left vertex (second triangle of the grid quad)
                    diff1 = vertices[idxUR].Position - vertices[idxLL].Position;
                    diff2 = vertices[idxLR].Position - vertices[idxLL].Position;
                    norms[idxLL].Add(Vector3.Normalize(Vector3.Cross(diff1, diff2)));

                    // Add normals for the lower-left vertex
                    diff1 = vertices[idxUR].Position - vertices[idxUL].Position;
                    diff2 = vertices[idxLL].Position - vertices[idxUL].Position;
                    norms[idxUL].Add(Vector3.Normalize(Vector3.Cross(diff1, diff2)));

                    // Add normals for the lower-right vertex
                    diff1 = vertices[idxLL].Position - vertices[idxUR].Position;
                    diff2 = vertices[idxUL].Position - vertices[idxUR].Position;
                    norms[idxUR].Add(Vector3.Normalize(Vector3.Cross(diff1, diff2)));

                    // Add normals for the upper-left vertex (second triangle of the grid quad)
                    diff1 = vertices[idxLR].Position - vertices[idxUR].Position;
                    diff2 = vertices[idxLL].Position - vertices[idxUR].Position;
                    norms[idxUR].Add(Vector3.Normalize(Vector3.Cross(diff1, diff2)));

                    // Add normals for the upper-right vertex
                    diff1 = vertices[idxLL].Position - vertices[idxLR].Position;
                    diff2 = vertices[idxUR].Position - vertices[idxLR].Position;
                    norms[idxLR].Add(Vector3.Normalize(Vector3.Cross(diff1, diff2)));
                }

            // Average together the various normals found in the above loops
            Vector3 ctsum;
            for (int a = 0; a < norms.Length; a++)
            {
                ctsum = Vector3.Zero;
                foreach (Vector3 norm in norms[a])
                    ctsum += norm;
                vertices[a].Normal = ctsum / norms[a].Count;
            }

            return vertices;
        }
Пример #9
0
        /// <summary>
        /// Generates a cylinder of unit radius centered on (0, 0, 0) and extending one unit along the positive Y axis. Vertices are shared.
        /// </summary>
        /// <param name="indices">An ordered list of indices that tell the GPU how to construct the cylinder.</param>
        /// <param name="n">The number of quad faces that will be used to approximate the cylinder's circular profile.</param>
        /// <returns>The Vertex.Default array that constructs the cylinder.</returns>
        public static Vertex.Default[] Cylinder(out uint[] indices, int n)
        {
            indices = new uint[6 * n];
            Vertex.Default[] vertices = new Vertex.Default[n * 2];
            float angleIncrement = Constants.TwoPi / n;

            for (int a = 0; a < n; a++)
            {
                float ctangle = angleIncrement * a;
                float ntangle = angleIncrement * (a + 1);

                float x1 = (float)Math.Cos(ctangle);
                float z1 = (float)Math.Sin(ctangle);
                float x2 = (float)Math.Cos(ntangle);
                float z2 = (float)Math.Sin(ntangle);

                vertices[a * 2] = new Vertex.Default(x1, 1, z1);
                vertices[a * 2 + 1] = new Vertex.Default(x1, 0, z1);

                indices[a * 6] = (uint)(a * 2);
                indices[a * 6 + 1] = (uint)(a * 2 + 1);
                indices[a * 6 + 2] = (uint)(a * 2 + 3);
                indices[a * 6 + 3] = (uint)(a * 2);
                indices[a * 6 + 4] = (uint)(a * 2 + 3);
                indices[a * 6 + 5] = (uint)(a * 2 + 2);
            }

            indices[n * 6 - 4] = 1;
            indices[n * 6 - 2] = 1;
            indices[n * 6 - 1] = 0;

            Vertex.Default.CalculateVertexNormals(ref vertices, indices);
            CalculateSphericalUV(ref vertices, indices);

            return vertices;
        }
Пример #10
0
        /// <summary>
        /// Generates a cylinder of unit radius centered on (0, 0, 0) and extending one unit along the positive Y axis. Vertices are not shared.
        /// </summary>
        /// <param name="n">The number of quad faces that will be used to approximate the cylinder's circular profile.</param>
        /// <returns>The Vertex.Default array that constructs the cylinder.</returns>
        public static Vertex.Default[] Cylinder(int n)
        {
            Vertex.Default[] vertices = new Vertex.Default[6 * n];
            float angleIncrement = Constants.TwoPi / n;
            float hAngleIncrement = angleIncrement / 2f;

            for (int a = 0; a < n; a++)
            {
                float ctangle = angleIncrement * a;
                float hangle = ctangle + hAngleIncrement;
                float ntangle = angleIncrement * (a + 1);

                float x1 = (float)Math.Cos(ctangle);
                float z1 = (float)Math.Sin(ctangle);
                float x2 = (float)Math.Cos(ntangle);
                float z2 = (float)Math.Sin(ntangle);

                float nx = (float)Math.Cos(hangle);
                float nz = (float)Math.Sin(hangle);

                vertices[a * 6] = new Vertex.Default(x1, 1, z1, nx, 0, nz);
                vertices[a * 6 + 1] = new Vertex.Default(x1, 0, z1, nx, 0, nz);
                vertices[a * 6 + 2] = new Vertex.Default(x2, 0, z2, nx, 0, nz);
                vertices[a * 6 + 3] = new Vertex.Default(x1, 1, z1, nx, 0, nz);
                vertices[a * 6 + 4] = new Vertex.Default(x2, 0, z2, nx, 0, nz);
                vertices[a * 6 + 5] = new Vertex.Default(x2, 1, z2, nx, 0, nz);
            }

            CalculateSphericalUV(ref vertices);
            return vertices;
        }