private MyVoxelRangeType CopyVoxelContents()
        {
            m_temporaryVoxelsCounter++;

            var cache = ThreadLocalCache;

            var rangeStart = m_voxelStart + AffectedRangeOffset;

            Debug.Assert(m_precalcType == MyLodTypeEnum.LOD0 || m_precalcType == MyLodTypeEnum.LOD1);
            var rangeSize = new Vector3I(AffectedRangeSizeChange + ((m_precalcType == MyLodTypeEnum.LOD0)
                ? MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS
                : MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS));
            var rangeEnd = rangeStart + rangeSize - 1;

            cache.Resize(ref rangeSize);

            // for geometry, we need (start = m_voxelStart, size = cellSize+1), but normals are computed as derivative at voxel,
            // so we expand by one to arrive at (start = m_voxelStart - 1, size = cellSize+3)
            m_voxelMap.Storage.ReadRange(cache, true, false, MyVoxelGeometry.GetLodIndex(m_precalcType), ref rangeStart, ref rangeEnd);

            bool allEmpty = true;
            bool allFull  = true;

            for (int i = 0; (i < cache.SizeLinear) && (allEmpty || allFull); i += MyStorageDataCache.StepLinear)
            {
                switch (cache.Content(i))
                {
                case MyVoxelConstants.VOXEL_CONTENT_EMPTY: allFull = false; break;

                case MyVoxelConstants.VOXEL_CONTENT_FULL: allEmpty = false; break;

                default:
                    allEmpty = false;
                    allFull  = false;
                    break;
                }
            }
            var rangeType = allFull ? MyVoxelRangeType.FULL
                : allEmpty ? MyVoxelRangeType.EMPTY
                : MyVoxelRangeType.MIXED;

            if (rangeType == MyVoxelRangeType.MIXED)
            {// we will be creating geometry so need materials too
                m_voxelMap.Storage.ReadRange(cache, false, true, MyVoxelGeometry.GetLodIndex(m_precalcType), ref rangeStart, ref rangeEnd);
            }
            return(rangeType);
        }
示例#2
0
        public static void PaintInShape(
            MyVoxelMap voxelMap,
            MyShape shape,
            byte materialIdx,
            bool updateSync = false)
        {
            Profiler.Begin("MyVoxelGenerator::PaintInShape()");

            if (voxelMap == null)
            {
                return;
            }

            if (updateSync && Sync.IsServer)
            {
                shape.SendPaintRequest(voxelMap.SyncObject, materialIdx);
            }

            Vector3I minCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMin());
            Vector3I maxCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMax());

            voxelMap.FixVoxelCoord(ref minCorner);
            voxelMap.FixVoxelCoord(ref maxCorner);

            m_cache.Resize(ref minCorner, ref maxCorner);
            voxelMap.Storage.ReadRange(m_cache, false, true, MyVoxelGeometry.GetLodIndex(MyLodTypeEnum.LOD0), ref minCorner, ref maxCorner);

            Vector3I tempVoxelCoord;

            for (tempVoxelCoord.X = minCorner.X; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++)
            {
                for (tempVoxelCoord.Y = minCorner.Y; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++)
                {
                    for (tempVoxelCoord.Z = minCorner.Z; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++)
                    {
                        var relPos = tempVoxelCoord - minCorner;
                        m_cache.Material(ref relPos, materialIdx); // set material
                    }
                }
            }

            Profiler.End();
        }
示例#3
0
        public static void CutOutShape(
            MyVoxelMap voxelMap,
            MyShape shape,
            out float voxelsCountInPercent,
            out MyVoxelMaterialDefinition voxelMaterial,
            float removeRatio = 1,
            Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null,
            bool updateSync = true,
            bool onlyCheck  = false)
        {
            Profiler.Begin("MyVoxelGenerator::CutOutShape()");

            if (updateSync && Sync.IsServer)
            {
                shape.SendCutOutRequest(voxelMap.SyncObject, removeRatio);
            }

            int originalSum = 0;
            int removedSum  = 0;

            Vector3I minCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMin());
            Vector3I maxCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMax());

            voxelMap.FixVoxelCoord(ref minCorner);
            voxelMap.FixVoxelCoord(ref maxCorner);

            var cacheMin = minCorner - 1;
            var cacheMax = maxCorner + 1;

            voxelMap.FixVoxelCoord(ref cacheMin);
            voxelMap.FixVoxelCoord(ref cacheMax);
            m_cache.Resize(ref cacheMin, ref cacheMax);
            voxelMap.Storage.ReadRange(m_cache, true, true, MyVoxelGeometry.GetLodIndex(MyLodTypeEnum.LOD0), ref cacheMin, ref cacheMax);

            {
                Vector3I exactCenter = voxelMap.GetVoxelCoordinateFromMeters(shape.GetCenter());
                exactCenter  -= cacheMin;
                exactCenter   = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1);
                voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter));
            }

            Vector3I tempVoxelCoord;

            for (tempVoxelCoord.X = minCorner.X; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++)
            {
                for (tempVoxelCoord.Y = minCorner.Y; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++)
                {
                    for (tempVoxelCoord.Z = minCorner.Z; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++)
                    {
                        var relPos   = tempVoxelCoord - cacheMin; // get original amount
                        var original = m_cache.Content(ref relPos);

                        if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove
                        {
                            continue;
                        }

                        var vpos   = voxelMap.GetVoxelPositionAbsolute(ref tempVoxelCoord);
                        var volume = shape.GetVolume(ref vpos);

                        if (volume == 0f) // if there is no intersection
                        {
                            continue;
                        }

                        var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL);
                        var voxelMat  = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos));
                        var toRemove  = (int)(maxRemove * removeRatio * voxelMat.DamageRatio);
                        if (voxelMap.Storage is MyCellStorage)
                        {
                            if (toRemove < MyCellStorage.Quantizer.GetMinimumQuantizableValue())
                            {
                                toRemove = MyCellStorage.Quantizer.GetMinimumQuantizableValue();
                            }
                        }
                        var newVal  = MathHelper.Clamp(original - toRemove, 0, maxRemove);
                        var removed = Math.Abs(original - newVal);

                        if (!onlyCheck)
                        {
                            m_cache.Content(ref relPos, (byte)newVal);
                        }

                        originalSum += original;
                        removedSum  += removed;

                        if (exactCutOutMaterials != null)
                        {
                            int value = 0;
                            exactCutOutMaterials.TryGetValue(voxelMat, out value);
                            value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed);
                            exactCutOutMaterials[voxelMat] = value;
                        }
                    }
                }
            }

            if (removedSum > 0 && !onlyCheck)
            {
                //  Clear all small voxel that may have been created during explosion. They can be created even outside the range of
                //  explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the
                //  explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we
                //  will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove
                //  B voxels too.
                //!! TODO AR & MK : check if this is needed !!
                RemoveSmallVoxelsUsingChachedVoxels();

                voxelMap.Storage.WriteRange(m_cache, true, false, ref cacheMin, ref cacheMax);
                voxelMap.InvalidateCache(cacheMin, cacheMax);
            }
            voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f;
            Profiler.End();
        }
示例#4
0
        public static void FillInShape(
            MyVoxelMap voxelMap,
            MyShape shape,
            out float voxelsCountInPercent,
            byte materialIdx,
            float fillRatio = 1,
            bool updateSync = false,
            bool onlyCheck  = false)
        {
            Profiler.Begin("MyVoxelGenerator::FillInShape()");

            if (voxelMap == null)
            {
                voxelsCountInPercent = 0f;
                return;
            }

            if (updateSync && Sync.IsServer)
            {
                shape.SendFillRequest(voxelMap.SyncObject, materialIdx, fillRatio);
            }

            int originalSum = 0;
            int filledSum   = 0;

            Vector3I minCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMin() - MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * 1.01f);
            Vector3I maxCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMax() + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * 1.01f);

            voxelMap.FixVoxelCoord(ref minCorner);
            voxelMap.FixVoxelCoord(ref maxCorner);

            m_cache.Resize(ref minCorner, ref maxCorner);
            voxelMap.Storage.ReadRange(m_cache, true, true, MyVoxelGeometry.GetLodIndex(MyLodTypeEnum.LOD0), ref minCorner, ref maxCorner);

            Vector3I tempVoxelCoord;

            for (tempVoxelCoord.X = minCorner.X; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++)
            {
                for (tempVoxelCoord.Y = minCorner.Y; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++)
                {
                    for (tempVoxelCoord.Z = minCorner.Z; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++)
                    {
                        var relPos   = tempVoxelCoord - minCorner; // get original amount
                        var original = m_cache.Content(ref relPos);

                        if (original == MyVoxelConstants.VOXEL_CONTENT_FULL) // if there is nothing to add
                        {
                            continue;
                        }

                        var vpos   = voxelMap.GetVoxelPositionAbsolute(ref tempVoxelCoord);
                        var volume = shape.GetVolume(ref vpos);

                        if (volume <= 0f) // there is nothing to fill
                        {
                            continue;
                        }

                        m_cache.Material(ref relPos, materialIdx); // set material

                        var maxFill = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL);
                        var toFill  = (int)(maxFill * fillRatio);

                        if (original > maxFill)
                        {
                            maxFill = original;
                        }

                        var newVal = MathHelper.Clamp(original + toFill, 0, maxFill);

                        if (!onlyCheck)
                        {
                            m_cache.Content(ref relPos, (byte)newVal);
                        }

                        originalSum += original;
                        filledSum   += original + newVal;
                    }
                }
            }

            if (filledSum > 0 && !onlyCheck)
            {
                voxelMap.Storage.WriteRange(m_cache, true, true, ref minCorner, ref maxCorner);
                voxelMap.InvalidateCache(minCorner - 1, maxCorner + 1);
            }
            voxelsCountInPercent = (originalSum > 0f) ? (float)filledSum / (float)originalSum : 0f;
            Profiler.End();
        }
示例#5
0
        public static void MakeCrater(MyVoxelMap voxelMap, BoundingSphere sphere, Vector3 normal, MyVoxelMaterialDefinition material, ref bool changed, out Vector3I minChanged, out Vector3I maxChanged)
        {
            Profiler.Begin("MakeCrater");
            Vector3I minCorner = voxelMap.GetVoxelCoordinateFromMeters(sphere.Center - (sphere.Radius + MyVoxelConstants.VOXEL_SIZE_IN_METRES));
            Vector3I maxCorner = voxelMap.GetVoxelCoordinateFromMeters(sphere.Center + (sphere.Radius + MyVoxelConstants.VOXEL_SIZE_IN_METRES));

            voxelMap.FixVoxelCoord(ref minCorner);
            voxelMap.FixVoxelCoord(ref maxCorner);

            //  We are tracking which voxels were changed, so we can invalidate only needed cells in the cache
            minChanged = maxCorner;
            maxChanged = minCorner;
            Profiler.Begin("Reading cache");
            m_cache.Resize(ref minCorner, ref maxCorner);
            voxelMap.Storage.ReadRange(m_cache, true, true, MyVoxelGeometry.GetLodIndex(MyLodTypeEnum.LOD0), ref minCorner, ref maxCorner);
            Profiler.End();

            Profiler.Begin("Changing cache");
            int      removedVoxelContent = 0;
            Vector3I tempVoxelCoord;
            Vector3I cachePos;

            for (tempVoxelCoord.Z = minCorner.Z, cachePos.Z = 0; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++, ++cachePos.Z)
            {
                for (tempVoxelCoord.Y = minCorner.Y, cachePos.Y = 0; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++, ++cachePos.Y)
                {
                    for (tempVoxelCoord.X = minCorner.X, cachePos.X = 0; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++, ++cachePos.X)
                    {
                        bool    cellChanged   = false;
                        Vector3 voxelPosition = voxelMap.GetVoxelPositionAbsolute(ref tempVoxelCoord);

                        float addDist = (voxelPosition - sphere.Center).Length();
                        float addDiff = addDist - sphere.Radius;

                        byte newContent;
                        if (addDiff > MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF)
                        {
                            newContent = MyVoxelConstants.VOXEL_CONTENT_EMPTY;
                        }
                        else if (addDiff < -MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF)
                        {
                            newContent = MyVoxelConstants.VOXEL_CONTENT_FULL;
                        }
                        else
                        {
                            //  This formula will work even if diff is positive or negative
                            newContent = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - addDiff / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL);
                        }

                        byte originalContent = m_cache.Content(ref cachePos);

                        if (newContent > originalContent && originalContent > 0)
                        {
                            if (material != null)
                            {
                                m_cache.Material(ref cachePos, material.Index);
                            }

                            cellChanged = true;
                            m_cache.Content(ref cachePos, newContent);
                        }

                        float delDist = (voxelPosition - (sphere.Center + sphere.Radius * 0.7f * normal)).Length();
                        float delDiff = delDist - sphere.Radius;

                        byte contentToRemove;
                        if (delDiff > MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF)
                        {
                            contentToRemove = MyVoxelConstants.VOXEL_CONTENT_EMPTY;
                        }
                        else if (delDiff < -MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF)
                        {
                            contentToRemove = MyVoxelConstants.VOXEL_CONTENT_FULL;
                        }
                        else
                        {
                            //  This formula will work even if diff is positive or negative
                            contentToRemove = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - delDiff / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL);
                        }

                        originalContent = m_cache.Content(ref cachePos);

                        if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY && contentToRemove > MyVoxelConstants.VOXEL_CONTENT_EMPTY)
                        {
                            cellChanged = true;

                            int newVal = originalContent - contentToRemove;
                            if (newVal < MyVoxelConstants.VOXEL_CONTENT_EMPTY)
                            {
                                newVal = MyVoxelConstants.VOXEL_CONTENT_EMPTY;
                            }
                            m_cache.Content(ref cachePos, (byte)newVal);

                            removedVoxelContent += originalContent - newVal;
                        }

                        float setDist = (voxelPosition - (sphere.Center - sphere.Radius * 0.5f * normal)).Length();
                        float setDiff = setDist - sphere.Radius / 4f;

                        if (setDiff <= MyVoxelConstants.VOXEL_SIZE_IN_METRES * 1.5f)  // could be VOXEL_SIZE_IN_METRES_HALF, but we want to set material in empty cells correctly
                        {
                            byte indestructibleContentToSet = MyVoxelConstants.VOXEL_CONTENT_FULL;
                            if (setDiff >= MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF)  // outside
                            {
                                indestructibleContentToSet = MyVoxelConstants.VOXEL_CONTENT_EMPTY;
                            }
                            else if (setDiff >= -MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF)  // boundary
                            {
                                indestructibleContentToSet = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - setDiff / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL);
                            }

                            MyVoxelMaterialDefinition originalMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref cachePos));

                            // Change the material:
                            // - always on boundaries between material and nothing
                            // - smoothly on inner boundaries
                            MyVoxelMaterialDefinition newMaterial = material;
                            if (setDiff > 0)
                            {
                                byte content = m_cache.Content(ref cachePos);
                                if (content == MyVoxelConstants.VOXEL_CONTENT_FULL)
                                {
                                    newMaterial = originalMaterial;
                                }
                                if (setDiff >= MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF && content != MyVoxelConstants.VOXEL_CONTENT_EMPTY)  // set material behind boundary only for empty voxels
                                {
                                    newMaterial = originalMaterial;
                                }
                            }

                            if (originalMaterial == newMaterial)
                            {
                                continue;
                            }

                            m_cache.Material(ref cachePos, newMaterial.Index);
                            cellChanged = true;
                        }

                        float dist = (voxelPosition - sphere.Center).Length();
                        float diff = dist - sphere.Radius;

                        if (diff <= 0f)
                        {
                            originalContent = m_cache.Content(ref cachePos);
                            if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY)
                            {
                                bool result = m_cache.WrinkleVoxelContent(ref cachePos, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_ADD, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_REMOVE);
                                if (cellChanged == false)
                                {
                                    cellChanged = result;
                                }
                            }
                        }

                        if (cellChanged)
                        {
                            if (tempVoxelCoord.X < minChanged.X)
                            {
                                minChanged.X = tempVoxelCoord.X;
                            }
                            if (tempVoxelCoord.Y < minChanged.Y)
                            {
                                minChanged.Y = tempVoxelCoord.Y;
                            }
                            if (tempVoxelCoord.Z < minChanged.Z)
                            {
                                minChanged.Z = tempVoxelCoord.Z;
                            }
                            if (tempVoxelCoord.X > maxChanged.X)
                            {
                                maxChanged.X = tempVoxelCoord.X;
                            }
                            if (tempVoxelCoord.Y > maxChanged.Y)
                            {
                                maxChanged.Y = tempVoxelCoord.Y;
                            }
                            if (tempVoxelCoord.Z > maxChanged.Z)
                            {
                                maxChanged.Z = tempVoxelCoord.Z;
                            }
                            changed = true;
                        }
                    }
                }
            }
            Profiler.End();

            if (changed)
            {
                Profiler.Begin("RemoveSmallVoxelsUsingChachedVoxels");
                RemoveSmallVoxelsUsingChachedVoxels();
                Profiler.BeginNextBlock("Writing cache");
                voxelMap.Storage.WriteRange(m_cache, true, true, ref minCorner, ref maxCorner);
                Profiler.End();
            }

            Profiler.End();
        }
        //  Precalculate voxel cell into cache (makes triangles and vertex buffer from voxels)
        public void Precalc(MyVoxelPrecalcTaskItem task)
        {
            Profiler.Begin("MyVoxelPrecalcTask.Precalc");
            m_precalcType = task.Type;

            m_resultVerticesCounter  = 0;
            m_resultTrianglesCounter = 0;
            m_edgeVertexCalcCounter++;
            m_voxelMap   = task.VoxelMap;
            m_voxelStart = task.VoxelStart;

            int lodIdx = MyVoxelGeometry.GetLodIndex(m_precalcType);

            CalcPolygCubeSize(lodIdx);

            //  Copy voxels into temp array
            //using (Stats.Timing.Measure("NewPrecalc.CopyVoxelContents", MyStatTypeEnum.Sum, clearRateMs: TIMEOUT))
            Profiler.Begin("NewPrecalc.CopyVoxelContents");
            bool isMixed = CopyVoxelContents() == MyVoxelRangeType.MIXED;

            Profiler.End();

            //using (Stats.Timing.Measure("Precalc.Geometry generation", MyStatTypeEnum.Sum, clearRateMs: TIMEOUT))
            Profiler.Begin("Precalc.Geometry generation");
            {
                if (isMixed)
                {
                    var cache = ThreadLocalCache;
                    //  Size of voxel or cell (in meters) and size of voxel map / voxel cells
                    ComputeSizeAndOrigin(lodIdx);

                    var      start  = Vector3I.One;
                    var      end    = m_polygCubes - 1;
                    Vector3I coord0 = start;
                    for (var it = new Vector3I.RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out coord0))
                    {
                        //  We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc.
                        int cubeIndex = 0;
                        if (cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                        {
                            cubeIndex |= 1;
                        }
                        if (cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                        {
                            cubeIndex |= 2;
                        }
                        if (cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                        {
                            cubeIndex |= 4;
                        }
                        if (cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                        {
                            cubeIndex |= 8;
                        }
                        if (cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                        {
                            cubeIndex |= 16;
                        }
                        if (cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                        {
                            cubeIndex |= 32;
                        }
                        if (cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                        {
                            cubeIndex |= 64;
                        }
                        if (cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                        {
                            cubeIndex |= 128;
                        }

                        //  Cube is entirely in/out of the surface
                        if (MyMarchingCubesConstants.EdgeTable[cubeIndex] == 0)
                        {
                            continue;
                        }

                        //  We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc.
                        Vector3I tempVoxelCoord0 = ComputeTemporaryVoxelData(cache, ref coord0, cubeIndex);

                        //  Create the triangles
                        CreateTriangles(ref coord0, cubeIndex, ref tempVoxelCoord0);
                    }
                }
            }
            Profiler.End();

            //using (Stats.Timing.Measure("Precalc.PrepareCache", MyStatTypeEnum.Sum, clearRateMs: TIMEOUT))
            Profiler.Begin("Precalc.PrepareCache");
            {
                // Cache the vertices and triangles and precalculate the octree
                task.Cache.PrepareCache(m_resultVertices, m_resultVerticesCounter, m_resultTriangles, m_resultTrianglesCounter, m_positionScale, m_originPosition, task.Type == MyLodTypeEnum.LOD0);
            }
            Profiler.End();

            Profiler.End();
        }