public override void DoWork() { ProfilerShort.Begin("MyPrecalcJobPhysicsPrefetch.DoWork"); try { if (m_isCancelled) { return; } var geometryData = m_args.TargetPhysics.CreateMesh(m_args.Storage, m_args.GeometryCell); if (m_isCancelled) { return; } if (!MyIsoMesh.IsEmpty(geometryData)) { m_result = m_args.TargetPhysics.CreateShape(geometryData); } } finally { ProfilerShort.End(); } }
internal HkBvCompressedMeshShape CreateShape(MyIsoMesh mesh) { // mk:NOTE This method must be thread safe. Called from worker threads. if (mesh == null || mesh.TrianglesCount == 0 || mesh.VerticesCount == 0) { return((HkBvCompressedMeshShape)HkShape.Empty); } List <int> indexList = new List <int>(mesh.TrianglesCount * 3); List <Vector3> vertexList = new List <Vector3>(mesh.VerticesCount); for (int i = 0; i < mesh.TrianglesCount; i++) { indexList.Add(mesh.Triangles[i].VertexIndex0); indexList.Add(mesh.Triangles[i].VertexIndex2); indexList.Add(mesh.Triangles[i].VertexIndex1); } // mk:TODO Unify denormalizing of positions with what is in MyIsoMesh. var positionOffset = mesh.PositionOffset - m_voxelMap.StorageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var positions = mesh.Positions.GetInternalArray(); for (int i = 0; i < mesh.VerticesCount; i++) { vertexList.Add(positions[i] * mesh.PositionScale + positionOffset); } using (var cellGeometry = new HkGeometry(vertexList, indexList)) { var result = new HkBvCompressedMeshShape(cellGeometry, null, null, HkWeldingType.None, MyPerGameSettings.PhysicsConvexRadius); Debug.Assert(result.Base.ReferenceCount == 1); return(result); } }
private void RequestShapeBlocking(int x, int y, int z, out HkBvCompressedMeshShape shape, out HkReferencePolicy refPolicy) { ProfilerShort.Begin("MyVoxelPhysicsBody.RequestShapeBlocking"); const int lod = 0; var cellCoord = new MyCellCoord(lod, new Vector3I(x, y, z)); shape = (HkBvCompressedMeshShape)HkShape.Empty; // shape must take ownership, otherwise shapes created here will leak, since I can't remove reference refPolicy = HkReferencePolicy.TakeOwnership; MyPrecalcComponent.QueueJobCancel(m_workTracker, cellCoord.CoordInLod); if (m_voxelMap.MarkedForClose) { ProfilerShort.End(); return; } ProfilerShort.Begin("Generating geometry"); MyIsoMesh geometryData = CreateMesh(m_voxelMap.Storage, cellCoord.CoordInLod); ProfilerShort.End(); if (!MyIsoMesh.IsEmpty(geometryData)) { ProfilerShort.Begin("Shape from geometry"); shape = CreateShape(geometryData); m_needsShapeUpdate = true; ProfilerShort.End(); } ProfilerShort.End(); }
public override void DoWork() { ProfilerShort.Begin("MyPrecalcJobPhysicsBatch.DoWork"); try { IMyStorage storage = m_targetPhysics.m_voxelMap.Storage; foreach (var cell in CellBatch) { if (m_isCancelled) { break; } var geometryData = m_targetPhysics.CreateMesh(storage, cell); if (m_isCancelled) { break; } if (!MyIsoMesh.IsEmpty(geometryData)) { var meshShape = m_targetPhysics.CreateShape(geometryData); m_newShapes.Add(cell, meshShape); } else { m_newShapes.Add(cell, (HkBvCompressedMeshShape)HkShape.Empty); } } } finally { ProfilerShort.End(); } }
public bool TryGetMesh(MyCellCoord cell, out bool isEmpty, out MyIsoMesh nonEmptyMesh) { bool flag; using (this.m_lock.AcquireSharedUsing()) { if (this.IsEmpty(ref cell)) { isEmpty = true; nonEmptyMesh = null; flag = true; } else { ulong key = cell.PackId64(); if (this.m_coordinateToMesh.TryGetValue(key, out nonEmptyMesh)) { isEmpty = false; flag = true; } else { isEmpty = false; nonEmptyMesh = null; flag = false; } } } return(flag); }
private void ProcessVertex(MyIsoMesh mesh, int vertexIndex, ref BoundingBox localAabb, ref Vector3 positionScale, ref Vector3D positionOffset, out MyVoxelVertex vertex) { vertex.Position = mesh.Positions[vertexIndex]; vertex.Normal = mesh.Normals[vertexIndex]; vertex.Material = mesh.Materials[vertexIndex]; vertex.Ambient = 0f; Vertex morph; if (m_morphMap.TryGetValue(mesh.Cells[vertexIndex] >> 1, out morph)) { vertex.PositionMorph = morph.Target.Position; vertex.NormalMorph = morph.Target.Normal; vertex.MaterialMorph = morph.Target.Material; } else { vertex.PositionMorph = vertex.Position; vertex.NormalMorph = vertex.Normal; vertex.MaterialMorph = vertex.Material; } localAabb.Include(vertex.Position * positionScale + positionOffset); localAabb.Include(vertex.PositionMorph * positionScale + positionOffset); Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); }
private void RequestShapeBlockingInternal(int x, int y, int z, out HkBvCompressedMeshShape shape, out HkReferencePolicy refPolicy, bool lod1physics) { ProfilerShort.Begin("MyVoxelPhysicsBody.RequestShapeBlocking"); const int lod = 0; var cellCoord = new MyCellCoord(lod, new Vector3I(x, y, z)); shape = (HkBvCompressedMeshShape)HkShape.Empty; // shape must take ownership, otherwise shapes created here will leak, since I can't remove reference refPolicy = HkReferencePolicy.TakeOwnership; MyPrecalcComponent.QueueJobCancel(m_workTracker, cellCoord.CoordInLod); if (m_voxelMap.MarkedForClose) { ProfilerShort.End(); return; } //BoundingBoxD aabb; //MyVoxelCoordSystems.GeometryCellCoordToWorldAABB(m_voxelMap.PositionLeftBottomCorner, ref cellCoord.CoordInLod, out aabb); //MyRenderProxy.DebugDrawAABB(aabb, Color.Red, 1, 1, false); ProfilerShort.Begin("Generating geometry"); MyIsoMesh geometryData = CreateMesh(m_voxelMap.Storage, cellCoord.CoordInLod, lod1physics); ProfilerShort.End(); if (!MyIsoMesh.IsEmpty(geometryData)) { ProfilerShort.Begin("Shape from geometry"); shape = CreateShape(geometryData); m_needsShapeUpdate = true; ProfilerShort.End(); } ProfilerShort.End(); }
private void ProcessHighVertex(MyIsoMesh mesh, int vertexIndex, ref MyClipmapCellMeshMetadata meta, out MyVoxelVertex vertex) { vertex = new MyVoxelVertex(); vertex.Position = mesh.Positions[vertexIndex]; vertex.Normal = mesh.Normals[vertexIndex]; vertex.Material = mesh.Materials[vertexIndex]; vertex.Ambient = mesh.Ambient[vertexIndex]; vertex.Cell = mesh.Cells[vertexIndex]; vertex.PositionMorph = vertex.Position; vertex.NormalMorph = vertex.Normal; vertex.MaterialMorph = vertex.Material; vertex.AmbientMorph = vertex.Ambient; //Vertex morph; //Vector3I lowerLodCell = (mesh.Cells[vertexIndex]) >> 1; //if (m_morphMap.TryGetValue(lowerLodCell, out morph)) //{ // vertex.PositionMorph = morph.Target.Position; // vertex.NormalMorph = morph.Target.Normal; // vertex.MaterialMorph = morph.Target.Material; // vertex.AmbientMorph = morph.Target.Ambient; //} //else //{ //} //if (m_lowVertices.Count > 0) //{ // float closestDistance = float.MaxValue; // int closestLowVertex = -1; // for (int i = 0; i < m_lowVertices.Count; i++) // { // float dist = Vector3.DistanceSquared(vertex.Position, m_lowVertices[i].Target.Position); // if (dist < closestDistance) // { // closestDistance = dist; // closestLowVertex = i; // } // } // vertex.PositionMorph = m_lowVertices[closestLowVertex].Target.Position; // vertex.NormalMorph = m_lowVertices[closestLowVertex].Target.Normal; // vertex.MaterialMorph = m_lowVertices[closestLowVertex].Target.Material; // vertex.AmbientMorph = m_lowVertices[closestLowVertex].Target.Ambient; // m_lowToHighMapping[closestLowVertex].Add(vertexIndex); // m_highToLowMapping.Add(closestLowVertex); //} m_highVertices.Add(vertex); }
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"); } } } }
internal unsafe HkShape CreateShape(MyIsoMesh mesh, bool simple = false) { // mk:NOTE This method must be thread safe. Called from worker threads. if (mesh == null || mesh.TrianglesCount == 0 || mesh.VerticesCount == 0) { return(HkShape.Empty); } if (s_indexList.Capacity < mesh.TrianglesCount * 3) { s_indexList.Capacity = mesh.TrianglesCount * 3; } if (s_vertexList.Capacity < mesh.VerticesCount) { s_vertexList.Capacity = mesh.VerticesCount; } for (int i = 0; i < mesh.TrianglesCount; i++) { s_indexList.Add(mesh.Triangles[i].VertexIndex0); s_indexList.Add(mesh.Triangles[i].VertexIndex2); s_indexList.Add(mesh.Triangles[i].VertexIndex1); } // mk:TODO Unify denormalizing of positions with what is in MyIsoMesh. var positionOffset = mesh.PositionOffset - m_voxelMap.StorageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var positions = mesh.Positions.GetInternalArray(); for (int i = 0; i < mesh.VerticesCount; i++) { s_vertexList.Add(positions[i] * mesh.PositionScale + positionOffset); } { HkShape result; if (simple) { result = new HkSimpleMeshShape(s_vertexList, s_indexList); } else { s_cellGeometry.SetGeometry(s_vertexList, s_indexList); result = new HkBvCompressedMeshShape(s_cellGeometry, null, null, HkWeldingType.None, MyPerGameSettings.PhysicsConvexRadius); } Debug.Assert(result.ReferenceCount == 1); s_vertexList.Clear(); s_indexList.Clear(); return(result); } }
public override void DoWork() { ProfilerShort.Begin("MyPrecalcJobRender.DoWork"); try { if (m_isCancelled) { return; } m_metadata.Cell = m_args.Cell; m_metadata.LocalAabb = BoundingBox.CreateInvalid(); var cellSize = MyVoxelCoordSystems.RenderCellSizeInLodVoxels(m_args.Cell.Lod); var min = m_args.Cell.CoordInLod * cellSize; var max = min + cellSize - 1 + 1 // overlap to neighbor so geometry is stitched together within same LOD + 1 // extra overlap so there are more vertices for mapping to parent LOD + 1 // for eg. 9 vertices in row we need 9 + 1 samples (voxels) ; MyIsoMesh highResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod, min, max, true, true); if (m_isCancelled || highResMesh == null) { return; } MyIsoMesh lowResMesh = null; // Less detailed mesh for vertex morph targets min >>= 1; max >>= 1; min -= 1; max += 1; // lowResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod + 1, min, max, true, true); if (m_isCancelled) { return; } RenderCellBuilder.BuildCell(m_args, highResMesh, lowResMesh, m_batches, out m_metadata); } finally { ProfilerShort.End(); } }
private void ProcessHighVertex(MyIsoMesh mesh, int vertexIndex, out MyVoxelVertex vertex) { vertex = new MyVoxelVertex(); vertex.Position = mesh.Positions[vertexIndex]; vertex.Normal = mesh.Normals[vertexIndex]; vertex.Material = mesh.Materials[vertexIndex]; vertex.Ambient = mesh.Ambient[vertexIndex]; vertex.Cell = mesh.Cells[vertexIndex]; vertex.PositionMorph = vertex.Position; vertex.NormalMorph = vertex.Normal; vertex.MaterialMorph = vertex.Material; vertex.AmbientMorph = vertex.Ambient; m_highVertices.Add(vertex); }
private void RequestShapeBlockingInternal(int x, int y, int z, out HkShape shape, out HkReferencePolicy refPolicy, bool lod1physics) { ProfilerShort.Begin("MyVoxelPhysicsBody.RequestShapeBlocking"); if (!m_bodiesInitialized) { CreateRigidBodies(); } int lod = lod1physics ? 1 : 0; var cellCoord = new MyCellCoord(lod, new Vector3I(x, y, z)); shape = HkShape.Empty; // shape must take ownership, otherwise shapes created here will leak, since I can't remove reference refPolicy = HkReferencePolicy.TakeOwnership; //MyPrecalcComponent.QueueJobCancel(m_workTracker, cellCoord); if (m_voxelMap.MarkedForClose) { ProfilerShort.End(); return; } if (MyDebugDrawSettings.DEBUG_DRAW_REQUEST_SHAPE_BLOCKING) { BoundingBoxD aabb; MyVoxelCoordSystems.GeometryCellCoordToWorldAABB(m_voxelMap.PositionLeftBottomCorner, ref cellCoord, out aabb); MyRenderProxy.DebugDrawAABB(aabb, lod1physics ? Color.Yellow : Color.Red, 1, 1, true); } ProfilerShort.Begin("Generating geometry"); MyIsoMesh geometryData = CreateMesh(m_voxelMap.Storage, cellCoord); ProfilerShort.End(); if (!MyIsoMesh.IsEmpty(geometryData)) { ProfilerShort.Begin("Shape from geometry"); shape = CreateShape(geometryData, true); shape.AddReference(); var args = new MyPrecalcJobPhysicsPrefetch.Args() { GeometryCell = cellCoord, TargetPhysics = this, Tracker = m_workTracker, SimpleShape = shape }; MyPrecalcJobPhysicsPrefetch.Start(args); m_needsShapeUpdate = true; ProfilerShort.End(); } ProfilerShort.End(); }
public void SetMesh(MyCellCoord cell, MyIsoMesh mesh) { if (cell.Lod == 0) { using (this.m_lock.AcquireExclusiveUsing()) { if (mesh == null) { this.SetEmpty(ref cell, true); } else { ulong num = cell.PackId64(); this.m_coordinateToMesh[num] = mesh; } } } }
public bool TryGetMesh(MyCellCoord cell, out bool isEmpty, out MyIsoMesh nonEmptyMesh) { using (m_lock.AcquireSharedUsing()) { if (IsEmpty(ref cell)) { isEmpty = true; nonEmptyMesh = null; return(true); } UInt64 key = cell.PackId64(); if (m_coordinateToMesh.TryGetValue(key, out nonEmptyMesh)) { isEmpty = false; return(true); } isEmpty = default(bool); nonEmptyMesh = default(MyIsoMesh); return(false); } }
public void SetMesh(MyCellCoord cell, MyIsoMesh mesh) { // Don't store anything but the most detailed lod (used in physics and raycasts). // This cache is mostly supposed to help physics and raycasts, not render. if (cell.Lod != 0) { return; } MyPrecalcComponent.AssertUpdateThread(); using (m_lock.AcquireExclusiveUsing()) { if (mesh != null) { var key = cell.PackId64(); m_coordinateToMesh[key] = mesh; } else { SetEmpty(ref cell, true); } } }
public override void DoWork() { ProfilerShort.Begin("MyPrecalcJobPhysicsPrefetch.DoWork"); //try { if (m_isCancelled) { ProfilerShort.End(); return; } if (m_args.Storage != null) { var geometryData = m_args.TargetPhysics.CreateMesh(m_args.Storage, m_args.GeometryCell); if (m_isCancelled) { ProfilerShort.End(); return; } if (!MyIsoMesh.IsEmpty(geometryData)) { m_result = m_args.TargetPhysics.CreateShape(geometryData); } } else { m_result = m_args.TargetPhysics.BakeCompressedMeshShape((HkSimpleMeshShape)m_args.SimpleShape); m_args.SimpleShape.RemoveReference(); } } //finally { ProfilerShort.End(); } }
private void ProcessLowMesh(MyIsoMesh highResMesh, MyIsoMesh lowResMesh) { ProfilerShort.Begin("ProcessLowMesh"); 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], Ambient = lowResMesh.Ambient[i], }, Cell = lowResMesh.Cells[i], }; m_lowVertices.Add(vertex); m_morphMap[vertex.Cell] = vertex; } } ProfilerShort.End(); }
public static bool IsEmpty(MyIsoMesh self) { return self == null || self.Triangles.Count == 0; }
internal unsafe HkShape CreateShape(MyIsoMesh mesh, bool simple = false) { // mk:NOTE This method must be thread safe. Called from worker threads. if (mesh == null || mesh.TrianglesCount == 0 || mesh.VerticesCount == 0) return HkShape.Empty; if (s_indexList.Capacity < mesh.TrianglesCount * 3) s_indexList.Capacity = mesh.TrianglesCount * 3; if (s_vertexList.Capacity < mesh.VerticesCount) s_vertexList.Capacity = mesh.VerticesCount; for (int i = 0; i < mesh.TrianglesCount; i++) { s_indexList.Add(mesh.Triangles[i].VertexIndex0); s_indexList.Add(mesh.Triangles[i].VertexIndex2); s_indexList.Add(mesh.Triangles[i].VertexIndex1); } // mk:TODO Unify denormalizing of positions with what is in MyIsoMesh. var positionOffset = mesh.PositionOffset - m_voxelMap.StorageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var positions = mesh.Positions.GetInternalArray(); for (int i = 0; i < mesh.VerticesCount; i++) { s_vertexList.Add(positions[i] * mesh.PositionScale + positionOffset); } { HkShape result; if (simple) { result = new HkSimpleMeshShape(s_vertexList, s_indexList); } else { s_cellGeometry.SetGeometry(s_vertexList, s_indexList); result = new HkBvCompressedMeshShape(s_cellGeometry, null, null, HkWeldingType.None, MyPerGameSettings.PhysicsConvexRadius); } Debug.Assert(result.ReferenceCount == 1); s_vertexList.Clear(); s_indexList.Clear(); return result; } }
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(); }
public override void DoWork() { ProfilerShort.Begin("MyPrecalcJobRender.DoWork"); try { if (m_isCancelled) { return; } m_metadata.Cell = m_args.Cell; m_metadata.LocalAabb = BoundingBox.CreateInvalid(); var cellSize = MyVoxelCoordSystems.RenderCellSizeInLodVoxels(m_args.Cell.Lod); var min = m_args.Cell.CoordInLod * cellSize - 1; var max = min + cellSize - 1 + 1 // overlap to neighbor so geometry is stitched together within same LOD + 1 // extra overlap so there are more vertices for mapping to parent LOD + 1; // for eg. 9 vertices in row we need 9 + 1 samples (voxels) // + 1 // why not // + 1 // martin kroslak approved var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_args.ClipmapId, m_args.Cell.PackId64()); MyIsoMesh highResMesh = IsoMeshCache.Read(clipmapCellId); if (highResMesh == null) { highResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod, min, max, true, MyFakes.ENABLE_VOXEL_COMPUTED_OCCLUSION); if (UseIsoCache && highResMesh != null) { IsoMeshCache.Write(clipmapCellId, highResMesh); } } if (m_isCancelled || highResMesh == null) { return; } MyIsoMesh lowResMesh = null; if (m_args.Cell.Lod < 15 && MyFakes.ENABLE_VOXEL_LOD_MORPHING) { var nextLodCell = m_args.Cell; nextLodCell.Lod++; clipmapCellId = MyCellCoord.GetClipmapCellHash(m_args.ClipmapId, nextLodCell.PackId64()); lowResMesh = IsoMeshCache.Read(clipmapCellId); if (lowResMesh == null) { // Less detailed mesh for vertex morph targets min >>= 1; max >>= 1; min -= 1; max += 2; lowResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod + 1, min, max, true, MyFakes.ENABLE_VOXEL_COMPUTED_OCCLUSION); if (UseIsoCache && lowResMesh != null) { IsoMeshCache.Write(clipmapCellId, lowResMesh); } } } if (m_isCancelled) { return; } RenderCellBuilder.BuildCell(m_args, highResMesh, lowResMesh, m_batches, out m_metadata); } finally { ProfilerShort.End(); } }
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(); }
public bool TryGetMesh(MyCellCoord cell, out bool isEmpty, out MyIsoMesh nonEmptyMesh) { using (m_lock.AcquireSharedUsing()) { if (IsEmpty(ref cell)) { isEmpty = true; nonEmptyMesh = null; return true; } UInt64 key = cell.PackId64(); if (m_coordinateToMesh.TryGetValue(key, out nonEmptyMesh)) { isEmpty = false; return true; } isEmpty = default(bool); nonEmptyMesh = default(MyIsoMesh); return false; } }
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(); }
private void ProcessVertex(MyIsoMesh mesh, int vertexIndex, ref BoundingBox localAabb, ref Vector3 positionScale, ref Vector3D positionOffset, out MyVoxelVertex vertex) { vertex.Position = mesh.Positions[vertexIndex]; vertex.Normal = mesh.Normals[vertexIndex]; vertex.Material = mesh.Materials[vertexIndex]; vertex.Ambient = 0f; Vertex morph; if (m_morphMap.TryGetValue(mesh.Cells[vertexIndex] >> 1, out morph)) { vertex.PositionMorph = morph.Target.Position; vertex.NormalMorph = morph.Target.Normal; vertex.MaterialMorph = morph.Target.Material; } else { vertex.PositionMorph = vertex.Position; vertex.NormalMorph = vertex.Normal; vertex.MaterialMorph = vertex.Material; } localAabb.Include(vertex.Position * positionScale + positionOffset); localAabb.Include(vertex.PositionMorph * positionScale + positionOffset); Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); }
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(); }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient) { // change range so normal can be computed at edges (expand by 1 in all directions) voxelStart -= 1; voxelEnd += 1; m_cache.Resize(voxelStart, voxelEnd); storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd); if (!m_cache.ContainsIsoSurface()) { return(null); } var center = (storage.Size / 2) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); var vertexCellOffset = voxelStart - AffectedRangeOffset; double numCellsHalf = 0.5 * (m_cache.Size3D.X - 3); var posOffset = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize; if (generateMaterials) { m_cache.ClearMaterials(0); } IsoMesher mesher = new IsoMesher(); ProfilerShort.Begin("Dual Contouring"); unsafe { fixed(byte *voxels = m_cache.Data) { var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); mesher.Calculate(size3d.X, (VoxelData *)voxels, m_buffer, useAmbient, posOffset - center); } } ProfilerShort.End(); if (generateMaterials) { using (MyVoxelMaterialRequestHelper.StartContouring()) { storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd); bool hasOcclusionHint = false; FixCacheMaterial(voxelStart, voxelEnd); unsafe { fixed(byte *voxels = m_cache.Data) { var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); mesher.CalculateMaterials(size3d.X, (VoxelData *)voxels, hasOcclusionHint); } } } } else { m_cache.ClearMaterials(0); } mesher.Finish(m_buffer); if (m_buffer.VerticesCount == 0 && m_buffer.Triangles.Count == 0) { return(null); } ProfilerShort.Begin("Geometry post-processing"); { var positions = m_buffer.Positions.GetInternalArray(); var vertexCells = m_buffer.Cells.GetInternalArray(); for (int i = 0; i < m_buffer.VerticesCount; i++) { Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); vertexCells[i] += vertexCellOffset; Debug.Assert(vertexCells[i].IsInsideInclusive(voxelStart + 1, voxelEnd - 1)); } m_buffer.PositionOffset = posOffset; m_buffer.PositionScale = new Vector3((float)(numCellsHalf * voxelSize)); m_buffer.CellStart = voxelStart + 1; m_buffer.CellEnd = voxelEnd - 1; } ProfilerShort.End(); // Replace filled mesh with new one. // This way prevents allocation of meshes which then end up empty. var buffer = m_buffer; m_buffer = new MyIsoMesh(); return(buffer); }
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(); }
private void ProcessHighVertex(MyIsoMesh mesh, int vertexIndex, out MyVoxelVertex vertex) { vertex = new MyVoxelVertex(); vertex.Position = mesh.Positions[vertexIndex]; vertex.Normal = mesh.Normals[vertexIndex]; vertex.Material = mesh.Materials[vertexIndex]; vertex.Ambient = mesh.Ambient[vertexIndex]; vertex.Cell = mesh.Cells[vertexIndex]; vertex.PositionMorph = vertex.Position; vertex.NormalMorph = vertex.Normal; vertex.MaterialMorph = vertex.Material; vertex.AmbientMorph = vertex.Ambient; m_highVertices.Add(vertex); }
private void ProcessLowMesh(MyIsoMesh highResMesh, MyIsoMesh lowResMesh) { ProfilerShort.Begin("ProcessLowMesh"); 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], Ambient = lowResMesh.Ambient[i], }, Cell = lowResMesh.Cells[i], }; m_lowVertices.Add(vertex); m_morphMap[vertex.Cell] = vertex; } } ProfilerShort.End(); }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck = false) { // change range so normal can be computed at edges (expand by 1 in all directions) voxelStart -= 1; voxelEnd += 1; if (storage == null) { return(null); } using (storage.Pin()) { if (storage.Closed) { return(null); } MyVoxelRequestFlags request = MyVoxelRequestFlags.ContentChecked; // | (doNotCheck ? MyVoxelRequestFlags.DoNotCheck : 0); //if (lod == 0 && generateMaterials) request |= MyVoxelRequestFlags.AdviseCache; bool readAmbient = false; if (generateMaterials && storage.DataProvider != null && storage.DataProvider.ProvidesAmbient) { readAmbient = true; } m_cache.Resize(voxelStart, voxelEnd); if (readAmbient) { m_cache.StoreOcclusion = true; } storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd, ref request); if (request.HasFlag(MyVoxelRequestFlags.EmptyContent) || request.HasFlag(MyVoxelRequestFlags.FullContent) || (!request.HasFlag(MyVoxelRequestFlags.ContentChecked) && !m_cache.ContainsIsoSurface())) { //if(generateMaterials && lod == 0) Debugger.Break(); //storage.DebugDrawChunk(voxelStart, voxelEnd); return(null); } var center = (storage.Size / 2) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); var vertexCellOffset = voxelStart - AffectedRangeOffset; double numCellsHalf = 0.5 * (m_cache.Size3D.X - 3); var posOffset = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize; if (generateMaterials) { // 255 is the new black m_cache.ClearMaterials(255); } if (readAmbient) { m_cache.Clear(MyStorageDataTypeEnum.Occlusion, 0); } IsoMesher mesher = new IsoMesher(); ProfilerShort.Begin("Dual Contouring"); unsafe { fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content]) fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material]) { var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); mesher.Calculate(size3d.X, content, material, m_buffer, useAmbient, posOffset - center); } } ProfilerShort.End(); if (generateMaterials) { request = 0; request |= MyVoxelRequestFlags.SurfaceMaterial; request |= MyVoxelRequestFlags.ConsiderContent; var req = readAmbient ? MyStorageDataTypeFlags.Material | MyStorageDataTypeFlags.Occlusion : MyStorageDataTypeFlags.Material; storage.ReadRange(m_cache, req, lod, ref voxelStart, ref voxelEnd, ref request); FixCacheMaterial(voxelStart, voxelEnd); unsafe { fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content]) fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material]) { int materialOverride = request.HasFlag(MyVoxelRequestFlags.OneMaterial) ? m_cache.Material(0) : -1; var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); if (readAmbient) fixed(byte *ambient = m_cache[MyStorageDataTypeEnum.Occlusion]) mesher.CalculateMaterials(size3d.X, content, material, ambient, materialOverride); else { mesher.CalculateMaterials(size3d.X, content, material, null, materialOverride); } } } } else { m_cache.ClearMaterials(0); } mesher.Finish(m_buffer); if (m_buffer.VerticesCount == 0 || m_buffer.Triangles.Count == 0) { return(null); } ProfilerShort.Begin("Geometry post-processing"); { var positions = m_buffer.Positions.GetInternalArray(); var vertexCells = m_buffer.Cells.GetInternalArray(); var materials = m_buffer.Materials.GetInternalArray(); for (int i = 0; i < m_buffer.VerticesCount; i++) { Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); vertexCells[i] += vertexCellOffset; Debug.Assert(vertexCells[i].IsInsideInclusive(voxelStart + 1, voxelEnd - 1)); Debug.Assert(materials[i] != MyVoxelConstants.NULL_MATERIAL); } m_buffer.PositionOffset = posOffset; m_buffer.PositionScale = new Vector3((float)(numCellsHalf * voxelSize)); m_buffer.CellStart = voxelStart + 1; m_buffer.CellEnd = voxelEnd - 1; } ProfilerShort.End(); // Replace filled mesh with new one. // This way prevents allocation of meshes which then end up empty. var buffer = m_buffer; m_buffer = new MyIsoMesh(); return(buffer); } }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck, bool adviceCache = false) { m_resultVerticesCounter = 0; m_resultTrianglesCounter = 0; m_edgeVertexCalcCounter++; m_temporaryVoxelsCounter++; CalcPolygCubeSize(lod, storage.Size); m_voxelStart = voxelStart; //voxelStart = voxelStart; //voxelEnd = voxelEnd; var ssize = storage.Size; m_cache.Resize(voxelStart, voxelEnd); // Load content first, check it if it contains isosurface, early exit if it doesn't. storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd); if (!m_cache.ContainsIsoSurface()) return null; storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd); ProfilerShort.Begin("Marching cubes"); { // Size of voxel or cell (in meters) and size of voxel map / voxel cells ComputeSizeAndOrigin(lod, storage.Size); var start = Vector3I.Zero; var end = voxelEnd - voxelStart - 3; Vector3I coord0 = start; for (var it = new Vector3I_RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out coord0)) { int cubeIndex = 0; if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 1; if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 2; if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 4; if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 8; if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 16; if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 32; if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 64; if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 128; // Cube is entirely in/out of the surface if (MyMarchingCubesConstants.EdgeTable[cubeIndex] == 0) { continue; } // We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc. Vector3I tempVoxelCoord0 = ComputeTemporaryVoxelData(m_cache, ref coord0, cubeIndex, lod); // Create the triangles CreateTriangles(ref coord0, cubeIndex, ref tempVoxelCoord0); } } ProfilerShort.End(); double numCellsHalf = 0.5f * (m_cache.Size3D.X); var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); var vertexCellOffset = voxelStart - AffectedRangeOffset; IMyIsoMesherOutputBuffer isomesh = new MyIsoMesh(); for (int i = 0; i < m_resultVerticesCounter; i++) { var pos = (m_resultVertices[i].Position - (Vector3)storage.Size / 2) / storage.Size; m_resultVertices[i].Position = pos; m_resultVertices[i].PositionMorph = pos; m_resultVertices[i].NormalMorph = m_resultVertices[i].Normal; m_resultVertices[i].MaterialMorph = m_resultVertices[i].Material; m_resultVertices[i].AmbientMorph = m_resultVertices[i].Ambient; } for (int i = 0; i < m_resultVerticesCounter; i++) { isomesh.WriteVertex(ref m_resultVertices[i].Cell, ref m_resultVertices[i].Position, ref m_resultVertices[i].Normal, (byte)m_resultVertices[i].Material, m_resultVertices[i].Ambient); } for (int i = 0; i < m_resultTrianglesCounter; i++) { isomesh.WriteTriangle(m_resultTriangles[i].VertexIndex0, m_resultTriangles[i].VertexIndex1, m_resultTriangles[i].VertexIndex2); } var mIsoMesh = (MyIsoMesh)isomesh; mIsoMesh.PositionOffset = storage.Size / 2; mIsoMesh.PositionScale = storage.Size; mIsoMesh.CellStart = voxelStart; mIsoMesh.CellEnd = voxelEnd; var vertexCells = mIsoMesh.Cells.GetInternalArray(); for (int i = 0; i < mIsoMesh.VerticesCount; i++) { vertexCells[i] += vertexCellOffset; } return (MyIsoMesh)isomesh; }
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"); } } } }
public void SetMesh(MyCellCoord cell, MyIsoMesh mesh) { // Don't store anything but the most detailed lod (used in physics and raycasts). // This cache is mostly supposed to help physics and raycasts, not render. if (cell.Lod != 0) return; MyPrecalcComponent.AssertUpdateThread(); using (m_lock.AcquireExclusiveUsing()) { if (mesh != null) { var key = cell.PackId64(); m_coordinateToMesh[key] = mesh; } else { SetEmpty(ref cell, true); } } }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck = false) { // change range so normal can be computed at edges (expand by 1 in all directions) voxelStart -= 1; voxelEnd += 1; if (storage == null) return null; using (storage.Pin()) { if (storage.Closed) return null; MyVoxelRequestFlags request = MyVoxelRequestFlags.ContentChecked; // | (doNotCheck ? MyVoxelRequestFlags.DoNotCheck : 0); //if (lod == 0 && generateMaterials) request |= MyVoxelRequestFlags.AdviseCache; bool readAmbient = false; if (generateMaterials && storage.DataProvider != null && storage.DataProvider.ProvidesAmbient) readAmbient = true; m_cache.Resize(voxelStart, voxelEnd); if (readAmbient) m_cache.StoreOcclusion = true; storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd, ref request); if (request.HasFlags(MyVoxelRequestFlags.EmptyContent) || request.HasFlags(MyVoxelRequestFlags.FullContent) || (!request.HasFlags(MyVoxelRequestFlags.ContentChecked) && !m_cache.ContainsIsoSurface())) { //if(generateMaterials && lod == 0) Debugger.Break(); //storage.DebugDrawChunk(voxelStart, voxelEnd); return null; } var center = (storage.Size / 2) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); var vertexCellOffset = voxelStart - AffectedRangeOffset; double numCellsHalf = 0.5 * (m_cache.Size3D.X - 3); var posOffset = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize; if (generateMaterials) { // 255 is the new black m_cache.ClearMaterials(255); } if (readAmbient) m_cache.Clear(MyStorageDataTypeEnum.Occlusion, 0); IsoMesher mesher = new IsoMesher(); ProfilerShort.Begin("Dual Contouring"); unsafe { fixed (byte* content = m_cache[MyStorageDataTypeEnum.Content]) fixed (byte* material = m_cache[MyStorageDataTypeEnum.Material]) { var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); mesher.Calculate(size3d.X, content, material, m_buffer, useAmbient, posOffset - center); } } if (generateMaterials) { request = 0; request |= MyVoxelRequestFlags.SurfaceMaterial; request |= MyVoxelRequestFlags.ConsiderContent; var req = readAmbient ? MyStorageDataTypeFlags.Material | MyStorageDataTypeFlags.Occlusion : MyStorageDataTypeFlags.Material; storage.ReadRange(m_cache, req, lod, ref voxelStart, ref voxelEnd, ref request); FixCacheMaterial(voxelStart, voxelEnd); unsafe { fixed (byte* content = m_cache[MyStorageDataTypeEnum.Content]) fixed (byte* material = m_cache[MyStorageDataTypeEnum.Material]) { int materialOverride = request.HasFlags(MyVoxelRequestFlags.OneMaterial) ? m_cache.Material(0) : -1; var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); if (readAmbient) fixed (byte* ambient = m_cache[MyStorageDataTypeEnum.Occlusion]) mesher.CalculateMaterials(size3d.X, content, material, ambient, materialOverride); else mesher.CalculateMaterials(size3d.X, content, material, null, materialOverride); } } } else m_cache.ClearMaterials(0); mesher.Finish(m_buffer); ProfilerShort.End(); if (m_buffer.VerticesCount == 0 || m_buffer.Triangles.Count == 0) { return null; } ProfilerShort.Begin("Geometry post-processing"); { var positions = m_buffer.Positions.GetInternalArray(); var vertexCells = m_buffer.Cells.GetInternalArray(); var materials = m_buffer.Materials.GetInternalArray(); var ambients = m_buffer.Ambient.GetInternalArray(); for (int i = 0; i < m_buffer.VerticesCount; i++) { Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); vertexCells[i] += vertexCellOffset; Debug.Assert(vertexCells[i].IsInsideInclusive(voxelStart + 1, voxelEnd - 1)); Debug.Assert(materials[i] != MyVoxelConstants.NULL_MATERIAL); Debug.Assert(ambients[i] >= 0 && ambients[i] <= 1); } m_buffer.PositionOffset = posOffset; m_buffer.PositionScale = new Vector3((float)(numCellsHalf * voxelSize)); m_buffer.CellStart = voxelStart + 1; m_buffer.CellEnd = voxelEnd - 1; } ProfilerShort.End(); // Replace filled mesh with new one. // This way prevents allocation of meshes which then end up empty. var buffer = m_buffer; m_buffer = new MyIsoMesh(); return buffer; } }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials) { // change range so normal can be computed at edges (expand by 1 in all directions) voxelStart -= 1; voxelEnd += 1; m_cache.Resize(voxelStart, voxelEnd); storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd); if (!m_cache.ContainsIsoSurface()) { return(null); } if (generateMaterials) { storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd); } else { m_cache.ClearMaterials(0); } var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); ProfilerShort.Begin("Dual Contouring"); unsafe { fixed(byte *voxels = m_cache.Data) { var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); IsoMesher.Calculate(size3d.X, (VoxelData *)voxels, m_buffer); } } ProfilerShort.End(); if (m_buffer.VerticesCount == 0 && m_buffer.Triangles.Count == 0) { return(null); } ProfilerShort.Begin("Geometry post-processing"); { var vertexCellOffset = voxelStart - AffectedRangeOffset; var positions = m_buffer.Positions.GetInternalArray(); var vertexCells = m_buffer.Cells.GetInternalArray(); for (int i = 0; i < m_buffer.VerticesCount; i++) { var min = -Vector3.One; var max = Vector3.One; // Debug.Assert(positions[i].IsInsideInclusive(ref min, ref max)); vertexCells[i] += vertexCellOffset; } float numCellsHalf = 0.5f * (m_cache.Size3D.X - 3); m_buffer.PositionOffset = (vertexCellOffset + numCellsHalf) * voxelSize; m_buffer.PositionScale = new Vector3(numCellsHalf * voxelSize); } ProfilerShort.End(); // Replace filled mesh with new one. // This way prevents allocation of meshes which then end up empty. var buffer = m_buffer; m_buffer = new MyIsoMesh(); return(buffer); }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials) { // change range so normal can be computed at edges (expand by 1 in all directions) voxelStart -= 1; voxelEnd += 1; m_cache.Resize(voxelStart, voxelEnd); storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd); if (!m_cache.ContainsIsoSurface()) { return null; } if (generateMaterials) { storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd); } else { m_cache.ClearMaterials(0); } var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); ProfilerShort.Begin("Dual Contouring"); unsafe { fixed (byte* voxels = m_cache.Data) { var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); IsoMesher.Calculate(size3d.X, (VoxelData*)voxels, m_buffer); } } ProfilerShort.End(); if (m_buffer.VerticesCount == 0 && m_buffer.Triangles.Count == 0) { return null; } ProfilerShort.Begin("Geometry post-processing"); { var vertexCellOffset = voxelStart - AffectedRangeOffset; var positions = m_buffer.Positions.GetInternalArray(); var vertexCells = m_buffer.Cells.GetInternalArray(); for (int i = 0; i < m_buffer.VerticesCount; i++) { Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); vertexCells[i] += vertexCellOffset; } double numCellsHalf = 0.5 * (m_cache.Size3D.X - 3); m_buffer.PositionOffset = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize; m_buffer.PositionScale = new Vector3((float)(numCellsHalf * voxelSize)); } ProfilerShort.End(); // Replace filled mesh with new one. // This way prevents allocation of meshes which then end up empty. var buffer = m_buffer; m_buffer = new MyIsoMesh(); return buffer; }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck) { m_resultVerticesCounter = 0; m_resultTrianglesCounter = 0; m_edgeVertexCalcCounter++; m_temporaryVoxelsCounter++; CalcPolygCubeSize(lod, storage.Size); m_voxelStart = voxelStart; //voxelStart = voxelStart; //voxelEnd = voxelEnd; var ssize = storage.Size; m_cache.Resize(voxelStart, voxelEnd); // Load content first, check it if it contains isosurface, early exit if it doesn't. storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd); if (!m_cache.ContainsIsoSurface()) { return(null); } storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd); ProfilerShort.Begin("Marching cubes"); { // Size of voxel or cell (in meters) and size of voxel map / voxel cells ComputeSizeAndOrigin(lod, storage.Size); var start = Vector3I.Zero; var end = voxelEnd - voxelStart - 3; Vector3I coord0 = start; for (var it = new Vector3I.RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out coord0)) { int cubeIndex = 0; if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 1; } if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 2; } if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 4; } if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 8; } if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 16; } if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 32; } if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 64; } if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 128; } // Cube is entirely in/out of the surface if (MyMarchingCubesConstants.EdgeTable[cubeIndex] == 0) { continue; } // We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc. Vector3I tempVoxelCoord0 = ComputeTemporaryVoxelData(m_cache, ref coord0, cubeIndex, lod); // Create the triangles CreateTriangles(ref coord0, cubeIndex, ref tempVoxelCoord0); } } ProfilerShort.End(); double numCellsHalf = 0.5f * (m_cache.Size3D.X); var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); var vertexCellOffset = voxelStart - AffectedRangeOffset; IMyIsoMesherOutputBuffer isomesh = new MyIsoMesh(); for (int i = 0; i < m_resultVerticesCounter; i++) { var pos = (m_resultVertices[i].Position - (Vector3)storage.Size / 2) / storage.Size; m_resultVertices[i].Position = pos; m_resultVertices[i].PositionMorph = pos; m_resultVertices[i].NormalMorph = m_resultVertices[i].Normal; m_resultVertices[i].MaterialMorph = m_resultVertices[i].Material; m_resultVertices[i].AmbientMorph = m_resultVertices[i].Ambient; } for (int i = 0; i < m_resultVerticesCounter; i++) { isomesh.WriteVertex(ref m_resultVertices[i].Cell, ref m_resultVertices[i].Position, ref m_resultVertices[i].Normal, (byte)m_resultVertices[i].Material, m_resultVertices[i].Ambient); } for (int i = 0; i < m_resultTrianglesCounter; i++) { isomesh.WriteTriangle(m_resultTriangles[i].VertexIndex0, m_resultTriangles[i].VertexIndex1, m_resultTriangles[i].VertexIndex2); } var mIsoMesh = (MyIsoMesh)isomesh; mIsoMesh.PositionOffset = storage.Size / 2; mIsoMesh.PositionScale = storage.Size; mIsoMesh.CellStart = voxelStart; mIsoMesh.CellEnd = voxelEnd; var vertexCells = mIsoMesh.Cells.GetInternalArray(); for (int i = 0; i < mIsoMesh.VerticesCount; i++) { vertexCells[i] += vertexCellOffset; } return((MyIsoMesh)isomesh); }
private void ProcessHighVertex(MyIsoMesh mesh, int vertexIndex, ref MyClipmapCellMeshMetadata meta, out MyVoxelVertex vertex) { vertex = new MyVoxelVertex(); vertex.Position = mesh.Positions[vertexIndex]; vertex.Normal = mesh.Normals[vertexIndex]; vertex.Material = mesh.Materials[vertexIndex]; vertex.Ambient = mesh.Ambient[vertexIndex]; vertex.Cell = mesh.Cells[vertexIndex]; vertex.PositionMorph = vertex.Position; vertex.NormalMorph = vertex.Normal; vertex.MaterialMorph = vertex.Material; vertex.AmbientMorph = vertex.Ambient; //Vertex morph; //Vector3I lowerLodCell = (mesh.Cells[vertexIndex]) >> 1; //if (m_morphMap.TryGetValue(lowerLodCell, out morph)) //{ // vertex.PositionMorph = morph.Target.Position; // vertex.NormalMorph = morph.Target.Normal; // vertex.MaterialMorph = morph.Target.Material; // vertex.AmbientMorph = morph.Target.Ambient; //} //else //{ //} //if (m_lowVertices.Count > 0) //{ // float closestDistance = float.MaxValue; // int closestLowVertex = -1; // for (int i = 0; i < m_lowVertices.Count; i++) // { // float dist = Vector3.DistanceSquared(vertex.Position, m_lowVertices[i].Target.Position); // if (dist < closestDistance) // { // closestDistance = dist; // closestLowVertex = i; // } // } // vertex.PositionMorph = m_lowVertices[closestLowVertex].Target.Position; // vertex.NormalMorph = m_lowVertices[closestLowVertex].Target.Normal; // vertex.MaterialMorph = m_lowVertices[closestLowVertex].Target.Material; // vertex.AmbientMorph = m_lowVertices[closestLowVertex].Target.Ambient; // m_lowToHighMapping[closestLowVertex].Add(vertexIndex); // m_highToLowMapping.Add(closestLowVertex); //} m_highVertices.Add(vertex); }
private void AddMeshTriangles(MyIsoMesh mesh, Vector3 offset, Matrix rotation, Matrix ownRotation) { for (int i = 0; i < mesh.TrianglesCount; i++) { ushort a = mesh.Triangles[i].VertexIndex0; ushort b = mesh.Triangles[i].VertexIndex1; ushort c = mesh.Triangles[i].VertexIndex2; m_worldVertices.Triangles.Add(m_worldVertices.VerticesMaxValue + c); m_worldVertices.Triangles.Add(m_worldVertices.VerticesMaxValue + b); m_worldVertices.Triangles.Add(m_worldVertices.VerticesMaxValue + a); } for (int i = 0; i < mesh.VerticesCount; i++) { Vector3 vert; mesh.GetUnpackedPosition(i, out vert); Vector3.Transform(ref vert, ref ownRotation, out vert); vert -= offset; Vector3.Transform(ref vert, ref rotation, out vert); m_worldVertices.Vertices.Add(vert); } m_worldVertices.VerticesMaxValue += mesh.VerticesCount; }
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(); }
internal HkBvCompressedMeshShape CreateShape(MyIsoMesh mesh) { // mk:NOTE This method must be thread safe. Called from worker threads. if (mesh == null || mesh.TrianglesCount == 0 || mesh.VerticesCount == 0) return (HkBvCompressedMeshShape)HkShape.Empty; List<int> indexList = new List<int>(mesh.TrianglesCount * 3); List<Vector3> vertexList = new List<Vector3>(mesh.VerticesCount); for (int i = 0; i < mesh.TrianglesCount; i++) { indexList.Add(mesh.Triangles[i].VertexIndex0); indexList.Add(mesh.Triangles[i].VertexIndex2); indexList.Add(mesh.Triangles[i].VertexIndex1); } // mk:TODO Unify denormalizing of positions with what is in MyIsoMesh. var positionOffset = mesh.PositionOffset - m_voxelMap.StorageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var positions = mesh.Positions.GetInternalArray(); for (int i = 0; i < mesh.VerticesCount; i++) { vertexList.Add(positions[i] * mesh.PositionScale + positionOffset); } using (var cellGeometry = new HkGeometry(vertexList, indexList)) { var result = new HkBvCompressedMeshShape(cellGeometry, null, null, HkWeldingType.None, MyPerGameSettings.PhysicsConvexRadius); Debug.Assert(result.Base.ReferenceCount == 1); return result; } }
public static bool IsEmpty(MyIsoMesh self) { return(self == null || self.Triangles.Count == 0); }