/*
     * Given a grid cell and an isolevel, calculate the triangular
     * facets required to represent the isosurface through the cell.
     * Return the number of triangular facets, the array "triangles"
     * will be loaded up with the vertices at most 5 triangular facets.
     *  0 will be returned if the grid cell is either totally above
     * of totally below the isolevel.
     */
    public static int Polygonise(GRIDCELL grid, float isolevel, TRIANGLE[] triangles)
    {
        int i, ntriang;
        int cubeindex;

        Vector3[] vertlist = new Vector3[12];

        int[] edgeTable = MarchingCubesConstants.edgeTable;
        int[,] triTable = MarchingCubesConstants.triTable;

        /*
         * Determine the index into the edge table which
         * tells us which vertices are inside of the surface
         */
        cubeindex = 0;
        if (grid.val[0] < isolevel)
        {
            cubeindex |= 1;
        }
        if (grid.val[1] < isolevel)
        {
            cubeindex |= 2;
        }
        if (grid.val[2] < isolevel)
        {
            cubeindex |= 4;
        }
        if (grid.val[3] < isolevel)
        {
            cubeindex |= 8;
        }
        if (grid.val[4] < isolevel)
        {
            cubeindex |= 16;
        }
        if (grid.val[5] < isolevel)
        {
            cubeindex |= 32;
        }
        if (grid.val[6] < isolevel)
        {
            cubeindex |= 64;
        }
        if (grid.val[7] < isolevel)
        {
            cubeindex |= 128;
        }

        /* Cube is entirely in/out of the surface */
        if (edgeTable[cubeindex] == 0)
        {
            return(0);
        }

        /* Find the vertices where the surface intersects the cube */
        if ((edgeTable[cubeindex] & 1) != 0)
        {
            vertlist[0] = VertexInterp(isolevel, grid.p[0], grid.p[1], grid.val[0], grid.val[1]);
        }
        if ((edgeTable[cubeindex] & 2) != 0)
        {
            vertlist[1] = VertexInterp(isolevel, grid.p[1], grid.p[2], grid.val[1], grid.val[2]);
        }
        if ((edgeTable[cubeindex] & 4) != 0)
        {
            vertlist[2] = VertexInterp(isolevel, grid.p[2], grid.p[3], grid.val[2], grid.val[3]);
        }
        if ((edgeTable[cubeindex] & 8) != 0)
        {
            vertlist[3] = VertexInterp(isolevel, grid.p[3], grid.p[0], grid.val[3], grid.val[0]);
        }
        if ((edgeTable[cubeindex] & 16) != 0)
        {
            vertlist[4] = VertexInterp(isolevel, grid.p[4], grid.p[5], grid.val[4], grid.val[5]);
        }
        if ((edgeTable[cubeindex] & 32) != 0)
        {
            vertlist[5] = VertexInterp(isolevel, grid.p[5], grid.p[6], grid.val[5], grid.val[6]);
        }
        if ((edgeTable[cubeindex] & 64) != 0)
        {
            vertlist[6] = VertexInterp(isolevel, grid.p[6], grid.p[7], grid.val[6], grid.val[7]);
        }
        if ((edgeTable[cubeindex] & 128) != 0)
        {
            vertlist[7] = VertexInterp(isolevel, grid.p[7], grid.p[4], grid.val[7], grid.val[4]);
        }
        if ((edgeTable[cubeindex] & 256) != 0)
        {
            vertlist[8] = VertexInterp(isolevel, grid.p[0], grid.p[4], grid.val[0], grid.val[4]);
        }
        if ((edgeTable[cubeindex] & 512) != 0)
        {
            vertlist[9] = VertexInterp(isolevel, grid.p[1], grid.p[5], grid.val[1], grid.val[5]);
        }
        if ((edgeTable[cubeindex] & 1024) != 0)
        {
            vertlist[10] = VertexInterp(isolevel, grid.p[2], grid.p[6], grid.val[2], grid.val[6]);
        }
        if ((edgeTable[cubeindex] & 2048) != 0)
        {
            vertlist[11] = VertexInterp(isolevel, grid.p[3], grid.p[7], grid.val[3], grid.val[7]);
        }

        /* Create the triangle */
        ntriang = 0;
        for (i = 0; triTable[cubeindex, i] != -1; i += 3)
        {
            triangles[ntriang].p    = new Vector3[3];
            triangles[ntriang].p[0] = vertlist[triTable[cubeindex, i]];
            triangles[ntriang].p[1] = vertlist[triTable[cubeindex, i + 1]];
            triangles[ntriang].p[2] = vertlist[triTable[cubeindex, i + 2]];
            ntriang++;
        }

        return(ntriang);
    }
Пример #2
0
    /*
       Linearly interpolate the position where an isosurface cuts
       an edge between two vertices, each with their own scalar value
    */
    static Vector3 VLerp(ref GRIDCELL curCell, double isolevel,
						int ia,int ib,
						ref Vector3 normal,ref Vector2 tex)
    {
        Vector3 p1=curCell.p[ia];
        Vector3 p2=curCell.p[ib];
        Vector3 n1=curCell.n[ia];
        Vector3 n2=curCell.n[ib];
        Vector2 t1=curCell.t[ia];
        Vector2 t2=curCell.t[ib];
        double valp1=curCell.val[ia];
        double valp2=curCell.val[ib];

        float mu;
        Vector3 p = new Vector3 ();
        if (Math.Abs (isolevel - valp1) < 0.00001)
        {	p=p1;
            normal=n1;
            tex=t1;
        }else
        if (Math.Abs (isolevel - valp2) < 0.00001)
        {	p=p2;
            normal=n2;
            tex=t2;
        }else
        if (Math.Abs (valp1 - valp2) < 0.00001)
        {	p=p1;
            normal=n1;
            tex=t1;
        }else{
            mu = (float)((isolevel - valp1) / (valp2 - valp1));
            p=p1+mu*(p2-p1);
            normal=n1+mu*(n2-n1);
            tex=t1+mu*(t2-t1);
        }
        normal.Normalize ();
        return(p);
    }
    //Build a unity mesh from a distance function
    public static Mesh BuildUnityMesh(Vector3 fieldMin, float fieldSize, int gridDims, DistanceFunction func)
    {
        //calc size of 1 cell
        float cellSize = fieldSize / gridDims;

        //allocate and initialize position / value for every grid vertex
        int vertDims = gridDims + 1;

        Vector3[] gridVertPos = new Vector3[vertDims * vertDims * vertDims];
        float[]   gridVertVal = new float[vertDims * vertDims * vertDims];
        for (int x = 0; x < vertDims; x++)
        {
            for (int y = 0; y < vertDims; y++)
            {
                for (int z = 0; z < vertDims; z++)
                {
                    int     idx = x + (y + vertDims * z) * vertDims;
                    Vector3 pos = new Vector3(x, y, z);
                    gridVertPos[idx] = pos * cellSize + fieldMin;
                    gridVertVal[idx] = func(gridVertPos[idx]);
                }
            }
        }

        //vertices and indices we build
        List <Vector3> vertices = new List <Vector3>();
        List <int>     indices  = new List <int>();

        //buffer to contain the generated triangles
        TRIANGLE[] tempTriangles = new TRIANGLE[5];

        //iterate over cells
        GRIDCELL[] cells = new GRIDCELL[gridDims * gridDims * gridDims];
        for (int x = 0; x < gridDims; x++)
        {
            for (int y = 0; y < gridDims; y++)
            {
                for (int z = 0; z < gridDims; z++)
                {
                    //calc cell index
                    int      idx       = x + (y + z * gridDims) * gridDims;
                    Vector3i cellCoord = new Vector3i(x, y, z);

                    //fill cell with corners of unit cube
                    GRIDCELL cell = new GRIDCELL();

                    //transform cell corners + calculate field values
                    cell.p   = new Vector3[8];
                    cell.val = new float[cell.p.Length];
                    for (int i = 0; i < cell.p.Length; i++)
                    {
                        int globalVertIdx = CellVertToGlobalVert(gridDims, cellCoord, i);
                        cell.p[i]   = gridVertPos[globalVertIdx];
                        cell.val[i] = gridVertVal[globalVertIdx];
                    }

                    //polygonise and store vertices (note: had to tweak winding order to make unity happy!)
                    int numTriangles = Polygonise(cell, 0.0f, tempTriangles);
                    for (int i = 0; i < numTriangles; i++)
                    {
                        int vidx = vertices.Count;
                        indices.Add(vidx + 0);
                        indices.Add(vidx + 1);
                        indices.Add(vidx + 2);
                        vertices.Add(tempTriangles[i].p[0]);
                        vertices.Add(tempTriangles[i].p[1]);
                        vertices.Add(tempTriangles[i].p[2]);
                    }
                }
            }
        }

        //build normals using central differences of field
        float          epsilon = 0.0001f;
        Vector3        xd      = Vector3.right * epsilon;
        Vector3        yd      = Vector3.up * epsilon;
        Vector3        zd      = Vector3.forward * epsilon;
        List <Vector3> normals = new List <Vector3>(vertices.Count);

        for (int i = 0; i < vertices.Count; i++)
        {
            Vector3 n = new Vector3(
                func(vertices[i] + xd) - func(vertices[i] - xd),
                func(vertices[i] + yd) - func(vertices[i] - yd),
                func(vertices[i] + zd) - func(vertices[i] - zd));
            normals.Add(n.normalized);
        }

        //fill and return unity mesh
        Mesh m = new Mesh();

        m.Clear();
        m.SetVertices(vertices);
        m.SetNormals(normals);
        m.SetIndices(indices.ToArray(), MeshTopology.Triangles, 0);
        return(m);
    }
Пример #4
0
    /*
       Linearly interpolate the position where an isosurface cuts
       an edge between two vertices, each with their own scalar value
    */
    static Vector3 VertexInterp(ref GRIDCELL curCell, double isolevel,
						Vector3  p1, Vector3 p2,
						double valp1, double valp2, ref Vector3 normal)
    {
        float mu;
        Vector3 p = new Vector3 ();
        normal.x = (float)(curCell.val [0] - curCell.val [1]  );
        normal.y = (float)(curCell.val [0] - curCell.val [3]  );
        normal.z = (float)(curCell.val [0] - curCell.val [4]  );
        normal.Normalize ();
        if (Math.Abs (isolevel - valp1) < 0.00001)
            return(p1);
        if (Math.Abs (isolevel - valp2) < 0.00001)
            return(p2);
        if (Math.Abs (valp1 - valp2) < 0.00001)
            return(p1);
        mu = (float)((isolevel - valp1) / (valp2 - valp1));
        p.x = p1.x + mu * (p2.x - p1.x);
        p.y = p1.y + mu * (p2.y - p1.y);
        p.z = p1.z + mu * (p2.z - p1.z);
        return(p);
    }
Пример #5
0
    public static void Polygonise2(GRIDCELL grid, double isolevel, ref Vector3[] vertlist, ref Vector3[] normals, ref Vector2[] uvs, ref int[] triangles, ref int vertBase, ref int triBase)
    {
        int i;
        int cubeindex;
        //Vector3[] 	vertlist=new Vector3[12];
        /*
          Determine the index into the edge table which
          tells us which vertices are inside of the surface
           */
        cubeindex = 0;
        if (grid.val [0] < isolevel)
            cubeindex |= 1;
        if (grid.val [1] < isolevel)
            cubeindex |= 2;
        if (grid.val [2] < isolevel)
            cubeindex |= 4;
        if (grid.val [3] < isolevel)
            cubeindex |= 8;
        if (grid.val [4] < isolevel)
            cubeindex |= 16;
        if (grid.val [5] < isolevel)
            cubeindex |= 32;
        if (grid.val [6] < isolevel)
            cubeindex |= 64;
        if (grid.val [7] < isolevel)
            cubeindex |= 128;

        /* Cube is entirely in/out of the surface */
        if (edgeTable [cubeindex] == 0)
            return;//(0);

        int[] remap = new int[12];
        int mapTop = 0;

        int[] edgeMap = {
            0,1,
            1,2,
            2,3,
            3,0,
            4,5,
            5,6,
            6,7,
            7,4,
            0,4,
            1,5,
            2,6,
            3,7
        };
        int i2=0;
        for (i=0; i<12; i++) {
            if ((edgeTable [cubeindex] & (1 << i)) != 0) {
                remap [mapTop++] = i;
                normals [vertBase + i] = new Vector3 ();
                int e1=edgeMap[i2];
                int e2=edgeMap[i2+1];
                vertlist [vertBase + i] = VLerp (ref grid, isolevel, e1,e2, ref	normals [vertBase + i],ref uvs[vertBase+i]);
            }
            i2+=2;
         }

        /* Find the vertices where the surface intersects the cube */
        /*
        if ((edgeTable[cubeindex] & 1)!=0){
            remap[mapTop++]=0;
            normals[vertBase+0]=new Vector3();
          vertlist[vertBase+0] =
             VertexInterp(ref grid,isolevel,grid.p[0],grid.p[1],grid.val[0],grid.val[1],ref	normals[vertBase+0]);
        }
           if ((edgeTable[cubeindex] & 2)!=0){
            remap[mapTop++]=1;
            normals[vertBase+1]=new Vector3();
          vertlist[vertBase+1] =
             VertexInterp(ref grid,isolevel,grid.p[1],grid.p[2],grid.val[1],grid.val[2],ref	normals[vertBase+1]);
        }
           if ((edgeTable[cubeindex] & 4)!=0){
            remap[mapTop++]=2;
            normals[vertBase+2]=new Vector3();
          vertlist[vertBase+2] =
             VertexInterp(ref grid,isolevel,grid.p[2],grid.p[3],grid.val[2],grid.val[3],ref	normals[vertBase+2]);
        }
           if ((edgeTable[cubeindex] & 8)!=0){
            remap[mapTop++]=3;
            normals[vertBase+3]=new Vector3();
          vertlist[vertBase+3] =
             VertexInterp(ref grid,isolevel,grid.p[3],grid.p[0],grid.val[3],grid.val[0],ref	normals[vertBase+3]);
        }
           if ((edgeTable[cubeindex] & 16)!=0){
            remap[mapTop++]=4;
            normals[vertBase+4]=new Vector3();
          vertlist[vertBase+4] =
             VertexInterp(ref grid,isolevel,grid.p[4],grid.p[5],grid.val[4],grid.val[5],ref	normals[vertBase+4]);
        }
           if ((edgeTable[cubeindex] & 32)!=0){
            remap[mapTop++]=5;
            normals[vertBase+5]=new Vector3();
          vertlist[vertBase+5] =
             VertexInterp(ref grid,isolevel,grid.p[5],grid.p[6],grid.val[5],grid.val[6],ref	normals[vertBase+5]);
        }
           if ((edgeTable[cubeindex] & 64)!=0){
            remap[mapTop++]=6;
            normals[vertBase+6]=new Vector3();
          vertlist[vertBase+6] =
             VertexInterp(ref grid,isolevel,grid.p[6],grid.p[7],grid.val[6],grid.val[7],ref	normals[vertBase+6]);
        }
           if ((edgeTable[cubeindex] & 128)!=0){
            remap[mapTop++]=7;
            normals[vertBase+7]=new Vector3();
          vertlist[vertBase+7] =
             VertexInterp(ref grid,isolevel,grid.p[7],grid.p[4],grid.val[7],grid.val[4],ref	normals[vertBase+7]);
        }
           if ((edgeTable[cubeindex] & 256)!=0){
            remap[mapTop++]=8;
            normals[vertBase+8]=new Vector3();
          vertlist[vertBase+8] =
             VertexInterp(ref grid,isolevel,grid.p[0],grid.p[4],grid.val[0],grid.val[4],ref	normals[vertBase+8]);
        }
           if ((edgeTable[cubeindex] & 512)!=0){
            remap[mapTop++]=9;
            normals[vertBase+9]=new Vector3();
          vertlist[vertBase+9] =
             VertexInterp(ref grid,isolevel,grid.p[1],grid.p[5],grid.val[1],grid.val[5],ref	normals[vertBase+9]);
        }
           if ((edgeTable[cubeindex] & 1024)!=0){
            remap[mapTop++]=10;
            normals[vertBase+10]=new Vector3();
          vertlist[vertBase+10] =
             VertexInterp(ref grid,isolevel,grid.p[2],grid.p[6],grid.val[2],grid.val[6],ref	normals[vertBase+10]);
        }
           if ((edgeTable[cubeindex] & 2048)!=0){
            remap[mapTop++]=11;
            normals[vertBase+11]=new Vector3();
          vertlist[vertBase+11] =
             VertexInterp(ref grid,isolevel,grid.p[3],grid.p[7],grid.val[3],grid.val[7],ref	normals[vertBase+11]);
        }
        */

        //for (i=0; i<12; i++) {
        //	uvs [vertBase + i] = new Vector2 (vertlist [vertBase + i].x * 0.1f, vertlist [vertBase + i].z * 0.1f);//
        //}

        /* Create the triangle */
        for (i=0; triTable[cubeindex,i]!=-1; i+=3) {
            triangles [triBase++] = triTable [cubeindex, i] + vertBase;
            triangles [triBase++] = triTable [cubeindex, i + 1] + vertBase;
            triangles [triBase++] = triTable [cubeindex, i + 2] + vertBase;
        }
        vertBase += 12;
    }
Пример #6
0
    public static void Polygonise(GRIDCELL grid, double isolevel, ref Vector3[] vertlist, ref Vector3[] normals, ref Vector2[] uvs, ref int[] triangles, ref int vertBase, ref int triBase)
    {
        int i;
        int cubeindex;
        //Vector3[] 	vertlist=new Vector3[12];
        /*
          Determine the index into the edge table which
          tells us which vertices are inside of the surface
           */
        cubeindex = 0;
        if (grid.val [0] < isolevel)
            cubeindex |= 1;
        if (grid.val [1] < isolevel)
            cubeindex |= 2;
        if (grid.val [2] < isolevel)
            cubeindex |= 4;
        if (grid.val [3] < isolevel)
            cubeindex |= 8;
        if (grid.val [4] < isolevel)
            cubeindex |= 16;
        if (grid.val [5] < isolevel)
            cubeindex |= 32;
        if (grid.val [6] < isolevel)
            cubeindex |= 64;
        if (grid.val [7] < isolevel)
            cubeindex |= 128;

        /* Cube is entirely in/out of the surface */
        if (edgeTable [cubeindex] == 0)
            return;//(0);

        int mapTop = 0;

        int[] edgeMap = {
            0,1,
            1,2,
            2,3,
            3,0,
            4,5,
            5,6,
            6,7,
            7,4,
            0,4,
            1,5,
            2,6,
            3,7
        };
        int i2=0;
        /* Find the vertices where the surface intersects the cube */
        for (i=0; i<12; i++) {
            int vi=remap[i]=mapTop++;
            if ((edgeTable [cubeindex] & (1 << i)) != 0) {
                //normals [vertBase + vi] = new Vector3 ();
                int e1=edgeMap[i2];
                int e2=edgeMap[i2+1];
                vertlist [vertBase + vi] = VLerp (ref grid, isolevel, e1,e2, ref normals [vertBase + vi],ref uvs[vertBase+vi]);
            }
            i2+=2;
        }

        //		for (i=0; i<12; i++) {
            //Store material values in the uv channels..
            //Reflective..
        //			uvs [vertBase + i] = new Vector2 (vertlist [vertBase + i].x * 0.1f, vertlist [vertBase + i].z * 0.1f);
        //		}

        /* Create the triangle */
        for (i=0; triTable[cubeindex,i]!=-1; i+=3) {
            triangles [triBase++] = triTable [cubeindex, i] + vertBase;
            triangles [triBase++] = triTable [cubeindex, i + 1] + vertBase;
            triangles [triBase++] = triTable [cubeindex, i + 2] + vertBase;
        }
        vertBase += 12;
    }
Пример #7
0
	public MarchingCubes(Vector3 MaxSize, int resolution_) {
		resolution = resolution_;
		gridSize = new Vector3(resolution, resolution, resolution);
		//gxgy = resolution * resolution;
		//numxyz = resolution * resolution * resolution;	// totalNumberOfPoints
		worlddim = MaxSize;
		worldstride = new Vector3(gridSize.x / MaxSize.x, gridSize.y / MaxSize.y, gridSize.z / MaxSize.z);
		datastride = new Vector3(MaxSize.x / gridSize.x, MaxSize.y / gridSize.y, MaxSize.z / gridSize.z);
		worldcenter = new Vector3(MaxSize.x / 2.0f, MaxSize.y / 2.0f, MaxSize.z / 2.0f);
		WorldSize = new Vector3(resolution, resolution, resolution);
		for (int i = 0; i < 5; i++) {
			triangles.Add(new TRIANGLE());
		}
		//isolevel = 0.0161f;
		grid = new GRIDCELL();
	}
Пример #8
0
    //Build a unity mesh from a distance function
    public static Mesh BuildUnityMesh(Vector3 fieldMin, float fieldSize, int gridDims, DistanceFunction func)
    {
        //vertices and indices we build
        List <Vector3> vertices = new List <Vector3>();
        List <int>     indices  = new List <int>();

        //buffer to contain the generated triangles
        TRIANGLE[] tempTriangles = new MarchingCubesBasicPort.TRIANGLE[5];

        //calc size of 1 cell
        float cellSize = fieldSize / gridDims;

        //iterate over cells
        GRIDCELL[] cells = new MarchingCubesBasicPort.GRIDCELL[gridDims * gridDims * gridDims];
        for (int x = 0; x < gridDims; x++)
        {
            for (int y = 0; y < gridDims; y++)
            {
                for (int z = 0; z < gridDims; z++)
                {
                    //calc cell index
                    int idx = x + (y + z * gridDims) * gridDims;

                    //fill cell with corners of unit cube
                    GRIDCELL cell = new GRIDCELL();
                    cell.p = new Vector3[]
                    {
                        new Vector3(x + 0, y + 0, z + 0),
                        new Vector3(x + 1, y + 0, z + 0),
                        new Vector3(x + 1, y + 0, z + 1),
                        new Vector3(x + 0, y + 0, z + 1),
                        new Vector3(x + 0, y + 1, z + 0),
                        new Vector3(x + 1, y + 1, z + 0),
                        new Vector3(x + 1, y + 1, z + 1),
                        new Vector3(x + 0, y + 1, z + 1)
                    };

                    //transform cell corners + calculate field values
                    cell.val = new float[cell.p.Length];
                    for (int i = 0; i < cell.p.Length; i++)
                    {
                        cell.p[i]   = cell.p[i] * cellSize + fieldMin;
                        cell.val[i] = func(cell.p[i]);
                    }

                    //polygonise and store vertices
                    int numTriangles = Polygonise(cell, 0.0f, tempTriangles);
                    for (int i = 0; i < numTriangles; i++)
                    {
                        int vidx = vertices.Count;
                        indices.Add(vidx + 0);
                        indices.Add(vidx + 1);
                        indices.Add(vidx + 2);
                        vertices.Add(tempTriangles[i].p[0]);
                        vertices.Add(tempTriangles[i].p[1]);
                        vertices.Add(tempTriangles[i].p[2]);
                    }
                }
            }
        }

        //build normals using central differences of field
        float          epsilon = 0.0001f;
        Vector3        xd      = Vector3.right * epsilon;
        Vector3        yd      = Vector3.up * epsilon;
        Vector3        zd      = Vector3.forward * epsilon;
        List <Vector3> normals = new List <Vector3>(vertices.Count);

        for (int i = 0; i < vertices.Count; i++)
        {
            Vector3 n = new Vector3(
                func(vertices[i] + xd) - func(vertices[i] - xd),
                func(vertices[i] + yd) - func(vertices[i] - yd),
                func(vertices[i] + zd) - func(vertices[i] - zd));
            normals.Add(n.normalized);
        }

        //fill and return unity mesh
        Mesh m = new Mesh();

        m.Clear();
        m.SetVertices(vertices);
        m.SetNormals(normals);
        m.SetIndices(indices.ToArray(), MeshTopology.Triangles, 0);
        return(m);
    }