public void Init(
                Vector3 positionOffset, Vector3 positionScale,
                Vector3[] positions, int vertexCount,
                MyVoxelTriangle[] triangles, int triangleCount)
            {
                if (vertexCount == 0)
                {
                    VoxelVerticesCount = 0;
                    VoxelTrianglesCount = 0;
                    m_octree = null;
                    m_positions = null;
                    return;
                }
                Debug.Assert(vertexCount <= Int16.MaxValue);

                // copy voxel vertices
                m_positionOffset = positionOffset;
                m_positionScale = positionScale;
                m_positions = new Vector3[vertexCount];
                Array.Copy(positions, m_positions, vertexCount);

                ProfilerShort.Begin("build octree");
                if (m_octree == null)
                    m_octree = new MyOctree();
                m_octree.Init(m_positions, vertexCount, triangles, triangleCount, out VoxelTriangles);
                ProfilerShort.End();

                // set size only after the arrays are fully allocated
                VoxelVerticesCount = vertexCount;
                VoxelTrianglesCount = triangleCount;
            }
Пример #2
0
 private void GetCellLineIntersectionOctree(ref MyIntersectionResultLineTriangle?result, ref Line modelSpaceLine, ref float?minDistanceUntilNow, CellData cachedDataCell, IntersectionFlags flags)
 {
     m_overlapElementCache.Clear();
     if (cachedDataCell.Octree != null)
     {
         Vector3 vector;
         Vector3 vector2;
         cachedDataCell.GetPackedPosition(ref modelSpaceLine.From, out vector);
         cachedDataCell.GetPackedPosition(ref modelSpaceLine.To, out vector2);
         Ray ray = new Ray(vector, vector2 - vector);
         cachedDataCell.Octree.GetIntersectionWithLine(ref ray, m_overlapElementCache);
     }
     for (int i = 0; i < m_overlapElementCache.Count; i++)
     {
         int index = m_overlapElementCache[i];
         if ((cachedDataCell.VoxelTriangles != null) && (index < cachedDataCell.VoxelTriangles.Length))
         {
             MyTriangle_Vertices vertices;
             MyVoxelTriangle     triangle = cachedDataCell.VoxelTriangles[index];
             cachedDataCell.GetUnpackedPosition(triangle.V0, out vertices.Vertex0);
             cachedDataCell.GetUnpackedPosition(triangle.V1, out vertices.Vertex1);
             cachedDataCell.GetUnpackedPosition(triangle.V2, out vertices.Vertex2);
             Vector3 normalVectorFromTriangle = MyUtils.GetNormalVectorFromTriangle(ref vertices);
             if (normalVectorFromTriangle.IsValid() && (((flags & IntersectionFlags.FLIPPED_TRIANGLES) != ((IntersectionFlags)0)) || (Vector3.Dot(modelSpaceLine.Direction, normalVectorFromTriangle) <= 0f)))
             {
                 float?lineTriangleIntersection = MyUtils.GetLineTriangleIntersection(ref modelSpaceLine, ref vertices);
                 if ((lineTriangleIntersection != null) && ((result == 0) || (lineTriangleIntersection.Value < result.Value.Distance)))
                 {
                     minDistanceUntilNow = new float?(lineTriangleIntersection.Value);
                     result = new MyIntersectionResultLineTriangle(0, ref vertices, ref normalVectorFromTriangle, lineTriangleIntersection.Value);
                 }
             }
         }
     }
 }
Пример #3
0
        private void GetCellLineIntersectionOctree(ref MyIntersectionResultLineTriangle?result, ref Line modelSpaceLine, ref float?minDistanceUntilNow, CellData cachedDataCell, IntersectionFlags flags)
        {
            m_overlapElementCache.Clear();
            if (cachedDataCell.Octree != null)
            {
                Vector3 packedStart, packedEnd;
                cachedDataCell.GetPackedPosition(ref modelSpaceLine.From, out packedStart);
                cachedDataCell.GetPackedPosition(ref modelSpaceLine.To, out packedEnd);
                var ray = new Ray(packedStart, packedEnd - packedStart);
                cachedDataCell.Octree.GetIntersectionWithLine(ref ray, m_overlapElementCache);
            }

            for (int j = 0; j < m_overlapElementCache.Count; j++)
            {
                var i = m_overlapElementCache[j];

                if (cachedDataCell.VoxelTriangles == null) //probably not calculated yet
                {
                    continue;
                }

                // this should never happen
                if (i >= cachedDataCell.VoxelTriangles.Length)
                {
                    Debug.Assert(i < cachedDataCell.VoxelTriangles.Length);
                    continue;
                }

                MyVoxelTriangle voxelTriangle = cachedDataCell.VoxelTriangles[i];

                MyTriangle_Vertexes triangleVertices;
                cachedDataCell.GetUnpackedPosition(voxelTriangle.VertexIndex0, out triangleVertices.Vertex0);
                cachedDataCell.GetUnpackedPosition(voxelTriangle.VertexIndex1, out triangleVertices.Vertex1);
                cachedDataCell.GetUnpackedPosition(voxelTriangle.VertexIndex2, out triangleVertices.Vertex2);

                Vector3 calculatedTriangleNormal = MyUtils.GetNormalVectorFromTriangle(ref triangleVertices);
                if (!calculatedTriangleNormal.IsValid())
                {
                    continue;
                }
                //We dont want backside intersections
                if (((int)(flags & IntersectionFlags.FLIPPED_TRIANGLES) == 0) &&
                    Vector3.Dot(modelSpaceLine.Direction, calculatedTriangleNormal) > 0)
                {
                    continue;
                }

                // AABB intersection test removed, AABB is tested inside BVH
                float?distance = MyUtils.GetLineTriangleIntersection(ref modelSpaceLine, ref triangleVertices);

                //  If intersection occured and if distance to intersection is closer to origin than any previous intersection
                if ((distance != null) && ((result == null) || (distance.Value < result.Value.Distance)))
                {
                    minDistanceUntilNow = distance.Value;
                    result = new MyIntersectionResultLineTriangle(ref triangleVertices, ref calculatedTriangleNormal, distance.Value);
                }
            }
        }
Пример #4
0
        internal void BuildCell(
            MyPrecalcJobRender.Args args,
            MyIsoMesh highResMesh,
            MyIsoMesh lowResMesh,
            List <MyClipmapCellBatch> outBatches,
            out MyClipmapCellMeshMetadata meta)
        {
            ProfilerShort.Begin("MyRenderCellBuilder.BuildCell");
            Debug.Assert(highResMesh != null);

            meta.Cell           = args.Cell;
            meta.PositionOffset = highResMesh.PositionOffset;
            meta.PositionScale  = highResMesh.PositionScale;
            meta.LocalAabb      = BoundingBox.CreateInvalid();

            m_lowVertices.SetSize(0);
            m_highVertices.SetSize(0);

            ProcessLowMesh(highResMesh, lowResMesh);

            //  Increase lookup count, so we will think that all vertices in helper arrays are new
            foreach (var lookup in SM_BatchLookups.Values)
            {
                lookup.ResetBatch();
            }


            for (int i = 0; i < highResMesh.VerticesCount; i++)
            {
                MyVoxelVertex vertex;
                ProcessHighVertex(highResMesh, i, out vertex);
            }

            if (lowResMesh != null)
            {
                m_highGrid.ClearFast();

                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    Vector3 position = m_highVertices[i].Position;
                    m_highGrid.AddPoint(ref position, i);
                }

                //TODO: Fix ocassional bad triangles on asteroid

                /*
                 * //Closest vertex
                 * for (int l = 0; l < m_lowVertices.Count; l++)
                 * {
                 *  Vector3 targetPosition = m_lowVertices[l].Target.Position;
                 *
                 *  int bestV = -1;
                 *  float ldist = float.MaxValue;
                 *  float startMeters = 1;
                 *  float maxDistance = 10;
                 *
                 *  MyVector3Grid<int>.Enumerator points = default(MyVector3Grid<int>.Enumerator);
                 *  while (startMeters < maxDistance)
                 *  {
                 *      points = m_highGrid.GetPointsCloserThan(ref targetPosition, startMeters);
                 *
                 *      while (points.MoveNext())
                 *      {
                 *          var dist = Vector3.DistanceSquared(targetPosition, m_highVertices[points.Current].Position);
                 *          if (dist < ldist)
                 *          {
                 *              ldist = dist;
                 *              bestV = points.Current;
                 *          }
                 *      }
                 *
                 *      if (bestV != -1)
                 *          break;
                 *
                 *      startMeters += 1;
                 *  }
                 *
                 *  if (bestV != -1)
                 *  {
                 *      var vtx = m_highVertices[bestV];
                 *      vtx.PositionMorph = m_lowVertices[l].Target.Position;
                 *      vtx.NormalMorph = m_lowVertices[l].Target.Normal;
                 *      vtx.MaterialMorph = m_lowVertices[l].Target.Material;
                 *      vtx.AmbientMorph = m_lowVertices[l].Target.Ambient;
                 *      m_highVertices[bestV] = vtx;
                 *  }
                 *  else
                 *  {
                 *  }
                 * }
                 *
                 */

                //Closest vertex
                float largestDistance = float.MinValue;
                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    float ldist = float.MaxValue;
                    int   bestV = -1;

                    for (int l = 0; l < m_lowVertices.Count; l++)
                    {
                        var dist = Vector3.DistanceSquared(m_lowVertices[l].Target.Position, m_highVertices[i].Position);
                        if (dist < ldist)
                        {
                            ldist = dist;
                            bestV = l;
                        }
                    }

                    var highVertex = m_highVertices[i];
                    highVertex.PositionMorph = m_lowVertices[bestV].Target.Position;
                    highVertex.NormalMorph   = m_lowVertices[bestV].Target.Normal;
                    highVertex.MaterialMorph = m_lowVertices[bestV].Target.Material;
                    highVertex.AmbientMorph  = m_lowVertices[bestV].Target.Ambient;

                    float p1 = highVertex.Position.AbsMax();
                    if (p1 > largestDistance)
                    {
                        largestDistance = p1;
                    }
                    float p2 = highVertex.PositionMorph.AbsMax();
                    if (p2 > largestDistance)
                    {
                        largestDistance = p2;
                    }

                    m_highVertices[i] = highVertex;
                }

                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    MyVoxelVertex vertex = m_highVertices[i];

                    vertex.Position      /= largestDistance;
                    vertex.PositionMorph /= largestDistance;

                    m_highVertices[i] = vertex;
                }

                meta.PositionScale *= largestDistance;
            }

            //Create batches
            for (int i = 0; i < m_highVertices.Count; i++)
            {
                MyVoxelVertex vertex = m_highVertices[i];

                meta.LocalAabb.Include(vertex.Position * meta.PositionScale + meta.PositionOffset);
                meta.LocalAabb.Include(vertex.PositionMorph * meta.PositionScale + meta.PositionOffset);

                Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
            }

            for (int i = 0; i < highResMesh.TrianglesCount; i++)
            {
                MyVoxelTriangle srcTriangle = highResMesh.Triangles[i];
                MyVoxelVertex   vertex0     = m_highVertices[srcTriangle.VertexIndex0];
                MyVoxelVertex   vertex1     = m_highVertices[srcTriangle.VertexIndex1];
                MyVoxelVertex   vertex2     = m_highVertices[srcTriangle.VertexIndex2];

                if (vertex0.Material == vertex1.Material &&
                    vertex0.Material == vertex2.Material &&
                    vertex0.Material == vertex0.MaterialMorph &&
                    vertex0.Material == vertex1.MaterialMorph &&
                    vertex0.Material == vertex2.MaterialMorph)
                { // single material
                    var matIdx = vertex0.Material;

                    //  This is single-texture triangleVertexes, so we can choose material from any edge
                    SingleMaterialHelper materialHelper;
                    if (!SM_Helpers.TryGetValue(matIdx, out materialHelper))
                    {
                        if (!SM_HelperPool.TryDequeue(out materialHelper))
                        {
                            materialHelper = new SingleMaterialHelper();
                        }
                        materialHelper.Material = matIdx;
                        SM_Helpers.Add(matIdx, materialHelper);
                    }

                    VertexInBatchLookup batchLookup;
                    if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup))
                    {
                        if (!SM_BatchLookupPool.TryDequeue(out batchLookup))
                        {
                            batchLookup = new VertexInBatchLookup();
                        }
                        SM_BatchLookups.Add(matIdx, batchLookup);
                    }

                    AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0);
                    AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1);
                    AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2);

                    //  Add indices
                    int nextTriangleIndex = materialHelper.IndexCount;
                    materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0);
                    materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1);
                    materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2);
                    materialHelper.IndexCount += 3;

                    if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) ||
                        (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP))
                    {
                        //  If this batch is almost full (or is full), we end it and start with new one
                        EndSingleMaterial(materialHelper, outBatches);
                    }
                }
                else
                {
                    Vector3I materials = GetMaterials(ref vertex0, ref vertex1, ref vertex2);
                    Debug.Assert(materials.X < 1 << 10, "Too many materials");
                    Debug.Assert(materials.Y < 1 << 10, "Too many materials");
                    Debug.Assert(materials.Z < 1 << 10, "Too many materials");
                    int id = materials.X + (materials.Y + (materials.Z << 10) << 10);

                    // Assign current material
                    MultiMaterialHelper helper = null;
                    if (!MM_Helpers.TryGetValue(id, out helper))
                    {
                        if (!MM_HelperPool.TryDequeue(out helper))
                        {
                            helper = new MultiMaterialHelper();
                        }
                        helper.Material0 = materials.X;
                        helper.Material1 = materials.Y;
                        helper.Material2 = materials.Z;
                        MM_Helpers.Add(id, helper);
                    }

                    helper.AddVertex(ref vertex0);
                    helper.AddVertex(ref vertex1);
                    helper.AddVertex(ref vertex2);

                    if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                }
            }

            { //renderCell.End();
                foreach (var helper in SM_Helpers.Values)
                {
                    Debug.Assert(helper != null);
                    if (helper.IndexCount > 0)
                    {
                        EndSingleMaterial(helper, outBatches);
                    }
                    helper.IndexCount  = 0;
                    helper.VertexCount = 0;
                    SM_HelperPool.Enqueue(helper);
                }
                SM_Helpers.Clear();

                foreach (var helper in MM_Helpers.Values)
                {
                    if (helper.Vertices.Count > 0)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                    helper.Vertices.Clear();
                    MM_HelperPool.Enqueue(helper);
                }
                MM_Helpers.Clear();

                foreach (var lookup in SM_BatchLookups.Values)
                {
                    SM_BatchLookupPool.Enqueue(lookup);
                }
                SM_BatchLookups.Clear();
            }

            m_morphMap.Clear();
            meta.BatchCount = outBatches.Count;
            ProfilerShort.End();
        }
Пример #5
0
        internal void BuildCell(
            MyPrecalcJobRender.Args args,
            MyIsoMesh highResMesh,
            MyIsoMesh lowResMesh,
            List <MyClipmapCellBatch> outBatches,
            out MyClipmapCellMeshMetadata meta)
        {
            Debug.Assert(highResMesh != null);

            meta.Cell           = args.Cell;
            meta.PositionOffset = highResMesh.PositionOffset;
            meta.PositionScale  = highResMesh.PositionScale;
            meta.LocalAabb      = BoundingBox.CreateInvalid();

            m_lowVertices.Clear();
            m_highVertices.Clear();
            m_lowToHighMapping.Clear();
            m_highToLowMapping.Clear();
            m_highTriangles.Clear();


            ProcessLowMesh(highResMesh, lowResMesh);

            //  Increase lookup count, so we will think that all vertices in helper arrays are new
            foreach (var lookup in SM_BatchLookups.Values)
            {
                lookup.ResetBatch();
            }

            //for (int i = 0; i < highResMesh.TrianglesCount; i++)
            //{
            //    var v0 = highResMesh.Triangles[i].VertexIndex0;
            //    var v1 = highResMesh.Triangles[i].VertexIndex1;
            //    var v2 = highResMesh.Triangles[i].VertexIndex2;

            //    MyVoxelVertex vertex;
            //    ProcessHighVertex(highResMesh, v0, ref meta, out vertex);
            //    ProcessHighVertex(highResMesh, v1, ref meta, out vertex);
            //    ProcessHighVertex(highResMesh, v2, ref meta, out vertex);

            //    m_highTriangles.Add(new MyVoxelTriangle()
            //    {
            //        VertexIndex0 = (ushort)(i * 3),
            //        VertexIndex1 = (ushort)(i * 3 + 1),
            //        VertexIndex2 = (ushort)(i * 3 + 2),
            //    });
            //}

            for (int i = 0; i < highResMesh.TrianglesCount; i++)
            {
                m_highTriangles.Add(highResMesh.Triangles[i]);
            }
            for (int i = 0; i < highResMesh.VerticesCount; i++)
            {
                MyVoxelVertex vertex;
                ProcessHighVertex(highResMesh, i, ref meta, out vertex);
            }

            if (lowResMesh != null)
            {
                //Closest vertex

                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    float ldist = float.MaxValue;
                    int   bestV = -1;

                    for (int l = 0; l < m_lowVertices.Count; l++)
                    {
                        var dist = Vector3.DistanceSquared(m_lowVertices[l].Target.Position, m_highVertices[i].Position);
                        if (dist < ldist)
                        {
                            ldist = dist;
                            bestV = l;
                        }
                    }

                    var vtx = m_highVertices[i];
                    vtx.PositionMorph = m_lowVertices[bestV].Target.Position;
                    vtx.Normal        = m_lowVertices[bestV].Target.Normal;
                    vtx.Material      = m_lowVertices[bestV].Target.Material;
                    vtx.Ambient       = m_lowVertices[bestV].Target.Ambient;
                    m_highVertices[i] = vtx;
                }



                ////



                //HashSet<int> alreadySetHighTris = new HashSet<int>();

                ////all low tris must have at least one tri from high set, otherwise holes appear.
                //for (int l = 0; l < lowResMesh.TrianglesCount; l++)
                //{
                //    float triDist = float.MaxValue;
                //    int bestT = -1;

                //    for (int i = 0; i < m_highTriangles.Count; i++)
                //    {
                //        if (alreadySetHighTris.Contains(i))
                //            continue;

                //        float dist = 0;
                //        dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);

                //        if (dist < triDist)
                //        {
                //            triDist = dist;
                //            bestT = i;
                //        }
                //    }

                //    if (bestT == -1)
                //    {
                //        //Happens when LOD0 has less tris than LOD1
                //        bestT = 0;
                //    }

                //    alreadySetHighTris.Add(bestT);

                //    var v0 = m_highVertices[m_highTriangles[bestT].VertexIndex0];
                //    v0.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position;
                //    v0.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Normal;
                //    v0.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Ambient;
                //    m_highVertices[m_highTriangles[bestT].VertexIndex0] = v0;

                //    var v1 = m_highVertices[m_highTriangles[bestT].VertexIndex1];
                //    v1.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position;
                //    v1.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Normal;
                //    v1.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Ambient;
                //    m_highVertices[m_highTriangles[bestT].VertexIndex1] = v1;

                //    var v2 = m_highVertices[m_highTriangles[bestT].VertexIndex2];
                //    v2.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position;
                //    v2.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Normal;
                //    v2.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Ambient;
                //    m_highVertices[m_highTriangles[bestT].VertexIndex2] = v2;
                //}


                //List<MyVoxelTriangle> restHighTriangles = new List<MyVoxelTriangle>(m_highTriangles);
                //List<int> toRemove = new List<int>();
                //foreach (var i in alreadySetHighTris)
                //{
                //    toRemove.Add(i);
                //}
                //toRemove.Sort();

                //for (int i = toRemove.Count - 1; i >= 0; i--)
                //{
                //    restHighTriangles.RemoveAt(toRemove[i]);
                //}



                //for (int i = 0; i < restHighTriangles.Count; i++)
                //{
                //    float triDist = float.MaxValue;
                //    int bestT = -1;

                //    int swtch = 0;


                //    for (int l = 0; l < lowResMesh.TrianglesCount; l++)
                //    {
                //        float dist = 0;
                //        dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);

                //        float dist1 = 0;
                //        dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);
                //        dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);
                //        dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);

                //        float dist2 = 0;
                //        dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);
                //        dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);
                //        dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);

                //        int sw = 0;

                //        if (dist1 < dist && dist1 < dist2)
                //        {
                //            dist = dist1;
                //            sw = 1;
                //        }

                //        if (dist2 < dist && dist2 < dist1)
                //        {
                //            dist = dist2;
                //            sw = 2;
                //        }

                //        if (dist < triDist)
                //        {
                //            triDist = dist;
                //            bestT = l;
                //            swtch = sw;
                //        }
                //    }


                //    //bestT = i % lowResMesh.TrianglesCount;
                //    //bestT = MyUtils.GetRandomInt(lowResMesh.TrianglesCount);

                //    int vi0 = lowResMesh.Triangles[bestT].VertexIndex0;
                //    int vi1 = lowResMesh.Triangles[bestT].VertexIndex1;
                //    int vi2 = lowResMesh.Triangles[bestT].VertexIndex2;

                //    if (swtch == 1)
                //    {
                //        vi0 = lowResMesh.Triangles[bestT].VertexIndex1;
                //        vi1 = lowResMesh.Triangles[bestT].VertexIndex2;
                //        vi2 = lowResMesh.Triangles[bestT].VertexIndex0;
                //    }

                //    if (swtch == 2)
                //    {
                //        vi0 = lowResMesh.Triangles[bestT].VertexIndex2;
                //        vi1 = lowResMesh.Triangles[bestT].VertexIndex0;
                //        vi2 = lowResMesh.Triangles[bestT].VertexIndex1;
                //    }

                //    var v0 = m_highVertices[restHighTriangles[i].VertexIndex0];
                //    v0.PositionMorph = m_lowVertices[vi0].Target.Position;
                //    v0.NormalMorph = m_lowVertices[vi0].Target.Normal;
                //    v0.AmbientMorph = m_lowVertices[vi0].Target.Ambient;
                //    m_highVertices[restHighTriangles[i].VertexIndex0] = v0;

                //    var v1 = m_highVertices[restHighTriangles[i].VertexIndex1];
                //    v1.PositionMorph = m_lowVertices[vi1].Target.Position;
                //    v1.NormalMorph = m_lowVertices[vi1].Target.Normal;
                //    v1.AmbientMorph = m_lowVertices[vi1].Target.Ambient;
                //    m_highVertices[restHighTriangles[i].VertexIndex1] = v1;

                //    var v2 = m_highVertices[restHighTriangles[i].VertexIndex2];
                //    v2.PositionMorph = m_lowVertices[vi2].Target.Position;
                //    v2.NormalMorph = m_lowVertices[vi2].Target.Normal;
                //    v2.AmbientMorph = m_lowVertices[vi2].Target.Ambient;
                //    m_highVertices[restHighTriangles[i].VertexIndex2] = v2;

                //}

                ////add low lod
                //for (int i = 0; i < lowResMesh.TrianglesCount; i++)
                //{
                //    var lt = lowResMesh.Triangles[i];

                //    m_highTriangles.Add(new MyVoxelTriangle()
                //    {
                //        VertexIndex0 = (ushort)(lt.VertexIndex0 + m_highVertices.Count),
                //        VertexIndex1 = (ushort)(lt.VertexIndex1 + m_highVertices.Count),
                //        VertexIndex2 = (ushort)(lt.VertexIndex2 + m_highVertices.Count),
                //    }
                //    );
                //}

                //for (int i = 0; i < m_lowVertices.Count; i++)
                //{
                //    var vertex = new MyVoxelVertex();
                //    vertex.Position = m_lowVertices[i].Target.Position;
                //    vertex.Normal = m_lowVertices[i].Target.Normal;
                //    vertex.Material = m_lowVertices[i].Target.Material;
                //    vertex.Ambient = 0;
                //    vertex.PositionMorph = vertex.Position;
                //    vertex.NormalMorph = vertex.Normal;
                //    vertex.MaterialMorph = vertex.Material;
                //    vertex.AmbientMorph = vertex.Ambient;
                //    m_highVertices.Add(vertex);
                //}


                //    List<MyVoxelTriangle> newTriangles = new List<MyVoxelTriangle>();

                //    for (int i = 0; i < m_highTriangles.Count; i++)
                //    {
                //        MyVoxelVertex v0 = m_highVertices[m_highTriangles[i].VertexIndex0];
                //        MyVoxelVertex v1 = m_highVertices[m_highTriangles[i].VertexIndex1];
                //        MyVoxelVertex v2 = m_highVertices[m_highTriangles[i].VertexIndex2];

                //        for (int v = 0; v < m_highVertices.Count; v++)
                //        {
                //            if (v0.Position == m_highVertices[v].Position)
                //            {
                //                if (v0.PositionMorph == m_highVertices[v].PositionMorph)
                //                {
                //                    var t = m_highTriangles[i];
                //                    t.VertexIndex0 = (ushort)v;
                //                    m_highTriangles[i] = t;
                //                    break;
                //                }
                //                else
                //                {
                //                    var vert1 = m_highVertices[m_highTriangles[i].VertexIndex1];
                //                    var vert2 = m_highVertices[m_highTriangles[i].VertexIndex2];

                //                    vert1.Position = m_highVertices[v].Position;
                //                    vert2.Position = m_highVertices[v].Position;

                //                    m_highVertices.Add(vert1);
                //                    m_highVertices.Add(vert2);

                //                    newTriangles.Add(new MyVoxelTriangle()
                //                    {
                //                        VertexIndex0 = (ushort)v,
                //                        VertexIndex1 = (ushort)(m_highVertices.Count - 2),
                //                        VertexIndex2 = (ushort)(m_highVertices.Count - 1)
                //                    });
                //                }
                //            }
                //        }

                //        for (int v = 0; v < m_highVertices.Count; v++)
                //        {
                //            if (v1.Position == m_highVertices[v].Position)
                //            {
                //                if (v1.PositionMorph == m_highVertices[v].PositionMorph)
                //                {
                //                    var t = m_highTriangles[i];
                //                    t.VertexIndex1 = (ushort)v;
                //                    m_highTriangles[i] = t;
                //                    break;
                //                }
                //                else
                //                {
                //                    var vert0 = m_highVertices[m_highTriangles[i].VertexIndex0];
                //                    var vert2 = m_highVertices[m_highTriangles[i].VertexIndex2];

                //                    vert0.Position = m_highVertices[v].Position;
                //                    vert2.Position = m_highVertices[v].Position;

                //                    m_highVertices.Add(vert0);
                //                    m_highVertices.Add(vert2);

                //                    newTriangles.Add(new MyVoxelTriangle()
                //                    {
                //                        VertexIndex0 = (ushort)(m_highVertices.Count - 2),
                //                        VertexIndex1 = (ushort)v,
                //                        VertexIndex2 = (ushort)(m_highVertices.Count - 1)
                //                    });
                //                }

                //            }
                //        }

                //        for (int v = 0; v < m_highVertices.Count; v++)
                //        {
                //            if (v2.Position == m_highVertices[v].Position)
                //            {
                //                if (v2.PositionMorph == m_highVertices[v].PositionMorph)
                //                {
                //                    var t = m_highTriangles[i];
                //                    t.VertexIndex2 = (ushort)v;
                //                    m_highTriangles[i] = t;
                //                    break;
                //                }
                //                else
                //                {
                //                    var vert0 = m_highVertices[m_highTriangles[i].VertexIndex0];
                //                    var vert1 = m_highVertices[m_highTriangles[i].VertexIndex1];

                //                    vert0.Position = m_highVertices[v].Position;
                //                    vert1.Position = m_highVertices[v].Position;

                //                    m_highVertices.Add(vert0);
                //                    m_highVertices.Add(vert1);

                //                    newTriangles.Add(new MyVoxelTriangle()
                //                    {
                //                        VertexIndex0 = (ushort)(m_highVertices.Count - 2),
                //                        VertexIndex1 = (ushort)(m_highVertices.Count - 1),
                //                        VertexIndex2 = (ushort)v
                //                    });
                //                }

                //            }
                //        }
                //    }


                //    foreach (var t in newTriangles)
                //    {
                //        m_highTriangles.Add(t);
                //    }


                float largestDistance = float.MinValue;
                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    MyVoxelVertex vertex = m_highVertices[i];
                    float         p1     = vertex.Position.AbsMax();
                    if (p1 > largestDistance)
                    {
                        largestDistance = p1;
                    }
                    float p2 = vertex.PositionMorph.AbsMax();
                    if (p2 > largestDistance)
                    {
                        largestDistance = p2;
                    }
                }


                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    MyVoxelVertex vertex = m_highVertices[i];

                    vertex.Position      /= largestDistance;
                    vertex.PositionMorph /= largestDistance;

                    m_highVertices[i] = vertex;
                }

                meta.PositionScale *= largestDistance;
            }
            else
            {
            }



            for (int i = 0; i < m_highVertices.Count; i++)
            {
                MyVoxelVertex vertex = m_highVertices[i];

                meta.LocalAabb.Include(vertex.Position * meta.PositionScale + meta.PositionOffset);
                meta.LocalAabb.Include(vertex.PositionMorph * meta.PositionScale + meta.PositionOffset);

                Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
            }


            for (int i = 0; i < m_highTriangles.Count; i++)
            {
                MyVoxelTriangle srcTriangle = m_highTriangles[i];
                MyVoxelVertex   vertex0, vertex1, vertex2;
                vertex0 = m_highVertices[srcTriangle.VertexIndex0];
                vertex1 = m_highVertices[srcTriangle.VertexIndex1];
                vertex2 = m_highVertices[srcTriangle.VertexIndex2];

                if (vertex0.Material == vertex1.Material &&
                    vertex0.Material == vertex2.Material &&
                    vertex0.Material == vertex0.MaterialMorph &&
                    vertex0.Material == vertex1.MaterialMorph &&
                    vertex0.Material == vertex2.MaterialMorph)
                { // single material
                    var matIdx = vertex0.Material;

                    //  This is single-texture triangleVertexes, so we can choose material from any edge
                    SingleMaterialHelper materialHelper;
                    if (!SM_Helpers.TryGetValue(matIdx, out materialHelper))
                    {
                        if (!SM_HelperPool.TryDequeue(out materialHelper))
                        {
                            materialHelper = new SingleMaterialHelper();
                        }
                        materialHelper.Material = matIdx;
                        SM_Helpers.Add(matIdx, materialHelper);
                    }

                    VertexInBatchLookup batchLookup;
                    if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup))
                    {
                        if (!SM_BatchLookupPool.TryDequeue(out batchLookup))
                        {
                            batchLookup = new VertexInBatchLookup();
                        }
                        SM_BatchLookups.Add(matIdx, batchLookup);
                    }

                    AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0);
                    AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1);
                    AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2);

                    //  Add indices
                    int nextTriangleIndex = materialHelper.IndexCount;
                    materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0);
                    materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1);
                    materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2);
                    materialHelper.IndexCount += 3;

                    if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) ||
                        (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP))
                    {
                        //  If this batch is almost full (or is full), we end it and start with new one
                        EndSingleMaterial(materialHelper, outBatches);
                    }
                }
                else
                {
                    Vector3I materials          = GetMaterials(ref vertex0, ref vertex1, ref vertex2);
                    var      voxelMaterialCount = MyDefinitionManager.Static.VoxelMaterialCount;
                    int      id = materials.X + voxelMaterialCount * (materials.Y + materials.Z * voxelMaterialCount);

                    // Assign current material
                    MultiMaterialHelper helper = null;
                    if (!MM_Helpers.TryGetValue(id, out helper))
                    {
                        if (!MM_HelperPool.TryDequeue(out helper))
                        {
                            helper = new MultiMaterialHelper();
                        }
                        helper.Material0 = materials.X;
                        helper.Material1 = materials.Y;
                        helper.Material2 = materials.Z;
                        MM_Helpers.Add(id, helper);
                    }

                    helper.AddVertex(ref vertex0);
                    helper.AddVertex(ref vertex1);
                    helper.AddVertex(ref vertex2);

                    if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                }
            }

            { //renderCell.End();
                foreach (var helper in SM_Helpers.Values)
                {
                    Debug.Assert(helper != null);
                    if (helper.IndexCount > 0)
                    {
                        EndSingleMaterial(helper, outBatches);
                    }
                    helper.IndexCount  = 0;
                    helper.VertexCount = 0;
                    SM_HelperPool.Enqueue(helper);
                }
                SM_Helpers.Clear();

                foreach (var helper in MM_Helpers.Values)
                {
                    if (helper.Vertices.Count > 0)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                    helper.Vertices.Clear();
                    MM_HelperPool.Enqueue(helper);
                }
                MM_Helpers.Clear();

                foreach (var lookup in SM_BatchLookups.Values)
                {
                    SM_BatchLookupPool.Enqueue(lookup);
                }
                SM_BatchLookups.Clear();
            }

            m_morphMap.Clear();
        }
Пример #6
0
        public void Init(Vector3[] positions, int vertexCount, MyVoxelTriangle[] triangles, int triangleCount, out MyVoxelTriangle[] sortedTriangles)
        {
            for (int i = 0; i < NODE_COUNT; i++)
            {
                m_firstTriangleIndex[i] = 0;
                m_triangleCount[i] = 0;
            }
            for (int i = 0; i < 9; i++)
            {
                m_childEmpty[i] = 0;
            }

            // compute bounding box
            {
                BoundingBox bbox = BoundingBox.CreateInvalid();
                for (int i = 0; i < vertexCount; i++)
                    bbox.Include(ref positions[i]);
                m_bbMin = bbox.Min;
                var scale = bbox.Max - bbox.Min;

                m_bbInvScale = Vector3.One;  // minimum bounding box size = 1 (in each dimension)
                if (scale.X > 1) m_bbInvScale.X = 1 / scale.X;
                if (scale.Y > 1) m_bbInvScale.Y = 1 / scale.Y;
                if (scale.Z > 1) m_bbInvScale.Z = 1 / scale.Z;
            }

            // compute triangle counts
            for (int i = 0; i < triangleCount; i++)
            {
                var t = triangles[i];
                BoundingBox bbox = BoundingBox.CreateInvalid();
                bbox.Include(ref positions[t.VertexIndex0],
                             ref positions[t.VertexIndex1],
                             ref positions[t.VertexIndex2]);
                short count = m_triangleCount[GetNode(ref bbox)]++;
            }

            // accumulate triangle counts
            m_firstTriangleIndex[0] = m_triangleCount[0];
            for (int i = 1; i < NODE_COUNT; i++)
            {
                m_firstTriangleIndex[i] = (short)(m_firstTriangleIndex[i - 1] + m_triangleCount[i]);
            }
            // m_firstTriangleIndex[i] now contains the first index AFTER where the node's triangles will be, e.g.:
            //   m_triangleCount:      2 0 4 3
            //   m_firstTriangleIndex: 2 2 6 9

            // bucketsort triangles into the output array according to the nodes they're in
            var newSortedTriangles = new MyVoxelTriangle[triangleCount];
            for (int i = 0; i < triangleCount; i++)
            {
                var t = triangles[i];
                BoundingBox bbox = BoundingBox.CreateInvalid();
                bbox.Include(ref positions[t.VertexIndex0],
                             ref positions[t.VertexIndex1],
                             ref positions[t.VertexIndex2]);
                newSortedTriangles[--m_firstTriangleIndex[GetNode(ref bbox)]] = t;
            }
            sortedTriangles = newSortedTriangles;  // "out sortedTriangles" may be the same as "triangles"

            // find empty children
            for (int i = NODE_COUNT - 1; i > 0; i--)
                if (m_triangleCount[i] == 0 && (i > 8 || m_childEmpty[i] == 0xFF)) // no triangles AND (no children OR all children empty)
                    m_childEmpty[i - 1 >> 3] |= (byte)(1 << (i - 1 & 7));
        }
Пример #7
0
        public bool Intersects(ref BoundingSphereD localSphere)
        {
            MyPrecalcComponent.AssertUpdateThread();

            //  Get min and max cell coordinate where boundingBox can fit
            BoundingBoxD sphereBoundingBox = BoundingBoxD.CreateInvalid();

            sphereBoundingBox.Include(ref localSphere);
            Vector3I cellCoordMin, cellCoordMax;

            {
                Vector3D minD = sphereBoundingBox.Min;
                Vector3D maxD = sphereBoundingBox.Max;
                MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref minD, out cellCoordMin);
                MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref maxD, out cellCoordMax);
            }

            //  Fix min and max cell coordinates so they don't overlap the voxelmap
            ClampCellCoord(ref cellCoordMin);
            ClampCellCoord(ref cellCoordMax);

            MyCellCoord cell = new MyCellCoord();

            for (cell.CoordInLod.X = cellCoordMin.X; cell.CoordInLod.X <= cellCoordMax.X; cell.CoordInLod.X++)
            {
                for (cell.CoordInLod.Y = cellCoordMin.Y; cell.CoordInLod.Y <= cellCoordMax.Y; cell.CoordInLod.Y++)
                {
                    for (cell.CoordInLod.Z = cellCoordMin.Z; cell.CoordInLod.Z <= cellCoordMax.Z; cell.CoordInLod.Z++)
                    {
                        //  If no overlap between bounding box of data cell and the sphere
                        BoundingBox cellBoundingBox;
                        MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref cell.CoordInLod, out cellBoundingBox);
                        if (cellBoundingBox.Intersects(ref localSphere) == false)
                        {
                            continue;
                        }

                        //  Get cell from cache. If not there, precalc it and store in the cache.
                        //  If null is returned, we know that cell doesn't contain any triangleVertexes so we don't need to do intersections.
                        CellData cachedData = GetCell(ref cell);

                        if (cachedData == null)
                        {
                            continue;
                        }

                        for (int i = 0; i < cachedData.VoxelTrianglesCount; i++)
                        {
                            MyVoxelTriangle voxelTriangle = cachedData.VoxelTriangles[i];

                            MyTriangle_Vertexes triangle;
                            cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex0, out triangle.Vertex0);
                            cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex1, out triangle.Vertex1);
                            cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex2, out triangle.Vertex2);

                            BoundingBox localTriangleAABB = BoundingBox.CreateInvalid();
                            localTriangleAABB.Include(ref triangle.Vertex0);
                            localTriangleAABB.Include(ref triangle.Vertex1);
                            localTriangleAABB.Include(ref triangle.Vertex2);

                            //  First test intersection of triangle's bounding box with line's bounding box. And only if they overlap or intersect, do further intersection tests.
                            if (localTriangleAABB.Intersects(ref localSphere))
                            {
                                PlaneD trianglePlane = new PlaneD(triangle.Vertex0, triangle.Vertex1, triangle.Vertex2);

                                if (MyUtils.GetSphereTriangleIntersection(ref localSphere, ref trianglePlane, ref triangle) != null)
                                {
                                    //  If intersection found - we are finished. We don't need to look for more.
                                    return(true);
                                }
                            }
                        }
                    }
                }
            }

            return(false);
        }
Пример #8
0
        public unsafe bool Intersects(ref BoundingSphere localSphere)
        {
            Vector3I    vectori;
            Vector3I    vectori2;
            BoundingBox box = BoundingBox.CreateInvalid();

            box.Include(ref localSphere);
            Vector3 min = box.Min;
            Vector3 max = box.Max;

            MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref min, out vectori);
            MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref max, out vectori2);
            this.ClampCellCoord(ref vectori);
            this.ClampCellCoord(ref vectori2);
            MyCellCoord cell = new MyCellCoord {
                CoordInLod = { X = vectori.X }
            };

            while (cell.CoordInLod.X <= vectori2.X)
            {
                cell.CoordInLod.Y = vectori.Y;
                while (true)
                {
                    if (cell.CoordInLod.Y > vectori2.Y)
                    {
                        int *numPtr3 = (int *)ref cell.CoordInLod.X;
                        numPtr3[0]++;
                        break;
                    }
                    cell.CoordInLod.Z = vectori.Z;
                    while (true)
                    {
                        BoundingBox box2;
                        if (cell.CoordInLod.Z > vectori2.Z)
                        {
                            int *numPtr2 = (int *)ref cell.CoordInLod.Y;
                            numPtr2[0]++;
                            break;
                        }
                        MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref cell.CoordInLod, out box2);
                        if (box2.Intersects(ref localSphere))
                        {
                            CellData data = this.GetCell(ref cell);
                            if (data != null)
                            {
                                for (int i = 0; i < data.VoxelTrianglesCount; i++)
                                {
                                    MyTriangle_Vertices vertices;
                                    MyVoxelTriangle     triangle = data.VoxelTriangles[i];
                                    data.GetUnpackedPosition(triangle.V0, out vertices.Vertex0);
                                    data.GetUnpackedPosition(triangle.V1, out vertices.Vertex1);
                                    data.GetUnpackedPosition(triangle.V2, out vertices.Vertex2);
                                    BoundingBox box3 = BoundingBox.CreateInvalid();
                                    box3.Include(ref vertices.Vertex0);
                                    box3.Include(ref vertices.Vertex1);
                                    box3.Include(ref vertices.Vertex2);
                                    if (box3.Intersects(ref localSphere))
                                    {
                                        Plane trianglePlane = new Plane(vertices.Vertex0, vertices.Vertex1, vertices.Vertex2);
                                        if (MyUtils.GetSphereTriangleIntersection(ref localSphere, ref trianglePlane, ref vertices) != null)
                                        {
                                            return(true);
                                        }
                                    }
                                }
                            }
                        }
                        int *numPtr1 = (int *)ref cell.CoordInLod.Z;
                        numPtr1[0]++;
                    }
                }
            }
            return(false);
        }
Пример #9
0
        internal void BuildCell(
            MyPrecalcJobRender.Args args,
            MyIsoMesh highResMesh,
            MyIsoMesh lowResMesh,
            List <MyClipmapCellBatch> outBatches,
            out Vector3D positionOffset,
            out Vector3 positionScale,
            out BoundingBox localBoundingBox)
        {
            Debug.Assert(highResMesh != null);

            {
                positionOffset = highResMesh.PositionOffset;
                positionScale  = highResMesh.PositionScale;
            }

            {
                // Find low resolution LoD vertices to map to
                float vertexCellSizeInParentLod = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1));
                float collisionThreshold        = 0.0001f * vertexCellSizeInParentLod * vertexCellSizeInParentLod;
                if (lowResMesh != null)
                {
                    /*
                     * Derived transformation of normalized coordinates from low res mesh to high res mesh.
                     * _l is for low res, _h for high res, x is vertex position
                     * x = x_l * scale_l + offset_l
                     * x_h = (x - offset_h) / scale_h
                     * x_h = ((x_l * scale_l + offset_l) - offset_h) / scale_h
                     * x_h = (x_l * scale_l + offset_l - offset_h) / scale_h
                     * x_h = x_l * (scale_l / scale_h) + ((offset_l - offset_h) / scale_h)
                     */
                    Vector3 morphOffset, morphScale;
                    morphScale  = lowResMesh.PositionScale / highResMesh.PositionScale;
                    morphOffset = (Vector3)(lowResMesh.PositionOffset - highResMesh.PositionOffset) / highResMesh.PositionScale;
                    for (int i = 0; i < lowResMesh.VerticesCount; ++i)
                    {
                        var vertex = new Vertex
                        {
                            Target = new MorphData {
                                Position = lowResMesh.Positions[i] * morphScale + morphOffset,
                                Normal   = lowResMesh.Normals[i],
                                Material = lowResMesh.Materials[i],
                            },
                            Cell = lowResMesh.Cells[i],
                        };

                        if (m_morphMap.ContainsKey(vertex.Cell))
                        {
                            var collidedVertex = m_morphMap[vertex.Cell];
                            Debug.Assert(collidedVertex.Cell == vertex.Cell);

                            var collisionDist2 = (collidedVertex.Target.Position - vertex.Target.Position).LengthSquared();
                            if (collisionDist2 > collisionThreshold)
                            {
                                //Debug.Fail(string.Format("Collision between vertices! {0} > {1}", collisionDist2, collisionThreshold));
                                m_collisionList.Add(collidedVertex);
                            }
                        }
                        m_morphMap[vertex.Cell] = vertex;
                    }
                }

#if false
                ProcessMorphTargetCollisions(args, vertexCellSizeInParentLod);
#endif

#if false
                EnsureMorphTargetExists(args, highResMesh);
#endif
            }

            localBoundingBox = BoundingBox.CreateInvalid();

            //  Increase lookup count, so we will think that all vertices in helper arrays are new
            foreach (var lookup in SM_BatchLookups.Values)
            {
                lookup.ResetBatch();
            }

            for (int i = 0; i < highResMesh.Triangles.Count; i++)
            {
                MyVoxelTriangle srcTriangle = highResMesh.Triangles[i];
                MyVoxelVertex   vertex0, vertex1, vertex2;
                ProcessVertex(highResMesh, srcTriangle.VertexIndex0, ref localBoundingBox, ref positionScale, ref positionOffset, out vertex0);
                ProcessVertex(highResMesh, srcTriangle.VertexIndex1, ref localBoundingBox, ref positionScale, ref positionOffset, out vertex1);
                ProcessVertex(highResMesh, srcTriangle.VertexIndex2, ref localBoundingBox, ref positionScale, ref positionOffset, out vertex2);

                if (MyPerGameSettings.ConstantVoxelAmbient.HasValue)
                {
                    vertex0.Ambient = vertex1.Ambient = vertex2.Ambient = MyPerGameSettings.ConstantVoxelAmbient.Value;
                }

                if (vertex0.Material == vertex1.Material &&
                    vertex0.Material == vertex2.Material &&
                    vertex0.Material == vertex0.MaterialMorph &&
                    vertex0.Material == vertex1.MaterialMorph &&
                    vertex0.Material == vertex2.MaterialMorph)
                { // single material
                    var matIdx = vertex0.Material;

                    //  This is single-texture triangleVertexes, so we can choose material from any edge
                    SingleMaterialHelper materialHelper;
                    if (!SM_Helpers.TryGetValue(matIdx, out materialHelper))
                    {
                        if (!SM_HelperPool.TryDequeue(out materialHelper))
                        {
                            materialHelper = new SingleMaterialHelper();
                        }
                        materialHelper.Material = matIdx;
                        SM_Helpers.Add(matIdx, materialHelper);
                    }

                    VertexInBatchLookup batchLookup;
                    if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup))
                    {
                        if (!SM_BatchLookupPool.TryDequeue(out batchLookup))
                        {
                            batchLookup = new VertexInBatchLookup();
                        }
                        SM_BatchLookups.Add(matIdx, batchLookup);
                    }

                    AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0);
                    AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1);
                    AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2);

                    //  Add indices
                    int nextTriangleIndex = materialHelper.IndexCount;
                    materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0);
                    materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1);
                    materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2);
                    materialHelper.IndexCount += 3;

                    if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) ||
                        (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP))
                    {
                        //  If this batch is almost full (or is full), we end it and start with new one
                        EndSingleMaterial(materialHelper, outBatches);
                    }
                }
                else
                {
                    Vector3I materials          = GetMaterials(ref vertex0, ref vertex1, ref vertex2);
                    var      voxelMaterialCount = MyDefinitionManager.Static.VoxelMaterialCount;
                    int      id = materials.X + voxelMaterialCount * (materials.Y + materials.Z * voxelMaterialCount);

                    // Assign current material
                    MultiMaterialHelper helper = null;
                    if (!MM_Helpers.TryGetValue(id, out helper))
                    {
                        if (!MM_HelperPool.TryDequeue(out helper))
                        {
                            helper = new MultiMaterialHelper();
                        }
                        helper.Material0 = materials.X;
                        helper.Material1 = materials.Y;
                        helper.Material2 = materials.Z;
                        MM_Helpers.Add(id, helper);
                    }

                    helper.AddVertex(ref vertex0);
                    helper.AddVertex(ref vertex1);
                    helper.AddVertex(ref vertex2);

                    if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                }
            }

            { //renderCell.End();
                foreach (var helper in SM_Helpers.Values)
                {
                    Debug.Assert(helper != null);
                    if (helper.IndexCount > 0)
                    {
                        EndSingleMaterial(helper, outBatches);
                    }
                    helper.IndexCount  = 0;
                    helper.VertexCount = 0;
                    SM_HelperPool.Enqueue(helper);
                }
                SM_Helpers.Clear();

                foreach (var helper in MM_Helpers.Values)
                {
                    if (helper.Vertices.Count > 0)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                    helper.Vertices.Clear();
                    MM_HelperPool.Enqueue(helper);
                }
                MM_Helpers.Clear();

                foreach (var lookup in SM_BatchLookups.Values)
                {
                    SM_BatchLookupPool.Enqueue(lookup);
                }
                SM_BatchLookups.Clear();
            }

            m_morphMap.Clear();
        }