Ejemplo n.º 1
0
        /// <summary>
        /// Initializes the marching cubes scene by loading the dataset from disk and creating a mesh for it.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();
            _brush = new NormalBrush();
            _pen   = new SolidColorPen(Color.Black);

            var triangleBuilder = new TriangleMeshDescriptionBuilder();
            // isolevel defines which points are inside/outside the structure
            int lastProgress = 0;

            // for each point we will at all 8 points forming a cube, we will simply take the index + 1 in each direction, thus our iteration counters must be reduced by 1 to prevent out of bound exception
            int xlen = InputData.XLength - 1;
            int ylen = InputData.YLength - 1;
            int zlen = InputData.ZLength - 1;

            var mcAlgo = new MarchingCubesAlgorithm(false);
            var box    = new BoundingBox();

            for (int x = 0; x < xlen; x++)
            {
                for (int y = 0; y < ylen; y++)
                {
                    // report progress here as one dimension by itself would progress really fast (too small increments)
                    var progress    = (y + x * ylen) / (float)(ylen * xlen);
                    var newProgress = (int)(progress * 100);
                    if (newProgress >= 100)
                    {
                        newProgress = 99; // don't send 100 yet, send it only once at the end of the method
                    }
                    if (newProgress != lastProgress)
                    {
                        var p = InitializeProgress;
                        p?.Invoke(this, newProgress);
                        lastProgress = newProgress;
                    }
                    for (int z = 0; z < zlen; z++)
                    {
                        box.Min.X = x;
                        box.Min.Y = y;
                        box.Min.Z = z;
                        box.Max.X = x + 1;
                        box.Max.Y = y + 1;
                        box.Max.Z = z + 1;
                        var vertices = mcAlgo.Polygonize(InputData, _isolevel, box);
                        if (vertices != null && vertices.Count > 0)
                        {
                            triangleBuilder.Vertices.AddRange(vertices);
                        }
                    }
                }
            }
            _dataMesh = RenderContext.MeshCreator.CreateMesh(triangleBuilder);

            var i = InitializeProgress;

            i?.Invoke(this, 100);
            InitializeProgress = null;
            Initialized        = true;
        }
Ejemplo n.º 2
0
        private void MarchCube(object sender, DoWorkEventArgs e)
        {
            var count = (int)e.Argument;

            // ideally we would just march the number of provided cubes and everything just works
            // in real life this usually means a lot of calls with count = 1 or other small values in each update
            // this forces the vertexbuffer to move vertices from CPU to GPU RAM everytime we add a few new vertices
            // (each time a new vertexbuffer from the perspective of the GPU when in reality it is the same buffer + ~3 vertices)
            // this not only causes stalls in the pipeline but is also generally very inefficient (and the GPU can't keep up with the changing data, thus eventually throws out of memory exception)

            // instead we add a batchsize of a fixed minimum (e.g. 1000) and only display the requested count ( e.g. 1) to the user
            // upon next request, we simply change the indexpointer as long as we still have enough pregenerated data (in this example for the next 999 calls with count = 1 each)
            // only once we run out the generated vertices will a new batch be generated

            // this drastically reduces the transfer times and prevents the out of memory exceptions

            if (_primitiveCount + count >= _vertices.Count / 3)
            {
                int refCount = count;
                // at least one new vertex must be generated to show all requested to the user
                // generate a new batch, but make sure not to overflow our data

                // make sure we generated no less than our batchsize at any time
                if (refCount < VertexGenerationMinBatchSize)
                {
                    refCount = VertexGenerationMinBatchSize;
                }
                if (_lookupTableWriteIndex + refCount > _filledDataIndices.Length)
                {
                    refCount = _filledDataIndices.Length - _lookupTableWriteIndex;
                }

                for (int i = 0; i < refCount; i++)
                {
                    // our dataset contains all datapoints, even all the empty cubes
                    // we built a lookup table for all the cubes with values, so access it
                    var lookupIndex    = _lookupTableWriteIndex + i;
                    var indexInDataset = _filledDataIndices[lookupIndex];
                    // now we have the actual index for the next cube with values in the dataset

                    // polygonize it
                    var p        = GetPositionFromIndex(indexInDataset);
                    var vertices = _marchingCubesAlgorithm.Polygonize(_inputData, _isoLevel, new BoundingBox(p, p + Vector3.One));
                    if (vertices != null && vertices.Count > 0)
                    {
                        _vertices.AddRange(vertices);
                        // list is always multiple of 3 (3 vertices form a triangle)
                        // add number of newly generated primitives/triangles
                        _primitiveCountPerDataPoint[lookupIndex] = vertices.Count / 3;
                    }
                }
                // update the index
                _lookupTableWriteIndex += refCount;
            }
            // now the vertex array is large enough, update the meshpointer and return
            var lookupTableReadIndex = _lookupTableReadIndex;

            for (int i = 0; i < count; i++)
            {
                var lookup = lookupTableReadIndex + i;
                if (lookup >= _primitiveCountPerDataPoint.Length)
                {
                    break; // end of dataset
                }
                var primitives = _primitiveCountPerDataPoint[lookup];
                _primitiveCount += primitives;
            }
            _lookupTableReadIndex += count;
        }