예제 #1
0
    //UTD2018
    public static GameObject MakeVolume(string path, Texture2D noise = null, Material loading = null)
    {
        GameObject g = GameObject.CreatePrimitive(PrimitiveType.Cube);

        g.transform.position = Vector3.up;
        g.GetComponent <MeshRenderer>().material = loading;
        VolumeComponent vc = g.AddComponent <VolumeComponent>();

        vc.rayOffset = noise;
        VolumeRenderer vr = Camera.main.GetComponent <VolumeRenderer>();

        if (!vr)
        {
            Debug.Log("Volume Renderer not detected, adding one to the main camera...");
            vr = Camera.main.gameObject.AddComponent <VolumeRenderer>();
            vr.volumeObjects = new List <VolumeComponent>();
        }
        vr.volumeObjects.Add(vc);
        VolumeFileLoader vfl = g.AddComponent <VolumeFileLoader>();

        vfl.forceDataFormat = VolumeTextureFormat.Alpha8;
        vfl.dataPath        = path;
        return(g);
    }
    public void ConvertToMesh(float cutoff = 0.5f)
    {
        //Set the mode used to create the mesh.
        //Cubes is faster and creates less verts, tetrahedrons is slower and creates more verts but better represents the mesh surface.
        Marching marching = null;

        if (mode == MARCHING_MODE.TETRAHEDRON)
        {
            marching = new MarchingTertrahedron();
        }
        else
        {
            marching = new MarchingCubes();
        }

        //Surface is the value that represents the surface of mesh
        //For example the perlin noise has a range of -1 to 1 so the mid point is where we want the surface to cut through.
        //The target value does not have to be the mid point it can be any value with in the range.
        marching.Surface = cutoff;

        VolumeFileLoader vfl = GetComponent <VolumeFileLoader>();

        //The size of voxel array.
        int width  = vfl.dataVolume.nx;
        int height = vfl.dataVolume.ny;
        int length = vfl.dataVolume.nz;

        float[] voxels = new float[width * height * length];
        Color[] pixels = vfl.dataVolume.texture.GetPixels();

        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;

                    Color pixel = pixels[idx];
                    if (pixel.a > 0f)
                    {
                        voxels[idx] = pixel.a;
                    }
                }
            }
        }

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

        Debug.Log("Starting marching cubes...");

        //The mesh produced is not optimal. There is one vert for each index.
        //Would need to weld vertices for better quality mesh.
        marching.Generate(voxels, width, height, length, verts, indices);

        /*A mesh in unity can only be made up of 65000 verts,
         | and need to split the verts between multiple meshes. */

        int maxVertsPerMesh = 30000; //must be divisible by 3, ie 3 verts == 1 triangle
        int numMeshes       = verts.Count / maxVertsPerMesh + 1;

        Debug.Log(verts.Count + " vertices scanned.");
        GameObject marchingObject = new GameObject("MarchingObject");

        marchingObject.transform.parent = transform;

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

            /*
             | Creates mesh with default vertices and edges
             */
            Mesh mesh = new Mesh();
            mesh.SetVertices(splitVerts);
            mesh.SetTriangles(splitIndices, 0);
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();

            /*
             |
             */
            GameObject go = new GameObject("Mesh");
            go.transform.parent = marchingObject.transform;
            go.AddComponent <MeshFilter>();
            go.AddComponent <MeshRenderer>();
            go.GetComponent <Renderer>().material = m_material;
            go.GetComponent <MeshFilter>().mesh   = mesh;
            go.transform.localRotation            = Quaternion.Euler(Vector3.zero);
            go.transform.localPosition            = new Vector3((float)-width / 2, (float)-height / 2, (float)-length / 2);

            meshes.Add(go);
        }
        marchingObject.transform.localPosition = Vector3.zero;
        marchingObject.transform.localRotation = Quaternion.Euler(Vector3.zero);
        marchingObject.transform.localScale    = new Vector3(1f / width, 1f / height, 1f / length);
        Debug.Log("Finishing marching cubes...");
        GetComponent <MeshRenderer>().enabled = false;
    }