public MyMarchingCubesMesher()
        {
            //  Cube Edges
            for (int i = 0; i < m_edges.Length; i++)
            {
                m_edges[i] = new MyEdge();
            }

            //  Temporary voxel values, serve as cache between precalc and voxel map - so we don't have to always access voxel maps but can look here
            for (int i = 0; i < m_temporaryVoxels.Length; i++)
            {
                m_temporaryVoxels[i] = new MyTemporaryVoxel();
            }

            //  Array of edges in the cell
            m_edgeVertexCalcCounter = 0;
            m_edgeVertex            = new MyEdgeVertex[CELL_EDGES_SIZE][][][];
            for (int x = 0; x < CELL_EDGES_SIZE; x++)
            {
                m_edgeVertex[x] = new MyEdgeVertex[CELL_EDGES_SIZE][][];
                for (int y = 0; y < CELL_EDGES_SIZE; y++)
                {
                    m_edgeVertex[x][y] = new MyEdgeVertex[CELL_EDGES_SIZE][];
                    for (int z = 0; z < CELL_EDGES_SIZE; z++)
                    {
                        m_edgeVertex[x][y][z] = new MyEdgeVertex[MyMarchingCubesConstants.CELL_EDGE_COUNT];
                        for (int w = 0; w < MyMarchingCubesConstants.CELL_EDGE_COUNT; w++)
                        {
                            m_edgeVertex[x][y][z][w]             = new MyEdgeVertex();
                            m_edgeVertex[x][y][z][w].CalcCounter = 0;
                        }
                    }
                }
            }
        }
        //  Get sun color (or light) from lookup table or calc it
        //  IMPORTANT: At this point normals must be calculated because GetVoxelAmbientAndSun() will be retrieving them from temp table and not checking if there is actual value
        void GetVoxelAmbient(MyTemporaryVoxel temporaryVoxel, ref Vector3I coord, ref Vector3I tempVoxelCoord)
        {
            if (temporaryVoxel.Ambient_CalcCounter != m_temporaryVoxelsCounter)
            {
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //  Ambient light calculation is same for LOD and no-LOD
                //  This formula was choosen by experiments and observation, no real thought is behind it.
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                if (MyPerGameSettings.ConstantVoxelAmbient.HasValue)
                {
                    temporaryVoxel.Ambient             = MyPerGameSettings.ConstantVoxelAmbient.Value;
                    temporaryVoxel.Ambient_CalcCounter = m_temporaryVoxelsCounter;
                    return;
                }

                // Voxel ambient occlusion
                const int VOXELS_CHECK_COUNT = 1;
                var       cache   = m_cache;
                float     ambient = 0f;
                for (int ambientX = -VOXELS_CHECK_COUNT; ambientX <= VOXELS_CHECK_COUNT; ambientX++)
                {
                    for (int ambientY = -VOXELS_CHECK_COUNT; ambientY <= VOXELS_CHECK_COUNT; ambientY++)
                    {
                        for (int ambientZ = -VOXELS_CHECK_COUNT; ambientZ <= VOXELS_CHECK_COUNT; ambientZ++)
                        {
                            Vector3I tmpVoxelCoord = new Vector3I(coord.X + ambientX - 1, coord.Y + ambientY - 1, coord.Z + ambientZ - 1);

                            if ((tmpVoxelCoord.X < 0) || (tmpVoxelCoord.X > (m_sizeMinusOne.X)) ||
                                (tmpVoxelCoord.Y < 0) || (tmpVoxelCoord.Y > (m_sizeMinusOne.Y)) ||
                                (tmpVoxelCoord.Z < 0) || (tmpVoxelCoord.Z > (m_sizeMinusOne.Z)))
                            {
                                //  Ambient occlusion for requested voxel can't be calculated because surounding voxels are outside of the map
                            }
                            else
                            {
                                ambient += (float)cache.Content(coord.X + ambientX, coord.Y + ambientY, coord.Z + ambientZ);
                            }
                        }
                    }
                }

                //  IMPORTANT: We trace 3x3x3 voxels around our voxel. So when dividng to get <0..1> interval, divide by this number.
                ambient /= MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT * (VOXELS_CHECK_COUNT * 2 + 1) * (VOXELS_CHECK_COUNT * 2 + 1) * (VOXELS_CHECK_COUNT * 2 + 1);

                //  Flip the number, so from now dark voxels are 0.0 and light are 1.0
                ambient = 1.0f - ambient;

                //  This values are chosen by trial-and-error
                const float MIN = 0.4f; // 0.1f;
                const float MAX = 0.9f; // 0.6f;

                ambient = MathHelper.Clamp(ambient, MIN, MAX);

                //ambient = (ambient - MIN) / (MAX - MIN);
                //ambient -= 0.5f;

                temporaryVoxel.Ambient             = ambient;
                temporaryVoxel.Ambient_CalcCounter = m_temporaryVoxelsCounter;
            }
        }
        //  Get normal from lookup table or calc it
        void GetVoxelNormal(MyTemporaryVoxel temporaryVoxel, ref Vector3I coord, ref Vector3I voxelCoord, MyTemporaryVoxel centerVoxel)
        {
            if (temporaryVoxel.Normal_CalcCounter != m_temporaryVoxelsCounter)
            {
                if ((voxelCoord.X == 0) || (voxelCoord.X == (m_sizeMinusOne.X)) ||
                    (voxelCoord.Y == 0) || (voxelCoord.Y == (m_sizeMinusOne.Y)) ||
                    (voxelCoord.Z == 0) || (voxelCoord.Z == (m_sizeMinusOne.Z)))
                {
                    //  If asked for normal vector for voxel that is at the voxel map border, we can't compute it by gradient, so return this hack.
                    temporaryVoxel.Normal = centerVoxel.Normal;
                }
                else
                {
                    var     cache  = ThreadLocalCache;
                    Vector3 normal = new Vector3(
                        (cache.Content(coord.X - 1, coord.Y, coord.Z) - cache.Content(coord.X + 1, coord.Y, coord.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT,
                        (cache.Content(coord.X, coord.Y - 1, coord.Z) - cache.Content(coord.X, coord.Y + 1, coord.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT,
                        (cache.Content(coord.X, coord.Y, coord.Z - 1) - cache.Content(coord.X, coord.Y, coord.Z + 1)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT);

                    if (normal.LengthSquared() <= 0.0f)
                    {
                        //  If voxels surounding voxel for which we want to get normal vector are of the same value, their subtracting leads to zero vector and that can't be used. So following line is hack.
                        temporaryVoxel.Normal = centerVoxel.Normal;
                    }
                    else
                    {
                        MyVRageUtils.Normalize(ref normal, out temporaryVoxel.Normal);
                    }
                }
                temporaryVoxel.Normal_CalcCounter = m_temporaryVoxelsCounter;
            }
        }
        //  Get normal from lookup table or calc it
        void GetVoxelNormal(MyTemporaryVoxel temporaryVoxel, ref Vector3I coord, ref Vector3I voxelCoord, MyTemporaryVoxel centerVoxel)
        {
            if (temporaryVoxel.Normal_CalcCounter != m_temporaryVoxelsCounter)
            {
                Vector3I sampleMin = coord - 1;
                Vector3I sampleMax = coord + 1;

                var cache    = m_cache;
                var clampMax = cache.Size3D - 1;
                Vector3I.Max(ref sampleMin, ref Vector3I.Zero, out sampleMin);
                Vector3I.Min(ref sampleMax, ref clampMax, out sampleMax);

                Vector3 normal = new Vector3(
                    (cache.Content(sampleMin.X, coord.Y, coord.Z) - cache.Content(sampleMax.X, coord.Y, coord.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT,
                    (cache.Content(coord.X, sampleMin.Y, coord.Z) - cache.Content(coord.X, sampleMax.Y, coord.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT,
                    (cache.Content(coord.X, coord.Y, sampleMin.Z) - cache.Content(coord.X, coord.Y, sampleMax.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT);

                if (normal.LengthSquared() <= 0.000001f)
                {
                    //  If voxels surounding voxel for which we want to get normal vector are of the same value, their subtracting leads to zero vector and that can't be used. So following line is hack.
                    temporaryVoxel.Normal = centerVoxel.Normal;
                }
                else
                {
                    MyUtils.Normalize(ref normal, out temporaryVoxel.Normal);
                }
                temporaryVoxel.Normal_CalcCounter = m_temporaryVoxelsCounter;
            }
        }
        //  Linearly interpolates position, normal and material on poly-cube edge. Interpolated point is where an isosurface cuts an edge between two vertices, each with their own scalar value.
        void GetVertexInterpolation(MyStorageDataCache cache, MyTemporaryVoxel inputVoxelA, MyTemporaryVoxel inputVoxelB, int edgeIndex)
        {
            MyEdge edge = m_edges[edgeIndex];

            byte contentA  = cache.Content(inputVoxelA.IdxInCache);
            byte contentB  = cache.Content(inputVoxelB.IdxInCache);
            byte materialA = cache.Material(inputVoxelA.IdxInCache);
            byte materialB = cache.Material(inputVoxelB.IdxInCache);

            if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - contentA) < 0.00001f)
            {
                edge.Position = inputVoxelA.Position;
                edge.Normal   = inputVoxelA.Normal;
                edge.Material = materialA;
                edge.Ambient  = inputVoxelA.Ambient;
                return;
            }

            if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - contentB) < 0.00001f)
            {
                edge.Position = inputVoxelB.Position;
                edge.Normal   = inputVoxelB.Normal;
                edge.Material = materialB;
                edge.Ambient  = inputVoxelB.Ambient;
                return;
            }

            float mu = (float)(MyVoxelConstants.VOXEL_ISO_LEVEL - contentA) / (float)(contentB - contentA);

            Debug.Assert(mu > 0.0f && mu < 1.0f);

            edge.Position.X = inputVoxelA.Position.X + mu * (inputVoxelB.Position.X - inputVoxelA.Position.X);
            edge.Position.Y = inputVoxelA.Position.Y + mu * (inputVoxelB.Position.Y - inputVoxelA.Position.Y);
            edge.Position.Z = inputVoxelA.Position.Z + mu * (inputVoxelB.Position.Z - inputVoxelA.Position.Z);

            edge.Normal.X = inputVoxelA.Normal.X + mu * (inputVoxelB.Normal.X - inputVoxelA.Normal.X);
            edge.Normal.Y = inputVoxelA.Normal.Y + mu * (inputVoxelB.Normal.Y - inputVoxelA.Normal.Y);
            edge.Normal.Z = inputVoxelA.Normal.Z + mu * (inputVoxelB.Normal.Z - inputVoxelA.Normal.Z);
            if (MyVRageUtils.IsZero(edge.Normal))
            {
                edge.Normal = inputVoxelA.Normal;
            }
            else
            {
                edge.Normal = MyVRageUtils.Normalize(edge.Normal);
            }

            float mu2 = ((float)contentB) / (((float)contentA) + ((float)contentB));

            edge.Material = (mu2 <= 0.5f) ? materialA : materialB;
            edge.Ambient  = inputVoxelA.Ambient + mu2 * (inputVoxelB.Ambient - inputVoxelA.Ambient);

            return;
        }
        private Vector3I ComputeTemporaryVoxelData(MyStorageData cache, ref Vector3I coord0, int cubeIndex, int lod)
        {
            int coord0LinIdx = coord0.X * m_sX + coord0.Y * m_sY + coord0.Z * m_sZ;

            MyTemporaryVoxel tempVoxel0 = m_temporaryVoxels[coord0LinIdx];
            MyTemporaryVoxel tempVoxel1 = m_temporaryVoxels[coord0LinIdx + m_sX];
            MyTemporaryVoxel tempVoxel2 = m_temporaryVoxels[coord0LinIdx + m_sX + m_sZ];
            MyTemporaryVoxel tempVoxel3 = m_temporaryVoxels[coord0LinIdx + m_sZ];
            MyTemporaryVoxel tempVoxel4 = m_temporaryVoxels[coord0LinIdx + m_sY];
            MyTemporaryVoxel tempVoxel5 = m_temporaryVoxels[coord0LinIdx + m_sX + m_sY];
            MyTemporaryVoxel tempVoxel6 = m_temporaryVoxels[coord0LinIdx + m_sX + m_sY + m_sZ];
            MyTemporaryVoxel tempVoxel7 = m_temporaryVoxels[coord0LinIdx + m_sY + m_sZ];



            Vector3I coord1 = new Vector3I(coord0.X + 1, coord0.Y + 0, coord0.Z + 0);
            Vector3I coord2 = new Vector3I(coord0.X + 1, coord0.Y + 0, coord0.Z + 1);
            Vector3I coord3 = new Vector3I(coord0.X + 0, coord0.Y + 0, coord0.Z + 1);
            Vector3I coord4 = new Vector3I(coord0.X + 0, coord0.Y + 1, coord0.Z + 0);
            Vector3I coord5 = new Vector3I(coord0.X + 1, coord0.Y + 1, coord0.Z + 0);
            Vector3I coord6 = new Vector3I(coord0.X + 1, coord0.Y + 1, coord0.Z + 1);
            Vector3I coord7 = new Vector3I(coord0.X + 0, coord0.Y + 1, coord0.Z + 1);

            Vector3I tempVoxelCoord0 = coord0;
            Vector3I tempVoxelCoord1 = coord1;
            Vector3I tempVoxelCoord2 = coord2;
            Vector3I tempVoxelCoord3 = coord3;
            Vector3I tempVoxelCoord4 = coord4;
            Vector3I tempVoxelCoord5 = coord5;
            Vector3I tempVoxelCoord6 = coord6;
            Vector3I tempVoxelCoord7 = coord7;


            tempVoxel0.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord0);
            tempVoxel1.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord1);
            tempVoxel2.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord2);
            tempVoxel3.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord3);
            tempVoxel4.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord4);
            tempVoxel5.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord5);
            tempVoxel6.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord6);
            tempVoxel7.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord7);

            //tempVoxel0.Position.X = m_originPosition.X + (coord0.X) * m_voxelSizeInMeters;
            //tempVoxel0.Position.Y = m_originPosition.Y + (coord0.Y) * m_voxelSizeInMeters;
            //tempVoxel0.Position.Z = m_originPosition.Z + (coord0.Z) * m_voxelSizeInMeters;

            tempVoxel0.Position.X = (m_voxelStart.X + coord0.X) * m_voxelSizeInMeters;
            tempVoxel0.Position.Y = (m_voxelStart.Y + coord0.Y) * m_voxelSizeInMeters;
            tempVoxel0.Position.Z = (m_voxelStart.Z + coord0.Z) * m_voxelSizeInMeters;


            tempVoxel1.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters;
            tempVoxel1.Position.Y = tempVoxel0.Position.Y;
            tempVoxel1.Position.Z = tempVoxel0.Position.Z;

            tempVoxel2.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters;
            tempVoxel2.Position.Y = tempVoxel0.Position.Y;
            tempVoxel2.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters;

            tempVoxel3.Position.X = tempVoxel0.Position.X;
            tempVoxel3.Position.Y = tempVoxel0.Position.Y;
            tempVoxel3.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters;

            tempVoxel4.Position.X = tempVoxel0.Position.X;
            tempVoxel4.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters;
            tempVoxel4.Position.Z = tempVoxel0.Position.Z;

            tempVoxel5.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters;
            tempVoxel5.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters;
            tempVoxel5.Position.Z = tempVoxel0.Position.Z;

            tempVoxel6.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters;
            tempVoxel6.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters;
            tempVoxel6.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters;

            tempVoxel7.Position.X = tempVoxel0.Position.X;
            tempVoxel7.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters;
            tempVoxel7.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters;

            //  Normals at grid corners (calculated from gradient)
            GetVoxelNormal(tempVoxel0, ref coord0, ref tempVoxelCoord0, tempVoxel0);
            GetVoxelNormal(tempVoxel1, ref coord1, ref tempVoxelCoord1, tempVoxel0);
            GetVoxelNormal(tempVoxel2, ref coord2, ref tempVoxelCoord2, tempVoxel0);
            GetVoxelNormal(tempVoxel3, ref coord3, ref tempVoxelCoord3, tempVoxel0);
            GetVoxelNormal(tempVoxel4, ref coord4, ref tempVoxelCoord4, tempVoxel0);
            GetVoxelNormal(tempVoxel5, ref coord5, ref tempVoxelCoord5, tempVoxel0);
            GetVoxelNormal(tempVoxel6, ref coord6, ref tempVoxelCoord6, tempVoxel0);
            GetVoxelNormal(tempVoxel7, ref coord7, ref tempVoxelCoord7, tempVoxel0);

            //  Ambient occlusion colors at grid corners
            //  IMPORTANT: At this point normals must be calculated because GetVoxelAmbientAndSun() will be retrieving them from temp table and not checking if there is actual value
            GetVoxelAmbient(tempVoxel0, ref coord0, ref tempVoxelCoord0);
            GetVoxelAmbient(tempVoxel1, ref coord1, ref tempVoxelCoord1);
            GetVoxelAmbient(tempVoxel2, ref coord2, ref tempVoxelCoord2);
            GetVoxelAmbient(tempVoxel3, ref coord3, ref tempVoxelCoord3);
            GetVoxelAmbient(tempVoxel4, ref coord4, ref tempVoxelCoord4);
            GetVoxelAmbient(tempVoxel5, ref coord5, ref tempVoxelCoord5);
            GetVoxelAmbient(tempVoxel6, ref coord6, ref tempVoxelCoord6);
            GetVoxelAmbient(tempVoxel7, ref coord7, ref tempVoxelCoord7);

            //  Find the vertices where the surface intersects the cube
            int edgeVal = MyMarchingCubesConstants.EdgeTable[cubeIndex];

            if ((edgeVal & 1) == 1)
            {
                GetVertexInterpolation(cache, tempVoxel0, tempVoxel1, 0);
            }
            if ((edgeVal & 2) == 2)
            {
                GetVertexInterpolation(cache, tempVoxel1, tempVoxel2, 1);
            }
            if ((edgeVal & 4) == 4)
            {
                GetVertexInterpolation(cache, tempVoxel2, tempVoxel3, 2);
            }
            if ((edgeVal & 8) == 8)
            {
                GetVertexInterpolation(cache, tempVoxel3, tempVoxel0, 3);
            }
            if ((edgeVal & 16) == 16)
            {
                GetVertexInterpolation(cache, tempVoxel4, tempVoxel5, 4);
            }
            if ((edgeVal & 32) == 32)
            {
                GetVertexInterpolation(cache, tempVoxel5, tempVoxel6, 5);
            }
            if ((edgeVal & 64) == 64)
            {
                GetVertexInterpolation(cache, tempVoxel6, tempVoxel7, 6);
            }
            if ((edgeVal & 128) == 128)
            {
                GetVertexInterpolation(cache, tempVoxel7, tempVoxel4, 7);
            }
            if ((edgeVal & 256) == 256)
            {
                GetVertexInterpolation(cache, tempVoxel0, tempVoxel4, 8);
            }
            if ((edgeVal & 512) == 512)
            {
                GetVertexInterpolation(cache, tempVoxel1, tempVoxel5, 9);
            }
            if ((edgeVal & 1024) == 1024)
            {
                GetVertexInterpolation(cache, tempVoxel2, tempVoxel6, 10);
            }
            if ((edgeVal & 2048) == 2048)
            {
                GetVertexInterpolation(cache, tempVoxel3, tempVoxel7, 11);
            }

            return(tempVoxelCoord0);
        }
        public MyMarchingCubesMesher()
        {
            //  Cube Edges
            for (int i = 0; i < m_edges.Length; i++)
            {
                m_edges[i] = new MyEdge();
            }

            //  Temporary voxel values, serve as cache between precalc and voxel map - so we don't have to always access voxel maps but can look here
            for (int i = 0; i < m_temporaryVoxels.Length; i++)
            {
                m_temporaryVoxels[i] = new MyTemporaryVoxel();
            }

            //  Array of edges in the cell
            m_edgeVertexCalcCounter = 0;
            m_edgeVertex = new MyEdgeVertex[CELL_EDGES_SIZE][][][];
            for (int x = 0; x < CELL_EDGES_SIZE; x++)
            {
                m_edgeVertex[x] = new MyEdgeVertex[CELL_EDGES_SIZE][][];
                for (int y = 0; y < CELL_EDGES_SIZE; y++)
                {
                    m_edgeVertex[x][y] = new MyEdgeVertex[CELL_EDGES_SIZE][];
                    for (int z = 0; z < CELL_EDGES_SIZE; z++)
                    {
                        m_edgeVertex[x][y][z] = new MyEdgeVertex[MyMarchingCubesConstants.CELL_EDGE_COUNT];
                        for (int w = 0; w < MyMarchingCubesConstants.CELL_EDGE_COUNT; w++)
                        {
                            m_edgeVertex[x][y][z][w] = new MyEdgeVertex();
                            m_edgeVertex[x][y][z][w].CalcCounter = 0;
                        }
                    }
                }
            }
        }
        //  Linearly interpolates position, normal and material on poly-cube edge. Interpolated point is where an isosurface cuts an edge between two vertices, each with their own scalar value.
        void GetVertexInterpolation(MyStorageData cache, MyTemporaryVoxel inputVoxelA, MyTemporaryVoxel inputVoxelB, int edgeIndex)
        {
            MyEdge edge = m_edges[edgeIndex];

            byte contentA = cache.Content(inputVoxelA.IdxInCache);
            byte contentB = cache.Content(inputVoxelB.IdxInCache);
            byte materialA = cache.Material(inputVoxelA.IdxInCache);
            byte materialB = cache.Material(inputVoxelB.IdxInCache);

            if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - contentA) < 0.00001f)
            {
                edge.Position = inputVoxelA.Position;
                edge.Normal = inputVoxelA.Normal;
                edge.Material = materialA;
                edge.Ambient = inputVoxelA.Ambient;
                return;
            }

            if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - contentB) < 0.00001f)
            {
                edge.Position = inputVoxelB.Position;
                edge.Normal = inputVoxelB.Normal;
                edge.Material = materialB;
                edge.Ambient = inputVoxelB.Ambient;
                return;
            }

            float mu = (float)(MyVoxelConstants.VOXEL_ISO_LEVEL - contentA) / (float)(contentB - contentA);
            Debug.Assert(mu > 0.0f && mu < 1.0f);

            edge.Position.X = inputVoxelA.Position.X + mu * (inputVoxelB.Position.X - inputVoxelA.Position.X);
            edge.Position.Y = inputVoxelA.Position.Y + mu * (inputVoxelB.Position.Y - inputVoxelA.Position.Y);
            edge.Position.Z = inputVoxelA.Position.Z + mu * (inputVoxelB.Position.Z - inputVoxelA.Position.Z);
            //edge.Normal = ComputeVertexNormal(ref edge.Position);

            edge.Normal.X = inputVoxelA.Normal.X + mu * (inputVoxelB.Normal.X - inputVoxelA.Normal.X);
            edge.Normal.Y = inputVoxelA.Normal.Y + mu * (inputVoxelB.Normal.Y - inputVoxelA.Normal.Y);
            edge.Normal.Z = inputVoxelA.Normal.Z + mu * (inputVoxelB.Normal.Z - inputVoxelA.Normal.Z);
            if (MyUtils.IsZero(edge.Normal))
                edge.Normal = inputVoxelA.Normal;
            else
                edge.Normal = MyUtils.Normalize(edge.Normal);


            if (MyUtils.IsZero(edge.Normal))
                edge.Normal = inputVoxelA.Normal;

            float mu2 = ((float)contentB) / (((float)contentA) + ((float)contentB));
            edge.Material = (mu2 <= 0.5f) ? materialA : materialB;
            edge.Ambient = inputVoxelA.Ambient + mu2 * (inputVoxelB.Ambient - inputVoxelA.Ambient);

            return;
        }
        //  Get sun color (or light) from lookup table or calc it
        //  IMPORTANT: At this point normals must be calculated because GetVoxelAmbientAndSun() will be retrieving them from temp table and not checking if there is actual value
        void GetVoxelAmbient(MyTemporaryVoxel temporaryVoxel, ref Vector3I coord, ref Vector3I tempVoxelCoord)
        {
            if (temporaryVoxel.Ambient_CalcCounter != m_temporaryVoxelsCounter)
            {
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //  Ambient light calculation is same for LOD and no-LOD
                //  This formula was choosen by experiments and observation, no real thought is behind it.
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                if (MyPerGameSettings.ConstantVoxelAmbient.HasValue)
                {
                    temporaryVoxel.Ambient = MyPerGameSettings.ConstantVoxelAmbient.Value;
                    temporaryVoxel.Ambient_CalcCounter = m_temporaryVoxelsCounter;
                    return;
                }

                // Voxel ambient occlusion
                const int VOXELS_CHECK_COUNT = 1;
                var cache = m_cache;
                float ambient = 0f;
                for (int ambientX = -VOXELS_CHECK_COUNT; ambientX <= VOXELS_CHECK_COUNT; ambientX++)
                {
                    for (int ambientY = -VOXELS_CHECK_COUNT; ambientY <= VOXELS_CHECK_COUNT; ambientY++)
                    {
                        for (int ambientZ = -VOXELS_CHECK_COUNT; ambientZ <= VOXELS_CHECK_COUNT; ambientZ++)
                        {
                            Vector3I tmpVoxelCoord = new Vector3I(coord.X + ambientX - 1, coord.Y + ambientY - 1, coord.Z + ambientZ - 1);

                            if ((tmpVoxelCoord.X < 0) || (tmpVoxelCoord.X > (m_sizeMinusOne.X)) ||
                                (tmpVoxelCoord.Y < 0) || (tmpVoxelCoord.Y > (m_sizeMinusOne.Y)) ||
                                (tmpVoxelCoord.Z < 0) || (tmpVoxelCoord.Z > (m_sizeMinusOne.Z)))
                            {
                                //  Ambient occlusion for requested voxel can't be calculated because surounding voxels are outside of the map
                            }
                            else
                            {
                                ambient += (float)cache.Content(coord.X + ambientX, coord.Y + ambientY, coord.Z + ambientZ);
                            }
                        }
                    }
                }

                //  IMPORTANT: We trace 3x3x3 voxels around our voxel. So when dividng to get <0..1> interval, divide by this number.
                ambient /= MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT * (VOXELS_CHECK_COUNT * 2 + 1) * (VOXELS_CHECK_COUNT * 2 + 1) * (VOXELS_CHECK_COUNT * 2 + 1);

                //  Flip the number, so from now dark voxels are 0.0 and light are 1.0
                ambient = 1.0f - ambient;

                //  This values are chosen by trial-and-error
                const float MIN = 0.4f;// 0.1f;
                const float MAX = 0.9f;// 0.6f;

                ambient = MathHelper.Clamp(ambient, MIN, MAX);

                //ambient = (ambient - MIN) / (MAX - MIN);
                //ambient -= 0.5f;

                temporaryVoxel.Ambient = ambient;
                temporaryVoxel.Ambient_CalcCounter = m_temporaryVoxelsCounter;
            }
        }
        //  Get normal from lookup table or calc it
        void GetVoxelNormal(MyTemporaryVoxel temporaryVoxel, ref Vector3I coord, ref Vector3I voxelCoord, MyTemporaryVoxel centerVoxel)
        {
            if (temporaryVoxel.Normal_CalcCounter != m_temporaryVoxelsCounter)
            {
                Vector3I sampleMin = coord - 1;
                Vector3I sampleMax = coord + 1;

                var cache = m_cache;
                var clampMax = cache.Size3D - 1;
                Vector3I.Max(ref sampleMin, ref Vector3I.Zero, out sampleMin);
                Vector3I.Min(ref sampleMax, ref clampMax, out sampleMax);

                Vector3 normal = new Vector3(
                        (cache.Content(sampleMin.X, coord.Y, coord.Z) - cache.Content(sampleMax.X, coord.Y, coord.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT,
                        (cache.Content(coord.X, sampleMin.Y, coord.Z) - cache.Content(coord.X, sampleMax.Y, coord.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT,
                        (cache.Content(coord.X, coord.Y, sampleMin.Z) - cache.Content(coord.X, coord.Y, sampleMax.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT);

                if (normal.LengthSquared() <= 0.000001f)
                {
                    //  If voxels surounding voxel for which we want to get normal vector are of the same value, their subtracting leads to zero vector and that can't be used. So following line is hack.
                    temporaryVoxel.Normal = centerVoxel.Normal;
                }
                else
                {
                    MyUtils.Normalize(ref normal, out temporaryVoxel.Normal);
                }
                temporaryVoxel.Normal_CalcCounter = m_temporaryVoxelsCounter;
            }
        }
        //  Get normal from lookup table or calc it
        void GetVoxelNormal(MyTemporaryVoxel temporaryVoxel, ref Vector3I coord, ref Vector3I voxelCoord, MyTemporaryVoxel centerVoxel)
        {
            if (temporaryVoxel.Normal_CalcCounter != m_temporaryVoxelsCounter)
            {
                if ((voxelCoord.X == 0) || (voxelCoord.X == (m_sizeMinusOne.X)) ||
                    (voxelCoord.Y == 0) || (voxelCoord.Y == (m_sizeMinusOne.Y)) ||
                    (voxelCoord.Z == 0) || (voxelCoord.Z == (m_sizeMinusOne.Z)))
                {
                    //  If asked for normal vector for voxel that is at the voxel map border, we can't compute it by gradient, so return this hack.
                    temporaryVoxel.Normal = centerVoxel.Normal;
                }
                else
                {
                    var cache = ThreadLocalCache;
                    Vector3 normal = new Vector3(
                            (cache.Content(coord.X - 1, coord.Y, coord.Z) - cache.Content(coord.X + 1, coord.Y, coord.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT,
                            (cache.Content(coord.X, coord.Y - 1, coord.Z) - cache.Content(coord.X, coord.Y + 1, coord.Z)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT,
                            (cache.Content(coord.X, coord.Y, coord.Z - 1) - cache.Content(coord.X, coord.Y, coord.Z + 1)) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT);

                    if (normal.LengthSquared() <= 0.0f)
                    {
                        //  If voxels surounding voxel for which we want to get normal vector are of the same value, their subtracting leads to zero vector and that can't be used. So following line is hack.
                        temporaryVoxel.Normal = centerVoxel.Normal;
                    }
                    else
                    {
                        MyVRageUtils.Normalize(ref normal, out temporaryVoxel.Normal);
                    }
                }
                temporaryVoxel.Normal_CalcCounter = m_temporaryVoxelsCounter;
            }
        }
示例#12
0
        //  Linearly interpolates position, normal and material on poly-cube edge. Interpolated point is where an isosurface cuts an edge between two vertices, each with their own scalar value.
        void GetVertexInterpolation(MyTemporaryVoxel inputVoxelA, MyTemporaryVoxel inputVoxelB, int edgeIndex)
        {
            MyEdge edge = m_edges[edgeIndex];

            if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - inputVoxelA.Content) < 0.00001f)
            {
                edge.Position = inputVoxelA.Position;
                edge.Normal = inputVoxelA.Normal;
                edge.Material = inputVoxelA.Material;
                edge.Ambient = inputVoxelA.Ambient;
                return;
            }

            if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - inputVoxelB.Content) < 0.00001f)
            {
                edge.Position = inputVoxelB.Position;
                edge.Normal = inputVoxelB.Normal;
                edge.Material = inputVoxelB.Material;
                edge.Ambient = inputVoxelB.Ambient;
                return;
            }

            float mu = (float)(MyVoxelConstants.VOXEL_ISO_LEVEL - inputVoxelA.Content) / (float)(inputVoxelB.Content - inputVoxelA.Content);
            System.Diagnostics.Debug.Assert(mu > 0.0f && mu < 1.0f);

            edge.Position.X = inputVoxelA.Position.X + mu * (inputVoxelB.Position.X - inputVoxelA.Position.X);
            edge.Position.Y = inputVoxelA.Position.Y + mu * (inputVoxelB.Position.Y - inputVoxelA.Position.Y);
            edge.Position.Z = inputVoxelA.Position.Z + mu * (inputVoxelB.Position.Z - inputVoxelA.Position.Z);

            edge.Normal.X = inputVoxelA.Normal.X + mu * (inputVoxelB.Normal.X - inputVoxelA.Normal.X);
            edge.Normal.Y = inputVoxelA.Normal.Y + mu * (inputVoxelB.Normal.Y - inputVoxelA.Normal.Y);
            edge.Normal.Z = inputVoxelA.Normal.Z + mu * (inputVoxelB.Normal.Z - inputVoxelA.Normal.Z);
            if (MyMwcUtils.IsZero(edge.Normal))
                edge.Normal = inputVoxelA.Normal;
            else
                edge.Normal = MyMwcUtils.Normalize(edge.Normal);

            float mu2 = ((float)inputVoxelB.Content) / (((float)inputVoxelA.Content) + ((float)inputVoxelB.Content));
            //edge.Material = (mu <= MyVoxelConstants.VOXEL_ISO_LEVEL) ? inputVoxelA.Material : inputVoxelB.Material;
            edge.Material = (mu2 <= 0.5f) ? inputVoxelA.Material : inputVoxelB.Material;

            edge.Ambient = inputVoxelA.Ambient + mu2 * (inputVoxelB.Ambient - inputVoxelA.Ambient);
            //edge.Ambient = inputVoxelA.Ambient + mu * (inputVoxelB.Ambient - inputVoxelA.Ambient);

            return;
        }
示例#13
0
        //  Get sun color (or light) from lookup table or calc it 
        //  IMPORTANT: At this point normals must be calculated because GetVoxelAmbientAndSun() will be retrieving them from temp table and not checking if there is actual value
        void GetVoxelAmbient(MyTemporaryVoxel temporaryVoxel, ref MyMwcVector3Int coord, ref MyMwcVector3Int tempVoxelCoord)
        {
            if (temporaryVoxel.Ambient_CalcCounter != m_temporaryVoxelsCounter)
            {
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //  Ambient light calculation is same for LOD and no-LOD
                //  This formula was choosen by experiments and observation, no real thought is behind it.
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                float ambient = 0;

                /* 3 Point lighting - disabled now, instead used ambient occlusion
                float dot0;
                Vector3.Dot(ref temporaryVoxel.Normal, ref MyVoxelConstants.AMBIENT_LIGHT_DIRECTION_0, out dot0);

                float dot1;
                Vector3.Dot(ref temporaryVoxel.Normal, ref MyVoxelConstants.AMBIENT_LIGHT_DIRECTION_1, out dot1);

                float dot2;
                Vector3.Dot(ref temporaryVoxel.Normal, ref MyVoxelConstants.AMBIENT_LIGHT_DIRECTION_2, out dot2);


                ambient += 1.0f * MathHelper.Clamp(dot0, 0, 1);
                ambient += 0.8f * MathHelper.Clamp(dot1, 0, 1);
                ambient += 0.6f * MathHelper.Clamp(dot2, 0, 1);
                //ambient *= 5;
                ambient = MathHelper.Clamp(ambient, 0, 1);
                ambient = 1 - ambient;
                ambient = 0.8f;
                //ambient *= MyConstants.AMBIENT_COLOR;
                //ambient *= 0.1f + ambient * 0.15f;
                */

                // Voxel ambient occlusion
                const int VOXELS_CHECK_COUNT = 1;
                for (int ambientX = -VOXELS_CHECK_COUNT; ambientX <= VOXELS_CHECK_COUNT; ambientX++)
                {
                    for (int ambientY = -VOXELS_CHECK_COUNT; ambientY <= VOXELS_CHECK_COUNT; ambientY++)
                    {
                        for (int ambientZ = -VOXELS_CHECK_COUNT; ambientZ <= VOXELS_CHECK_COUNT; ambientZ++)
                        {
                            MyMwcVector3Int tmpVoxelCoord = new MyMwcVector3Int(m_voxelStart.X + coord.X + ambientX - 1, m_voxelStart.Y + coord.Y + ambientY - 1, m_voxelStart.Z + coord.Z + ambientZ - 1);

                            if ((tmpVoxelCoord.X < 0) || (tmpVoxelCoord.X > (m_sizeMinusOne.X)) ||
                                (tmpVoxelCoord.Y < 0) || (tmpVoxelCoord.Y > (m_sizeMinusOne.Y)) ||
                                (tmpVoxelCoord.Z < 0) || (tmpVoxelCoord.Z > (m_sizeMinusOne.Z)))
                            {
                                //  Ambient occlusion for requested voxel can't be calculated because surounding voxels are outside of the map
                            }
                            else
                            {
                                if (VOXELS_CHECK_COUNT == 1)
                                {
                                    ambient += (float)GetVoxelContent(coord.X + ambientX, coord.Y + ambientY, coord.Z + ambientZ);
                                }
                                else
                                {
                                    //  IMPORTANT: We trace 3x3x3 voxels around our voxel. So when dividng to get <0..1> interval, divide by this number.
                                    ambient += m_voxelMap.GetVoxelContent(ref tmpVoxelCoord);
                                }
                            }
                        }
                    }
                }

                //  IMPORTANT: We trace 3x3x3 voxels around our voxel. So when dividng to get <0..1> interval, divide by this number.
                ambient /= MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT * (VOXELS_CHECK_COUNT * 2 + 1) * (VOXELS_CHECK_COUNT * 2 + 1) * (VOXELS_CHECK_COUNT * 2 + 1);

                //  Flip the number, so from now dark voxels are 0.0 and light are 1.0
                ambient = 1.0f - ambient;

                //  This values are chosen by trial-and-error
                const float MIN = 0.4f;// 0.1f;
                const float MAX = 0.9f;// 0.6f;

                ambient = MathHelper.Clamp(ambient, MIN, MAX);

                ambient = (ambient - MIN) / (MAX - MIN);
                ambient -= 0.5f;

                temporaryVoxel.Ambient = ambient;
                temporaryVoxel.Ambient_CalcCounter = m_temporaryVoxelsCounter;
            }
        }
示例#14
0
 //  Get material from lookup table or calc it
 void GetVoxelMaterial(MyTemporaryVoxel temporaryVoxel, ref MyMwcVector3Int voxelCoord)
 {
     if (temporaryVoxel.Material_CalcCounter != m_temporaryVoxelsCounter)
     {
         if (m_precalcType == MyLodTypeEnum.LOD0)
         {
             temporaryVoxel.Material = m_voxelMap.GetVoxelMaterial(ref voxelCoord);
         }
         else if (m_precalcType == MyLodTypeEnum.LOD1)
         {
             temporaryVoxel.Material = m_voxelMap.GetDataCellAverageMaterial(ref voxelCoord);
         }
         else
         {
             throw new MyMwcExceptionApplicationShouldNotGetHere();
         }
         temporaryVoxel.Material_CalcCounter = m_temporaryVoxelsCounter;
     }
 }