private void EnsureMorphTargetExists(MyPrecalcJobRender.Args args, MyIsoMesh highResMesh) { // Ensure as many (ideally all) vertices have some mapping prepared. // This is here to resolve any missing parent only once for each vertex (main loop can visit vertices for each triangle they appear in). //var geometryData = highResMesh; for (int i = 0; i < highResMesh.VerticesCount; ++i) { Vector3 highResPosition = highResMesh.Positions[i]; Vertex lowResVertex; Vector3I vertexCell = highResMesh.Cells[i] >> 1; if (!m_morphMap.TryGetValue(vertexCell, out lowResVertex)) { float scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << args.Cell.Lod); Vector3 cell = highResPosition / scale; cell *= 0.5f; scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1)); Vector3 lowResPosition = cell * scale; var cellMin = vertexCell; var cellMax = vertexCell + 1; // usually I need to find parent in this direction float nearestDist = float.PositiveInfinity; int nearestDistManhat = int.MaxValue; Vector3I?nearestCell = null; for (var it = new Vector3I.RangeIterator(ref cellMin, ref cellMax); it.IsValid(); it.MoveNext()) { Vertex morph; if (m_morphMap.TryGetValue(it.Current, out morph)) { var tmp = it.Current - cellMin; int distManhat = tmp.X + tmp.Y + tmp.Z; float dist = (morph.Target.Position - lowResPosition).LengthSquared(); if (distManhat < nearestDistManhat || (distManhat == nearestDistManhat && dist < nearestDist)) { nearestDist = dist; nearestDistManhat = distManhat; nearestCell = it.Current; } } } if (nearestCell.HasValue) { m_morphMap.Add(vertexCell, m_morphMap[nearestCell.Value]); } else { //Debug.Fail("I'm screwed"); } } } }
private void ProcessMorphTargetCollisions(MyPrecalcJobRender.Args args, float vertexCellSizeInParentLod) { // Process collisions. // Remove collided vertices from map and add them to the list of collisions. for (int i = 0; i < m_collisionList.Count; ++i) { var vertexA = m_collisionList[i]; Vertex vertexB; if (m_morphMap.TryGetValue(vertexA.Cell, out vertexB)) { m_morphMap.Remove(vertexA.Cell); m_collisionList.Add(vertexB); } } // Try find better position for each vertex involved in collision. // mk:TODO This would ideally be done wthout MyVoxelCoordSystems float vertexHalfExpand = 0.25f * vertexCellSizeInParentLod; for (int i = 0; i < m_collisionList.Count; ++i) { var vertex = m_collisionList[i]; var center = vertex.Target.Position; var min = center - vertexHalfExpand; var max = center + vertexHalfExpand; Vector3I minVertexCell, maxVertexCell; MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref min, out minVertexCell); MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref max, out maxVertexCell); if (minVertexCell == maxVertexCell) { m_morphMap[minVertexCell] = vertex; } else { for (var it = new Vector3I.RangeIterator(ref minVertexCell, ref maxVertexCell); it.IsValid(); it.MoveNext()) { if (!m_morphMap.ContainsKey(it.Current)) { m_morphMap[it.Current] = vertex; } } } } m_collisionList.Clear(); }
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(); }
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(); }
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(); }