Beispiel #1
0
        public void AddQuad_QuadAdded_QuadInMesh()
        {
            GeometryConstructor gc = new GeometryConstructor();

            Vector3[] vertices = new Vector3[]
            {
                new Vector3(0, 0, 0),
                new Vector3(0, 1, 0),
                new Vector3(1, 1, 0),
                new Vector3(1, 0, 0)
            };
            int[] expectedTriangles = new int[] { 0, 1, 2, 0, 2, 3 };

            // perform test action
            int v0 = gc.AddVertex(vertices[0]);
            int v1 = gc.AddVertex(vertices[1]);
            int v2 = gc.AddVertex(vertices[2]);
            int v3 = gc.AddVertex(vertices[3]);

            gc.AddQuad(v0, v1, v2, v3);
            Mesh mesh = gc.ConstructMesh();

            // check
            Assert.AreEqual(v0, 0);
            Assert.AreEqual(v1, 1);
            Assert.AreEqual(v2, 2);
            Assert.AreEqual(v3, 3);
            Assert.AreEqual(gc.Vertices.ToArray(), vertices);
            Assert.AreEqual(gc.Triangles.ToArray(), expectedTriangles);
            Assert.AreEqual(mesh.vertices, vertices);
            Assert.AreEqual(mesh.triangles, expectedTriangles);
        }
        /// <summary>
        /// Creates and adds the rim of a rounded corner to the geometry constructor
        /// </summary>
        /// <param name="constructor">The geometry constructor to which the rim of the corner should be added</param>
        /// <param name="endpoints1">Array of size two, containing the vertex index of the first endpoints (seen clockwise from the front)
        /// first entry: front vertex index
        /// second entry: back vertex index</param>
        /// <param name="cornerVertexCoordinates">Front vertex coordinates of the rounded corner</param>
        /// <param name="endpoints2">Array of size two, containing the vertex index of the second endpoints (seen clockwise from the front)
        /// first entry: front vertex index
        /// second entry: back vertex index</param>
        private void CreateCornerRim(GeometryConstructor constructor, int[] endpoints1, Vector3[] cornerVertexCoordinates, int[] endpoints2)
        {
            if (endpoints1.Length != 2 || endpoints2.Length != 2)
            {
                i5Debug.LogError("Expected endpoints array size of 2 but got " + endpoints1.Length + " and " + endpoints2.Length, this);
                return;
            }

            // generate vertex indices
            int[]   frontCornerVertices = new int[subdivisions];
            int[]   backCornerVertices  = new int[subdivisions];
            Vector3 depthVector         = new Vector3(0, 0, depth);

            for (int i = 0; i < subdivisions; i++)
            {
                frontCornerVertices[i] = constructor.AddVertex(cornerVertexCoordinates[i]);
                backCornerVertices[i]  = constructor.AddVertex(cornerVertexCoordinates[i] + depthVector);
            }

            // connect top rim to first corner segment
            constructor.AddQuad(endpoints1[1], backCornerVertices[0], frontCornerVertices[0], endpoints1[0]);
            // connect corner segments
            for (int i = 0; i < subdivisions - 1; i++)
            {
                constructor.AddQuad(backCornerVertices[i], backCornerVertices[i + 1], frontCornerVertices[i + 1], frontCornerVertices[i]);
            }
            // connect last corner segment to right rim
            constructor.AddQuad(backCornerVertices[subdivisions - 1], endpoints2[1], endpoints2[0], frontCornerVertices[subdivisions - 1]);
        }
Beispiel #3
0
        public void AddTriangle_TriangleAdded_TriangleInMesh()
        {
            GeometryConstructor gc = new GeometryConstructor();

            Vector3[] vertices = new Vector3[]
            {
                Vector3.zero,
                new Vector3(0, 1, 0),
                new Vector3(1, 0, 0)
            };
            int[] expectedTriangles = new int[] { 0, 1, 2 };

            int v0 = gc.AddVertex(vertices[0]);
            int v1 = gc.AddVertex(vertices[1]);
            int v2 = gc.AddVertex(vertices[2]);

            gc.AddTriangle(v0, v1, v2);
            Mesh mesh = gc.ConstructMesh();

            // check if the vertex indices are correct
            Assert.AreEqual(v0, expectedTriangles[0]);
            Assert.AreEqual(v1, expectedTriangles[1]);
            Assert.AreEqual(v2, expectedTriangles[2]);
            // check the mesh
            Assert.IsNotNull(mesh);
            Assert.AreEqual(mesh.vertices.Length, 3);
            Assert.AreEqual(mesh.triangles.Length, 3);
            Assert.AreEqual(mesh.vertices, vertices);
            Assert.AreEqual(mesh.triangles, expectedTriangles);
        }
Beispiel #4
0
        public void AddTriangleFan_FanAdded_FanInMesh()
        {
            GeometryConstructor gc = new GeometryConstructor();

            Vector3[] vertices = new Vector3[]
            {
                Vector3.zero,
                new Vector3(-1, -1, 0),
                new Vector3(-1, 1, 0),
                new Vector3(1, 1, 0),
                new Vector3(1, -1, 0)
            };
            int[] indices = new int[vertices.Length];
            for (int i = 0; i < vertices.Length; i++)
            {
                indices[i] = gc.AddVertex(vertices[i]);
            }
            int[] outerVertexIndices = new int[indices.Length - 1];
            Array.Copy(indices, 1, outerVertexIndices, 0, indices.Length - 1);
            gc.AddTriangleFan(indices[0], outerVertexIndices);
            Mesh mesh = gc.ConstructMesh();

            // check
            Assert.AreEqual(gc.Vertices.ToArray(), vertices);
            int[] expectedTriangles = new int[]
            {
                0, 1, 2,
                0, 2, 3,
                0, 3, 4,
            };
            Assert.AreEqual(gc.Triangles.ToArray(), expectedTriangles);
            Assert.AreEqual(mesh.vertices, vertices);
            Assert.AreEqual(mesh.triangles, expectedTriangles);
        }
Beispiel #5
0
        public void AddVertex_OneVertexAdded_VertexStored()
        {
            GeometryConstructor gc = new GeometryConstructor();
            int index = gc.AddVertex(Vector3.one);

            Assert.AreEqual(gc.Vertices.Count, 1);
            Assert.AreEqual(gc.Vertices[0], Vector3.one);
            Assert.AreEqual(index, 0);
        }
Beispiel #6
0
        public void ConstructMesh_NoInput_GeneratesEmptyMesh()
        {
            GeometryConstructor gc = new GeometryConstructor();
            Mesh mesh = gc.ConstructMesh();

            Assert.IsNotNull(mesh);
            Assert.IsEmpty(mesh.vertices);
            Assert.IsEmpty(mesh.triangles);
        }
Beispiel #7
0
        public void ConstructObject_WithGeometryDefaultMaterial_GOWithMeshDefaultMat()
        {
            ObjectConstructor   objConstructor      = new ObjectConstructor();
            GeometryConstructor geometryConstructor = CreateSimpleGeometry();

            objConstructor.GeometryConstructor = geometryConstructor;
            GameObject result = objConstructor.ConstructObject();

            AssertGameObjectWithGeometry(result, geometryConstructor, out MeshRenderer meshRenderer);
        }
Beispiel #8
0
        /// <summary>
        /// Creates a GeometryConstructor with a simple plane geometry
        /// </summary>
        /// <returns>A GeometryConstructor with a single quad</returns>
        private GeometryConstructor CreateSimpleGeometry()
        {
            GeometryConstructor gc = new GeometryConstructor();
            int v1 = gc.AddVertex(new Vector3(0, 0, 0));
            int v2 = gc.AddVertex(new Vector3(0, 1, 0));
            int v3 = gc.AddVertex(new Vector3(1, 0, 0));
            int v4 = gc.AddVertex(new Vector3(1, 1, 0));

            gc.AddQuad(v1, v3, v4, v2);
            gc.Name = "Simple Geometry" + Random.Range(0, 10000);
            return(gc);
        }
Beispiel #9
0
        /// <summary>
        /// Reusable function that checks if the given GameObject has the correct geometry and shader
        /// </summary>
        /// <param name="result">The created GameObject that should be checked</param>
        /// <param name="geometryConstructor">The geometry constructor which was used to create the object's mesh</param>
        /// <param name="meshRenderer">The mesh renderer that is retrieved from the GameObject result</param>
        private void AssertGameObjectWithGeometry(GameObject result, GeometryConstructor geometryConstructor,
                                                  out MeshRenderer meshRenderer)
        {
            Assert.IsNotNull(result);
            Assert.AreEqual(geometryConstructor.Name, result.name);

            MeshFilter meshFilter = result.GetComponent <MeshFilter>();

            Assert.IsNotNull(meshFilter);
            meshRenderer = result.GetComponent <MeshRenderer>();
            Assert.IsNotNull(meshRenderer);

            Assert.AreEqual(Shader.Find("Standard"), meshRenderer.sharedMaterial.shader);
        }
Beispiel #10
0
        public void ConstructObject_MaterialConstructorGiven_AssignedMaterial()
        {
            ObjectConstructor   objConstructor      = new ObjectConstructor();
            GeometryConstructor geometryConstructor = CreateSimpleGeometry();
            MaterialConstructor materialConstructor = new MaterialConstructor();

            materialConstructor.Color          = Color.red;
            materialConstructor.Name           = "RedMat";
            objConstructor.GeometryConstructor = geometryConstructor;
            objConstructor.MaterialConstructor = materialConstructor;
            GameObject result = objConstructor.ConstructObject();

            AssertGameObjectWithGeometry(result, geometryConstructor, out MeshRenderer meshRenderer);

            Assert.AreEqual(Color.red, meshRenderer.sharedMaterial.color);
            Assert.AreEqual(materialConstructor.Name, meshRenderer.sharedMaterial.name);
        }
        /// <summary>
        /// Creates the rounded corner in the mesh constructor
        /// </summary>
        /// <param name="constructor">The mesh constructor to which the geometry of the corner should be added</param>
        /// <param name="innerVertex">The index of the inner vertex around which the corner is rotated</param>
        /// <param name="outerVertex1">The clockwise first outer vertex to which the rounded corner is connected</param>
        /// <param name="outerVertex2">The clockwise second outer vertex to which the rounded corner is connected</param>
        /// <param name="subdivisionCoordinates">The front coorindates of the vertices of the rounded corner</param>
        /// <param name="isBackFace">True if the back faces should be generated</param>
        private void CreateCorner(GeometryConstructor constructor, int innerVertex, int outerVertex1, int outerVertex2, Vector3[] subdivisionCoordinates, bool isBackFace)
        {
            // triangle fan must include existing endpoint vertices => two more entries in vertex indices
            int[] iCornerVertices = new int[subdivisions + 2];
            // determine at which depth the vertices should be placed
            Vector3 depthVector = isBackFace ? new Vector3(0, 0, depth) : Vector3.zero;

            // create the vertices and write the indices to the index array
            iCornerVertices[0] = outerVertex1;
            for (int i = 0; i < subdivisionCoordinates.Length; i++)
            {
                iCornerVertices[i + 1] = constructor.AddVertex(subdivisionCoordinates[i] + depthVector);
            }
            iCornerVertices[iCornerVertices.Length - 1] = outerVertex2;

            // create the triangle fan which represents the rounded corner
            constructor.AddTriangleFan(innerVertex, iCornerVertices, isBackFace);
        }
        /// <summary>
        /// Generates the mesh based on the settings of the menu
        /// </summary>
        /// <returns></returns>
        private Mesh GenerateMesh()
        {
            GeometryConstructor constructor = new GeometryConstructor();

            // vertex positions
            // calculate positions of inner four vertices
            Vector3 leftTopInner     = new Vector3(-width / 2f + realCornerRadius, height / 2f - realCornerRadius, 0);
            Vector3 leftBottomInner  = new Vector3(-width / 2f + realCornerRadius, -height / 2f + realCornerRadius, 0);
            Vector3 rightTopInner    = new Vector3(width / 2f - realCornerRadius, height / 2f - realCornerRadius, 0);
            Vector3 rightBottomInner = new Vector3(width / 2f - realCornerRadius, -height / 2f + realCornerRadius, 0);

            // calculate positions of outer vertices (not part of the rounded corners)
            Vector3 leftTopOuterLeft       = leftTopInner - new Vector3(realCornerRadius, 0, 0);
            Vector3 leftTopOuterTop        = leftTopInner + new Vector3(0, realCornerRadius, 0);
            Vector3 leftBottomOuterLeft    = leftBottomInner - new Vector3(realCornerRadius, 0, 0);
            Vector3 leftBottomOuterBottom  = leftBottomInner - new Vector3(0, realCornerRadius, 0);
            Vector3 rightTopOuterRight     = rightTopInner + new Vector3(realCornerRadius, 0, 0);
            Vector3 rightTopOuterTop       = rightTopInner + new Vector3(0, realCornerRadius, 0);
            Vector3 rightBottomOuterRight  = rightBottomInner + new Vector3(realCornerRadius, 0, 0);
            Vector3 rightBottomOuterBottom = rightBottomInner - new Vector3(0, realCornerRadius, 0);

            // calculate positions of the front vertices for the rounded corners
            // back vertices can be calculated from this later
            Vector3[] leftTopCorner     = GetCornerVertexCoordinates(leftTopInner, 0f);
            Vector3[] rightTopCorner    = GetCornerVertexCoordinates(rightTopInner, 90f);
            Vector3[] rightBottomCorner = GetCornerVertexCoordinates(rightBottomInner, 180f);
            Vector3[] leftBottomCorner  = GetCornerVertexCoordinates(leftBottomInner, 270f);

            // create the areas twice: once for the front and once for the back of the menu
            for (int i = 0; i < 2; i++)
            {
                Vector3 depthOffset = new Vector3(0, 0, i * depth);

                // get indices for inner four vertices
                int iLeftTopInner     = constructor.AddVertex(leftTopInner + depthOffset);
                int iLeftBottomInner  = constructor.AddVertex(leftBottomInner + depthOffset);
                int iRightTopInner    = constructor.AddVertex(rightTopInner + depthOffset);
                int iRightBottomInner = constructor.AddVertex(rightBottomInner + depthOffset);

                // get indices for outer vertices
                int iLeftTopOuterLeft       = constructor.AddVertex(leftTopOuterLeft + depthOffset);
                int iLeftTopOuterTop        = constructor.AddVertex(leftTopOuterTop + depthOffset);
                int iLeftBottomOuterLeft    = constructor.AddVertex(leftBottomOuterLeft + depthOffset);
                int iLeftBottomOuterBottom  = constructor.AddVertex(leftBottomOuterBottom + depthOffset);
                int iRightTopOuterRight     = constructor.AddVertex(rightTopOuterRight + depthOffset);
                int iRightTopOuterTop       = constructor.AddVertex(rightTopOuterTop + depthOffset);
                int iRightBottomOuterRight  = constructor.AddVertex(rightBottomOuterRight + depthOffset);
                int iRightBottomOuterBottom = constructor.AddVertex(rightBottomOuterBottom + depthOffset);

                bool isBackFace = (i == 1);

                // create inner quad
                constructor.AddQuad(iLeftTopInner, iRightTopInner, iRightBottomInner, iLeftBottomInner, isBackFace);
                // create outer border
                constructor.AddQuad(iLeftTopOuterTop, iRightTopOuterTop, iRightTopInner, iLeftTopInner, isBackFace);
                constructor.AddQuad(iRightTopInner, iRightTopOuterRight, iRightBottomOuterRight, iRightBottomInner, isBackFace);
                constructor.AddQuad(iLeftBottomInner, iRightBottomInner, iRightBottomOuterBottom, iLeftBottomOuterBottom, isBackFace);
                constructor.AddQuad(iLeftTopOuterLeft, iLeftTopInner, iLeftBottomInner, iLeftBottomOuterLeft, isBackFace);

                // create the rounded corners
                CreateCorner(constructor, iLeftTopInner, iLeftTopOuterLeft, iLeftTopOuterTop, leftTopCorner, isBackFace);
                CreateCorner(constructor, iRightTopInner, iRightTopOuterTop, iRightTopOuterRight, rightTopCorner, isBackFace);
                CreateCorner(constructor, iRightBottomInner, iRightBottomOuterRight, iRightBottomOuterBottom, rightBottomCorner, isBackFace);
                CreateCorner(constructor, iLeftBottomInner, iLeftBottomOuterBottom, iLeftBottomOuterLeft, leftBottomCorner, isBackFace);
            }

            // create rim vertex indices
            // these vertices need to be separate from the ones above, even if they have the same coordinates to create sharp edges
            int[] rimLeftTopOuterLeft       = new int[2];
            int[] rimLeftTopOuterTop        = new int[2];
            int[] rimLeftBottomOuterLeft    = new int[2];
            int[] rimLeftBottomOuterBottom  = new int[2];
            int[] rimRightTopOuterRight     = new int[2];
            int[] rimRightTopOuterTop       = new int[2];
            int[] rimRightBottomOuterRight  = new int[2];
            int[] rimRightBottomOuterBottom = new int[2];

            for (int i = 0; i < 2; i++)
            {
                Vector3 depthOffset = new Vector3(0, 0, i * depth);

                rimLeftTopOuterLeft[i]       = constructor.AddVertex(leftTopOuterLeft + depthOffset);
                rimLeftTopOuterTop[i]        = constructor.AddVertex(leftTopOuterTop + depthOffset);
                rimLeftBottomOuterLeft[i]    = constructor.AddVertex(leftBottomOuterLeft + depthOffset);
                rimLeftBottomOuterBottom[i]  = constructor.AddVertex(leftBottomOuterBottom + depthOffset);
                rimRightTopOuterRight[i]     = constructor.AddVertex(rightTopOuterRight + depthOffset);
                rimRightTopOuterTop[i]       = constructor.AddVertex(rightTopOuterTop + depthOffset);
                rimRightBottomOuterRight[i]  = constructor.AddVertex(rightBottomOuterRight + depthOffset);
                rimRightBottomOuterBottom[i] = constructor.AddVertex(rightBottomOuterBottom + depthOffset);
            }

            // top rim
            constructor.AddQuad(rimLeftTopOuterTop[1], rimRightTopOuterTop[1], rimRightTopOuterTop[0], rimLeftTopOuterTop[0]);
            // right rim
            constructor.AddQuad(rimRightTopOuterRight[0], rimRightTopOuterRight[1], rimRightBottomOuterRight[1], rimRightBottomOuterRight[0]);
            // bottom rim
            constructor.AddQuad(rimLeftBottomOuterBottom[0], rimRightBottomOuterBottom[0], rimRightBottomOuterBottom[1], rimLeftBottomOuterBottom[1]);
            // left rim
            constructor.AddQuad(rimLeftTopOuterLeft[1], rimLeftTopOuterLeft[0], rimLeftBottomOuterLeft[0], rimLeftBottomOuterLeft[1]);

            // rim of the corners
            CreateCornerRim(constructor, rimLeftTopOuterLeft, leftTopCorner, rimLeftTopOuterTop);
            CreateCornerRim(constructor, rimRightTopOuterTop, rightTopCorner, rimRightTopOuterRight);
            CreateCornerRim(constructor, rimRightBottomOuterRight, rightBottomCorner, rimRightBottomOuterBottom);
            CreateCornerRim(constructor, rimLeftBottomOuterBottom, leftBottomCorner, rimLeftBottomOuterLeft);


            return(constructor.ConstructMesh());
        }