示例#1
0
    public void Visualize(float[,,] data)
    {
        var cube = new MarchingCube(transform.position, data, cubeSize, isoLevel);

        _bounds.Clear();
        var meshData = cube.March((min, max) => { _bounds.Add(new Bounds((min + max) / 2f, max - min)); });

        mesh = new Mesh()
        {
            indexFormat = IndexFormat.UInt32,
            vertices    = meshData.Vertices.ToArray(),
            triangles   = meshData.Triangles.ToArray()
        };
        mesh.RecalculateBounds();
        mesh.RecalculateNormals();

        if (!meshFilter)
        {
            meshFilter = gameObject.AddComponent <MeshFilter>();
        }
        meshFilter.sharedMesh = mesh;

        if (!meshRenderer)
        {
            meshRenderer = gameObject.AddComponent <MeshRenderer>();
        }
        meshRenderer.sharedMaterial = VisualMaterial;

        if (!meshCollider)
        {
            meshCollider = gameObject.AddComponent <MeshCollider>();
        }
        meshCollider.sharedMesh = mesh;
    }
示例#2
0
    void GenerateMap()
    {
        int resolutionCube = resolution * resolution * resolution;

        if (map.Length != resolutionCube)
        {
            map = new float[resolution, resolution, resolution];
        }

        NativeList <int3> usedIndices = new NativeList <int3>(Allocator.Temp);

        for (int x = 0; x < resolution - 1; x++)
        {
            for (int y = 0; y < resolution - 1; y++)
            {
                for (int z = 0; z < resolution - 1; z++)
                {
                    float4 pos    = new float4(position.x + x * scale, position.y + y * scale, position.z + z * scale, position.w);
                    float  perlin = noise.cnoise(pos);
                    map[x, y, z] = perlin > thresHold ? 1 : 0;
                    usedIndices.Add(new int3(x, y, z));
                }
            }
        }

        MarchingCube.CreateMeshData(map, usedIndices, scale, ref mesh);
        usedIndices.Dispose();

        filter.mesh = mesh;
    }
示例#3
0
    static void CalculateVertexWeight(MarchingCube cube, int index, MarchingCubeChunkSetting marchingCubeSetting, NoiseSetting noiseSetting)
    {
        //Cube neigborCube;
        //check there is exsiting noise value at neighbor
        //Skip this process because we use perlin noise
        //if(cubeDictionary.TryGetValue(new Vector3(vertexPosition.x - someOffset?, vertexPosition.y, vertexPosition.z), out neigborCube) {
        //    ...
        //} else if ...

        //For threading, we have to dupulicate Animation Curve
        AnimationCurve weightCurve = new AnimationCurve(marchingCubeSetting.weightCurve.keys);

        float height   = cube.origin.y + cube.offset[index].y;
        float height01 = Mathf.Lerp(1, 0, (marchingCubeSetting.mapMaxHeight - height) / (marchingCubeSetting.mapMaxHeight - marchingCubeSetting.mapMinHeight));
        float weight   = MarchingCubeNoise.GenerateTerrainNoise(cube.origin + cube.offset[index], noiseSetting) * weightCurve.Evaluate(height01);

        if (height < marchingCubeSetting.mapMinHeight + cube.offsetDistance)
        {
            weight = 1;
        }
        else if (height > marchingCubeSetting.mapMaxHeight - cube.offsetDistance)
        {
            weight = 0;
        }
        cube.vertexSelected[index] = weight < marchingCubeSetting.ignoreVertexLevel;
        cube.vertexWeight[index]   = weight;
    }
示例#4
0
    /// <summary>
    /// Uncompleted Bursted version
    /// </summary>
    public static void GenerateMeshBurst(NativeArray <SPHSystem.WaterParticle> waterParticles, int count, float3 minPosition, float3 maxPosition, int resolution, ref Mesh mesh)
    {
        Profiler.BeginSample("WaterMarchingCube");

        int resolutionCube = resolution * resolution * resolution;

        var nativeMap         = new NativeArray <float>(resolutionCube, Allocator.TempJob);
        var nativeUsedIndices = new NativeList <int3>(resolutionCube, Allocator.TempJob);

        float invResolution = 1f / resolution;

        FillMapJob fillMapJob = new FillMapJob()
        {
            map            = nativeMap,
            usedIndices    = nativeUsedIndices,
            resolution     = resolution,
            invResolution  = invResolution,
            maxPosition    = maxPosition,
            minPosition    = minPosition,
            waterParticles = waterParticles,
        };

        fillMapJob.Run();

        Profiler.EndSample();
        MarchingCube.CreateMeshData(nativeMap, nativeUsedIndices, resolution, invResolution, ref mesh);
        nativeMap.Dispose();
        nativeUsedIndices.Dispose();
    }
 public static MarchingCube getInstance()
 {
     if (instance == null)
     {
         instance = new MarchingCube();
     }
     return(instance);
 }
        void SetupOutline(ChunkConfig chunk, Vector2Int loc)
        {
            var terrainGen = chunk.terrainGen;

            using (ComputeBuffer outBuf = new ComputeBuffer(chunk.gridCount, sizeof(float)))
            {
                // Setup compute shader.
                int k = terrainGen.FindKernel("Main");
                terrainGen.SetFloat("pi", PI);
                terrainGen.SetFloat("rdSeed", chunk.seed);
                terrainGen.SetFloats("resolution", chunk.resolution.x, chunk.resolution.y);
                terrainGen.SetFloat("caveShrinkY", chunk.caveShrinkY);
                terrainGen.SetFloat("caveEliminateY", chunk.caveEliminateY);
                terrainGen.SetFloats("roughness", chunk.roughness);
                terrainGen.SetFloats("localScale", chunk.localScale.x, chunk.localScale.y);
                terrainGen.SetFloats("freq", chunk.frequency.x, chunk.frequency.y);
                terrainGen.SetFloats("offset", chunk.OffsetBottomLeft(loc).x, chunk.OffsetBottomLeft(loc).y);
                terrainGen.SetFloats("amplitude", chunk.amplitude.x, chunk.amplitude.y);
                terrainGen.SetBuffer(k, "output", outBuf);

                // Draw chunk terrain.
                terrainGen.Dispatch(k, CeilToInt(chunk.resolution.x / 16.0f), CeilToInt(chunk.resolution.y / 16.0f), 1);

                // check the databuf and its size.
                if (dataBuf == null || dataBuf.Length != chunk.gridCount)
                {
                    dataBuf = new float[chunk.gridCount];
                }

                // get data from GPU back into main memory.
                outBuf.GetData(dataBuf);
            }

            // Check chunk points.
            // Mesh vertices should be in *local* space that relative to the bottom-left corner.
            if (segs == null)
            {
                segs = new List <Segment>();
            }
            segs.Clear();

            for (int x = 0; x < chunk.resolution.x; x++)
            {
                for (int y = 0; y < chunk.resolution.y; y++)
                {
                    int val = RoundToInt(dataBuf[x + y * chunk.resolution.x]) ^ 0xF;
                    MarchingCube.Get(val, new Vector2(x, y), segs);
                }
            }

            for (int i = 0; i < segs.Count; i++)
            {
                segs[i] = new Segment(segs[i].from * chunk.localScale, segs[i].to * chunk.localScale);
            }

            lks = segs.LinkUp().Smooth(Util.SmoothAverage).Smooth(Util.SmoothFill);
        }
示例#7
0
 public void Init(GameObject template, Vector3 position)
 {
     internalCubes = new MarchingCube[offsets.Length];
     for (int i = 0; i < offsets.Length; i++)
     {
         var obj = Object.Instantiate(template, position + offsets[i] * cubeSize, new Quaternion());
         var marchingCubeShader = obj.GetComponent <MarchingCubeShader>();
         internalCubes[i] = new MarchingCube(matrixSize, marchingCubeShader);
     }
 }
    public GridMarcher(OccupancyGrid occupancyGrid, ComputeShader computeShader)
    {
        this.occupancyGrid = occupancyGrid;

        this.marchingCube = new MarchingCube();

        marchingCube.Init();

        this.computeShader = computeShader;
    }
示例#9
0
    public static void GenerateMesh(NativeArray <SPHSystem.WaterParticle> waterParticles, int count, float3 minPosition, float3 maxPosition, int resolution, ref Mesh mesh)
    {
        Profiler.BeginSample("WaterMarchingCube");
        int resolutionCube = resolution * resolution * resolution;

        if (usedGrid == null || usedGrid.Length != resolutionCube)
        {
            usedGrid = new bool[resolution, resolution, resolution];
            map      = new float[resolution, resolution, resolution];
        }
        else
        {
            Array.Clear(usedGrid, 0, resolutionCube);
            Array.Clear(map, 0, resolutionCube);
        }

        float             invResolution = 1f / resolution;
        float             step          = math.distance(maxPosition.x, minPosition.x) * invResolution;
        float             invStep       = 1f / step;
        NativeList <int3> usedIndices   = new NativeList <int3>(resolution * resolution, Allocator.Temp);

        for (int i = 0; i < count; i++)
        {
            int3 index = GetPositionIndex(waterParticles[i].position, minPosition, maxPosition, resolution, invStep);

            //Only calculate marching cube for the 8 corners per cube
            for (int j = 0; j < MarchingCubeTables.CornerTable.Length; j++)
            {
                int3 conerIndex = index + MarchingCubeTables.CornerTable[j];
                if (!usedGrid[conerIndex.x, conerIndex.y, conerIndex.z])
                {
                    usedGrid[conerIndex.x, conerIndex.y, conerIndex.z] = true;
                    usedIndices.Add(conerIndex);
                }
                int3 conerIndex2 = index - MarchingCubeTables.CornerTable[j];
                if (!usedGrid[conerIndex2.x, conerIndex2.y, conerIndex2.z])
                {
                    usedGrid[conerIndex2.x, conerIndex2.y, conerIndex2.z] = true;
                    usedIndices.Add(conerIndex2);
                }
            }

            map[index.x, index.y, index.z] = 1;
        }

        Profiler.EndSample();
        MarchingCube.CreateMeshData(map, usedIndices, invResolution, ref mesh);
        usedIndices.Dispose();
    }
示例#10
0
    /// <summary>
    /// Get the vertices of the triangles to be drawn.
    /// Each triangle is drawn between 3 points, each of which are on an edge in the marching cube.
    /// </summary>
    /// <param name="cube">The marching cube for which we are calculating triangles.</param>
    /// <param name="edgeNumbers">The numbers of the edges to be connected. Every 3 edges is
    ///     one triangle.</param>
    /// <returns>The coordinates of every triangle vertex. Every 3 is one triangle.</returns>
    private Vector3[] GetTriangleVertices(MarchingCube cube, int[] edgeNumbers)
    {
        List <Vector3> triangleVertices = new List <Vector3>();

        // Loop through each triangle
        for (int i = 0; i < edgeNumbers.Length; i++)
        {
            if (edgeNumbers[i] != -1)
            {
                triangleVertices.Add(cube.GetEdgeMidpoint(edgeNumbers[i]));
            }
        }

        return(triangleVertices.ToArray());
    }
示例#11
0
    public void InitializeVoxelCollection()
    {
        if (bIsVoxelCollectionInitialized)
        {
            for (int ColX = 0; ColX < XZMarchingCubeNums; ++ColX)
            {
                for (int ColY = 0; ColY < YMarchingCubeNums; ++ColY)
                {
                    for (int ColZ = 0; ColZ < XZMarchingCubeNums; ++ColZ)
                    {
                        InjectionData(ref GetMarchingCube(ColX, ColY, ColZ), ColX, ColY, ColZ);
                        GetMarchingCube(ColX, ColY, ColZ).InitializeVoxelData();
                    }
                }
            }

            return;
        }

        mVoxelData = new VoxelPoint[(XZMultiplier * XZMarchingCubeNums + 1) * (YMultiplier * YMarchingCubeNums + 1) * (XZMultiplier * XZMarchingCubeNums + 1)];
        mMarchingCubeCollection = new MarchingCube[XZMarchingCubeNums * YMarchingCubeNums * XZMarchingCubeNums];

        for (int ColX = 0; ColX < XZMarchingCubeNums; ++ColX)
        {
            for (int ColY = 0; ColY < YMarchingCubeNums; ++ColY)
            {
                for (int ColZ = 0; ColZ < XZMarchingCubeNums; ++ColZ)
                {
                    GameObject TempObject = Instantiate(MarchingCubePrefab,
                                                        transform.position + new Vector3(
                                                            (ColX - XZMarchingCubeNums / 2) * VoxelResolution * XZMultiplier,
                                                            (ColY - YMarchingCubeNums / 2) * VoxelResolution * YMultiplier,
                                                            (ColZ - XZMarchingCubeNums / 2) * VoxelResolution * XZMultiplier),
                                                        Quaternion.identity);

                    TempObject.transform.parent = transform;
                    MarchingCube TempComp = TempObject.GetComponent <MarchingCube>();

                    InjectionData(ref TempComp, ColX, ColY, ColZ);
                    TempComp.InitializeVoxelData();

                    GetMarchingCube(ColX, ColY, ColZ) = TempComp;
                }
            }
        }

        bIsVoxelCollectionInitialized = true;
    }
示例#12
0
    /// <summary>
    /// Generate a 3D mesh for the densities using a marching cubes algorithm.
    /// </summary>
    /// <returns>A Mesh object</returns>
    public Mesh Generate()
    {
        List <Vector3> vertices = new List <Vector3>();

        // Loop through the volumetric data.
        for (int xIndex = 0; xIndex < densities.GetLength(0) - 1; xIndex++)
        {
            for (int yIndex = 0; yIndex < densities.GetLength(1) - 1; yIndex++)
            {
                for (int zIndex = 0; zIndex < densities.GetLength(2) - 1; zIndex++)
                {
                    // Create a marching cube for this position.
                    Vector3Int   cubeIndex = new Vector3Int(xIndex, yIndex, zIndex);
                    MarchingCube cube      = new MarchingCube(settings, cubeIndex, points, densities);

                    // Determine which triangles to draw for this cube.
                    int       cubeCase             = ConcatenateIntoByte(GetActiveDensityBitArray(cube.densities));
                    int[]     connectedEdges       = Tables.triangles[cubeCase];
                    Vector3[] cubeTriangleVertices = GetTriangleVertices(cube, connectedEdges);

                    // Add the triangle vertices for this cube to the list of all triangle vertices
                    for (int i = 0; i < cubeTriangleVertices.Length; i++)
                    {
                        vertices.Add(cubeTriangleVertices[i]);
                    }
                }
            }
        }

        // Add all of the triangle indeces, which should simply be [0, numVertices] because we are
        // not reusing any vertices between triangles.
        List <int> triangles = new List <int>();

        for (int i = 0; i < vertices.Count; i++)
        {
            triangles.Add(vertices.Count - 1 - i);
        }

        // Create the mesh itself and assign all the data.
        Mesh cellMesh = new Mesh();

        cellMesh.vertices  = vertices.ToArray();
        cellMesh.triangles = triangles.ToArray();
        cellMesh.RecalculateNormals();

        return(cellMesh);
    }
 void DrawMarchingCube(MarchingCube cube)
 {
     Gizmos.color = Color.white;
     for (int i = 0; i < 8; i++)
     {
         if (cube.vertexSelected[i])
         {
             Gizmos.color = Color.black;
             Gizmos.DrawSphere(cube.origin + cube.offset[i], 0.05f);
         }
         else
         {
             Gizmos.color = Color.white;
             Gizmos.DrawSphere(cube.origin + cube.offset[i], 0.05f);
         }
     }
 }
示例#14
0
    private IEnumerator DestroyVoxel()
    {
        while (bIsTriggerPressed)
        {
            Ray RayDescriptor = new Ray();
            RayDescriptor.origin    = AimPoint.position;
            RayDescriptor.direction = AimPoint.forward;

            Debug.DrawRay(RayDescriptor.origin, RayDescriptor.direction * VoxelCastLength, Color.green, 10.0f);
            RaycastHit HitInfo;
            if (Physics.Raycast(RayDescriptor, out HitInfo, VoxelCastLength, -1, QueryTriggerInteraction.Ignore) == true)
            {
                BeamComp.TargetPosition = HitInfo.point;

                Collider[] HitColliders = Physics.OverlapSphere(HitInfo.point, VoxelEffectRadius);
                if (HitColliders != null)
                {
                    MarchingCube HitCube = HitInfo.collider.gameObject.GetComponent <MarchingCube>();
                    if (HitCube == null)
                    {
                        yield return(new WaitForSeconds(VoxelEditDelay));
                    }

                    HitCube.RemoveVoxel(HitInfo.point, VoxelEffectRadius, VoxelEditPower * VoxelEditDelay, Space.World);

                    for (int i = 0; i < HitColliders.Length; ++i)
                    {
                        MarchingCube CurCube = HitColliders[i].gameObject.GetComponent <MarchingCube>();
                        if (CurCube == null)
                        {
                            continue;
                        }

                        CurCube.UpdateMarchingCube();
                    }
                }
            }
            else
            {
                BeamComp.TargetPosition = RayDescriptor.direction * VoxelCastLength + BeamComp.transform.position;
            }

            yield return(new WaitForSeconds(VoxelEditDelay));
        }
    }
示例#15
0
    public static List <MarchingCube> InitVertices(Vector3 center, MarchingCubeChunkSetting marchingCubeChunksettings, NoiseSetting noiseSetting)
    {
        List <MarchingCube> cubeList = new List <MarchingCube>();

        for (int x = 0; x < marchingCubeChunksettings.numberOfVerticesPerLine; x++)
        {
            for (int y = 0; y < marchingCubeChunksettings.numberOfVerticesPerLine; y++)
            {
                for (int z = 0; z < marchingCubeChunksettings.numberOfVerticesPerLine; z++)
                {
                    MarchingCube cube = new MarchingCube(new Vector3(x, y, z) * marchingCubeChunksettings.distanceBetweenVertex + center, marchingCubeChunksettings.distanceBetweenVertex);
                    cubeList.Add(cube);
                    for (int i = 0; i < 8; i++)
                    {
                        CalculateVertexWeight(cube, i, marchingCubeChunksettings, noiseSetting);
                    }
                }
            }
        }

        return(cubeList);
    }
示例#16
0
    public void process(Chunk chunk)
    {
        this.chunk = chunk;
        MarchingCube marchingCube = MarchingCube.getInstance();

        float[,,] density = chunk.getDensity();
        for (int x = 0; x < voxelCount; x++)
        {
            for (int y = 0; y < voxelCount; y++)
            {
                for (int z = 0; z < voxelCount; z++)
                {
                    Profiler.BeginSample("Marching:March");
                    marchingCube.march(x, y, z, density, this);
                    Profiler.EndSample();
                }
            }
        }
        Profiler.BeginSample("Proccessor:GenerateMesh");
        generateMesh();
        Profiler.EndSample();
        reset();
    }
    private void OnDrawGizmos()
    {
        MarchingCube cube = new MarchingCube(Vector3.zero, 1);

        for (int i = 0; i < 8; i++)
        {
            cube.vertexSelected[i] = selectedCubeIndex[i];
        }

        Vector3[] vertices = cube.GetMarchingCubeVertices();
        int[]     triangle = new int[vertices.Length];
        for (int i = 0; i < triangle.Length; i++)
        {
            triangle[i] = i;
        }

        mesh.sharedMesh           = new Mesh();
        mesh.sharedMesh.vertices  = vertices;
        mesh.sharedMesh.triangles = triangle;
        mesh.sharedMesh.RecalculateNormals();

        DrawMarchingCube(cube);
    }
    private void OnSceneGUI()
    {
        UnityEngine.Mesh mesh = null;
        int          cellNum  = 10;
        MarchingCube mc       = target as MarchingCube;
        Dictionary <int, List <Vector3> > ss = new Dictionary <int, List <Vector3> >();

        if (mc.gameObject != null)
        {
            mesh = mc.gameObject.GetComponent <MeshFilter>().sharedMesh;

            Vector3[] verts = mesh.vertices;

            for (int i = 0; i < verts.Length; i++)
            {
                Vector3 worldPos = mc.gameObject.transform.TransformPoint(verts[i]);
                Vector3 pos      = worldPos;
                //check bound
                if (pos.x < 0 || pos.y < 0 || pos.z < 0)
                {
                    continue;
                }

                int hash = mc.MakeHash(pos);
                if (ss.ContainsKey(hash))
                {
                    ss[hash].Add(pos);
                }
                else
                {
                    List <Vector3> ptlist = new List <Vector3>();
                    ptlist.Add(pos);
                    ss.Add(hash, ptlist);
                }
            }
        }

        gizmoLines = new Vector3[cellNum * cellNum * cellNum];
        int cnt = 0;

        BitMap3d bm3d = new BitMap3d(cellNum, cellNum, cellNum);

        for (int i = 0; i < cellNum; i++)
        {
            for (int j = 0; j < cellNum; j++)
            {
                for (int k = 0; k < cellNum; k++)
                {
                    Vector3 start = new Vector3(k, j, i);
                    int     hash  = mc.MakeHash(start);

                    float dens = 0;
                    if (ss.ContainsKey(hash))
                    {                                       //verts inside cellgrid, calculate density
                        List <Vector3> objverts = ss[hash]; //obj verts in cell
                        //for (int ii = 0; ii < 8; ii++)
                        {
                            float dd = 0;
                            foreach (var vert in objverts)
                            {
                                dd += Vector3.Magnitude(vert - start);
                            }
                            dd = dd / objverts.Count;
                            if (dd > 0 && dd < densityThreshold)
                            {
                                Handles.color = new Color(dd, 0.5f, 0.0f);
                                //Handles.DrawLine(vert, cubePts[ii]);
                                Handles.SphereHandleCap(0, start, Quaternion.identity, 0.2f, EventType.Repaint);
                                Handles.Label(start, start.ToString());
                            }
                        }
                    }
                    else
                    {
                        dens = 0;
                    }

                    gizmoLines[cnt] = start;
                    Handles.color   = new Color(0.3f, 0.5f, 0.5f);
                    Vector3 gizmoCubeCenter = start + Vector3.one * 0.5f;
                    if (gizmoCube)
                    {
                        Handles.DrawWireCube(gizmoCubeCenter, Vector3.one);
                    }

                    cnt++;
                }
            }
        }
    }
 public static MarchingCube getInstance()
 {
     if(instance==null){
         instance = new MarchingCube();
     }
     return instance;
 }
示例#20
0
    void Generate()
    {
        DateTime startTime = System.DateTime.Now;

        INoise       perlin  = new PerlinNoise(seed, 2f);
        FractalNoise fractal = new FractalNoise(perlin, 3, 1f);

        MarchingCube marching = new MarchingCube();

        Marching.Surface = 0f;

        width  = sizeScale;
        height = sizeScale;
        length = sizeScale;

        float[] voxels = new float[width * height * length];

        //Fill voxels with values. Im using perlin noise but any method to create voxels will work.
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                for (int z = 0; z < length; z++)
                {
                    float fx = x / (width - 1.0f);
                    float fy = y / (height - 1.0f);
                    float fz = z / (length - 1.0f);

                    int idx = x + y * width + z * width * height;

                    voxels[idx] = fractal.Sample3D(fx, fy, fz);
                }
            }
        }

        verts   = new List <Vector3>();
        indices = new List <int>();


        if (useJobSystem)
        {
            MarchingCubeParallel          marching_p = new MarchingCubeParallel(0);
            MarchingCubeParallel.MarchJob job;
            JobHandle handle = marching_p.Generate(new List <float>(voxels), width, height, length, out job);
            StartCoroutine(Wait4Complete(handle, job));
        }
        else
        {
            marching.Generate(voxels, width, height, length, verts, indices);
            int maxVertsPerMesh = 30000; //must be divisible by 3, ie 3 verts == 1 triangle
            int numMeshes       = verts.Count / maxVertsPerMesh + 1;
            for (int i = 0; i < numMeshes; i++)
            {
                List <Vector3> splitVerts   = new List <Vector3>();
                List <int>     splitIndices = new List <int>();

                for (int j = 0; j < maxVertsPerMesh; j++)
                {
                    int idx = i * maxVertsPerMesh + j;

                    if (idx < verts.Count)
                    {
                        splitVerts.Add(verts[idx]);
                        splitIndices.Add(j);
                    }
                }

                if (splitVerts.Count == 0)
                {
                    continue;
                }

                Mesh mesh = new Mesh();
                mesh.SetVertices(splitVerts);
                mesh.SetTriangles(splitIndices, 0);
                mesh.RecalculateBounds();
                mesh.RecalculateNormals();

                GameObject go = new GameObject("Mesh");
                go.transform.parent = transform;
                go.AddComponent <MeshFilter>();
                go.AddComponent <MeshRenderer>();
                go.GetComponent <Renderer>().material = m_material;
                go.GetComponent <MeshFilter>().mesh   = mesh;
                go.transform.localPosition            = new Vector3(-width / 2, -height / 2, -length / 2);

                meshes.Add(go);
            }
        }
        double timeCost = System.DateTime.Now.Subtract(startTime).TotalMilliseconds;

        print("Time Cost : " + timeCost + " at size " + (8 * sizeScale));
    }