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]); }
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); }
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); }
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); }
public void ConstructMesh_NoInput_GeneratesEmptyMesh() { GeometryConstructor gc = new GeometryConstructor(); Mesh mesh = gc.ConstructMesh(); Assert.IsNotNull(mesh); Assert.IsEmpty(mesh.vertices); Assert.IsEmpty(mesh.triangles); }
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); }
/// <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); }
/// <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); }
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()); }