public void Init( Vector3 positionOffset, Vector3 positionScale, Vector3[] positions, int vertexCount, MyVoxelTriangle[] triangles, int triangleCount) { if (vertexCount == 0) { VoxelVerticesCount = 0; VoxelTrianglesCount = 0; m_octree = null; m_positions = null; return; } Debug.Assert(vertexCount <= Int16.MaxValue); // copy voxel vertices m_positionOffset = positionOffset; m_positionScale = positionScale; m_positions = new Vector3[vertexCount]; Array.Copy(positions, m_positions, vertexCount); ProfilerShort.Begin("build octree"); if (m_octree == null) m_octree = new MyOctree(); m_octree.Init(m_positions, vertexCount, triangles, triangleCount, out VoxelTriangles); ProfilerShort.End(); // set size only after the arrays are fully allocated VoxelVerticesCount = vertexCount; VoxelTrianglesCount = triangleCount; }
private void GetCellLineIntersectionOctree(ref MyIntersectionResultLineTriangle?result, ref Line modelSpaceLine, ref float?minDistanceUntilNow, CellData cachedDataCell, IntersectionFlags flags) { m_overlapElementCache.Clear(); if (cachedDataCell.Octree != null) { Vector3 vector; Vector3 vector2; cachedDataCell.GetPackedPosition(ref modelSpaceLine.From, out vector); cachedDataCell.GetPackedPosition(ref modelSpaceLine.To, out vector2); Ray ray = new Ray(vector, vector2 - vector); cachedDataCell.Octree.GetIntersectionWithLine(ref ray, m_overlapElementCache); } for (int i = 0; i < m_overlapElementCache.Count; i++) { int index = m_overlapElementCache[i]; if ((cachedDataCell.VoxelTriangles != null) && (index < cachedDataCell.VoxelTriangles.Length)) { MyTriangle_Vertices vertices; MyVoxelTriangle triangle = cachedDataCell.VoxelTriangles[index]; cachedDataCell.GetUnpackedPosition(triangle.V0, out vertices.Vertex0); cachedDataCell.GetUnpackedPosition(triangle.V1, out vertices.Vertex1); cachedDataCell.GetUnpackedPosition(triangle.V2, out vertices.Vertex2); Vector3 normalVectorFromTriangle = MyUtils.GetNormalVectorFromTriangle(ref vertices); if (normalVectorFromTriangle.IsValid() && (((flags & IntersectionFlags.FLIPPED_TRIANGLES) != ((IntersectionFlags)0)) || (Vector3.Dot(modelSpaceLine.Direction, normalVectorFromTriangle) <= 0f))) { float?lineTriangleIntersection = MyUtils.GetLineTriangleIntersection(ref modelSpaceLine, ref vertices); if ((lineTriangleIntersection != null) && ((result == 0) || (lineTriangleIntersection.Value < result.Value.Distance))) { minDistanceUntilNow = new float?(lineTriangleIntersection.Value); result = new MyIntersectionResultLineTriangle(0, ref vertices, ref normalVectorFromTriangle, lineTriangleIntersection.Value); } } } } }
private void GetCellLineIntersectionOctree(ref MyIntersectionResultLineTriangle?result, ref Line modelSpaceLine, ref float?minDistanceUntilNow, CellData cachedDataCell, IntersectionFlags flags) { m_overlapElementCache.Clear(); if (cachedDataCell.Octree != null) { Vector3 packedStart, packedEnd; cachedDataCell.GetPackedPosition(ref modelSpaceLine.From, out packedStart); cachedDataCell.GetPackedPosition(ref modelSpaceLine.To, out packedEnd); var ray = new Ray(packedStart, packedEnd - packedStart); cachedDataCell.Octree.GetIntersectionWithLine(ref ray, m_overlapElementCache); } for (int j = 0; j < m_overlapElementCache.Count; j++) { var i = m_overlapElementCache[j]; if (cachedDataCell.VoxelTriangles == null) //probably not calculated yet { continue; } // this should never happen if (i >= cachedDataCell.VoxelTriangles.Length) { Debug.Assert(i < cachedDataCell.VoxelTriangles.Length); continue; } MyVoxelTriangle voxelTriangle = cachedDataCell.VoxelTriangles[i]; MyTriangle_Vertexes triangleVertices; cachedDataCell.GetUnpackedPosition(voxelTriangle.VertexIndex0, out triangleVertices.Vertex0); cachedDataCell.GetUnpackedPosition(voxelTriangle.VertexIndex1, out triangleVertices.Vertex1); cachedDataCell.GetUnpackedPosition(voxelTriangle.VertexIndex2, out triangleVertices.Vertex2); Vector3 calculatedTriangleNormal = MyUtils.GetNormalVectorFromTriangle(ref triangleVertices); if (!calculatedTriangleNormal.IsValid()) { continue; } //We dont want backside intersections if (((int)(flags & IntersectionFlags.FLIPPED_TRIANGLES) == 0) && Vector3.Dot(modelSpaceLine.Direction, calculatedTriangleNormal) > 0) { continue; } // AABB intersection test removed, AABB is tested inside BVH float?distance = MyUtils.GetLineTriangleIntersection(ref modelSpaceLine, ref triangleVertices); // If intersection occured and if distance to intersection is closer to origin than any previous intersection if ((distance != null) && ((result == null) || (distance.Value < result.Value.Distance))) { minDistanceUntilNow = distance.Value; result = new MyIntersectionResultLineTriangle(ref triangleVertices, ref calculatedTriangleNormal, distance.Value); } } }
internal void BuildCell( MyPrecalcJobRender.Args args, MyIsoMesh highResMesh, MyIsoMesh lowResMesh, List <MyClipmapCellBatch> outBatches, out MyClipmapCellMeshMetadata meta) { ProfilerShort.Begin("MyRenderCellBuilder.BuildCell"); Debug.Assert(highResMesh != null); meta.Cell = args.Cell; meta.PositionOffset = highResMesh.PositionOffset; meta.PositionScale = highResMesh.PositionScale; meta.LocalAabb = BoundingBox.CreateInvalid(); m_lowVertices.SetSize(0); m_highVertices.SetSize(0); ProcessLowMesh(highResMesh, lowResMesh); // Increase lookup count, so we will think that all vertices in helper arrays are new foreach (var lookup in SM_BatchLookups.Values) { lookup.ResetBatch(); } for (int i = 0; i < highResMesh.VerticesCount; i++) { MyVoxelVertex vertex; ProcessHighVertex(highResMesh, i, out vertex); } if (lowResMesh != null) { m_highGrid.ClearFast(); for (int i = 0; i < m_highVertices.Count; i++) { Vector3 position = m_highVertices[i].Position; m_highGrid.AddPoint(ref position, i); } //TODO: Fix ocassional bad triangles on asteroid /* * //Closest vertex * for (int l = 0; l < m_lowVertices.Count; l++) * { * Vector3 targetPosition = m_lowVertices[l].Target.Position; * * int bestV = -1; * float ldist = float.MaxValue; * float startMeters = 1; * float maxDistance = 10; * * MyVector3Grid<int>.Enumerator points = default(MyVector3Grid<int>.Enumerator); * while (startMeters < maxDistance) * { * points = m_highGrid.GetPointsCloserThan(ref targetPosition, startMeters); * * while (points.MoveNext()) * { * var dist = Vector3.DistanceSquared(targetPosition, m_highVertices[points.Current].Position); * if (dist < ldist) * { * ldist = dist; * bestV = points.Current; * } * } * * if (bestV != -1) * break; * * startMeters += 1; * } * * if (bestV != -1) * { * var vtx = m_highVertices[bestV]; * vtx.PositionMorph = m_lowVertices[l].Target.Position; * vtx.NormalMorph = m_lowVertices[l].Target.Normal; * vtx.MaterialMorph = m_lowVertices[l].Target.Material; * vtx.AmbientMorph = m_lowVertices[l].Target.Ambient; * m_highVertices[bestV] = vtx; * } * else * { * } * } * */ //Closest vertex float largestDistance = float.MinValue; for (int i = 0; i < m_highVertices.Count; i++) { float ldist = float.MaxValue; int bestV = -1; for (int l = 0; l < m_lowVertices.Count; l++) { var dist = Vector3.DistanceSquared(m_lowVertices[l].Target.Position, m_highVertices[i].Position); if (dist < ldist) { ldist = dist; bestV = l; } } var highVertex = m_highVertices[i]; highVertex.PositionMorph = m_lowVertices[bestV].Target.Position; highVertex.NormalMorph = m_lowVertices[bestV].Target.Normal; highVertex.MaterialMorph = m_lowVertices[bestV].Target.Material; highVertex.AmbientMorph = m_lowVertices[bestV].Target.Ambient; float p1 = highVertex.Position.AbsMax(); if (p1 > largestDistance) { largestDistance = p1; } float p2 = highVertex.PositionMorph.AbsMax(); if (p2 > largestDistance) { largestDistance = p2; } m_highVertices[i] = highVertex; } for (int i = 0; i < m_highVertices.Count; i++) { MyVoxelVertex vertex = m_highVertices[i]; vertex.Position /= largestDistance; vertex.PositionMorph /= largestDistance; m_highVertices[i] = vertex; } meta.PositionScale *= largestDistance; } //Create batches for (int i = 0; i < m_highVertices.Count; i++) { MyVoxelVertex vertex = m_highVertices[i]; meta.LocalAabb.Include(vertex.Position * meta.PositionScale + meta.PositionOffset); meta.LocalAabb.Include(vertex.PositionMorph * meta.PositionScale + meta.PositionOffset); Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); } for (int i = 0; i < highResMesh.TrianglesCount; i++) { MyVoxelTriangle srcTriangle = highResMesh.Triangles[i]; MyVoxelVertex vertex0 = m_highVertices[srcTriangle.VertexIndex0]; MyVoxelVertex vertex1 = m_highVertices[srcTriangle.VertexIndex1]; MyVoxelVertex vertex2 = m_highVertices[srcTriangle.VertexIndex2]; if (vertex0.Material == vertex1.Material && vertex0.Material == vertex2.Material && vertex0.Material == vertex0.MaterialMorph && vertex0.Material == vertex1.MaterialMorph && vertex0.Material == vertex2.MaterialMorph) { // single material var matIdx = vertex0.Material; // This is single-texture triangleVertexes, so we can choose material from any edge SingleMaterialHelper materialHelper; if (!SM_Helpers.TryGetValue(matIdx, out materialHelper)) { if (!SM_HelperPool.TryDequeue(out materialHelper)) { materialHelper = new SingleMaterialHelper(); } materialHelper.Material = matIdx; SM_Helpers.Add(matIdx, materialHelper); } VertexInBatchLookup batchLookup; if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup)) { if (!SM_BatchLookupPool.TryDequeue(out batchLookup)) { batchLookup = new VertexInBatchLookup(); } SM_BatchLookups.Add(matIdx, batchLookup); } AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0); AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1); AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2); // Add indices int nextTriangleIndex = materialHelper.IndexCount; materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0); materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1); materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2); materialHelper.IndexCount += 3; if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) || (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP)) { // If this batch is almost full (or is full), we end it and start with new one EndSingleMaterial(materialHelper, outBatches); } } else { Vector3I materials = GetMaterials(ref vertex0, ref vertex1, ref vertex2); Debug.Assert(materials.X < 1 << 10, "Too many materials"); Debug.Assert(materials.Y < 1 << 10, "Too many materials"); Debug.Assert(materials.Z < 1 << 10, "Too many materials"); int id = materials.X + (materials.Y + (materials.Z << 10) << 10); // Assign current material MultiMaterialHelper helper = null; if (!MM_Helpers.TryGetValue(id, out helper)) { if (!MM_HelperPool.TryDequeue(out helper)) { helper = new MultiMaterialHelper(); } helper.Material0 = materials.X; helper.Material1 = materials.Y; helper.Material2 = materials.Z; MM_Helpers.Add(id, helper); } helper.AddVertex(ref vertex0); helper.AddVertex(ref vertex1); helper.AddVertex(ref vertex2); if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP) { EndMultiMaterial(helper, outBatches); } } } { //renderCell.End(); foreach (var helper in SM_Helpers.Values) { Debug.Assert(helper != null); if (helper.IndexCount > 0) { EndSingleMaterial(helper, outBatches); } helper.IndexCount = 0; helper.VertexCount = 0; SM_HelperPool.Enqueue(helper); } SM_Helpers.Clear(); foreach (var helper in MM_Helpers.Values) { if (helper.Vertices.Count > 0) { EndMultiMaterial(helper, outBatches); } helper.Vertices.Clear(); MM_HelperPool.Enqueue(helper); } MM_Helpers.Clear(); foreach (var lookup in SM_BatchLookups.Values) { SM_BatchLookupPool.Enqueue(lookup); } SM_BatchLookups.Clear(); } m_morphMap.Clear(); meta.BatchCount = outBatches.Count; ProfilerShort.End(); }
internal void BuildCell( MyPrecalcJobRender.Args args, MyIsoMesh highResMesh, MyIsoMesh lowResMesh, List <MyClipmapCellBatch> outBatches, out MyClipmapCellMeshMetadata meta) { Debug.Assert(highResMesh != null); meta.Cell = args.Cell; meta.PositionOffset = highResMesh.PositionOffset; meta.PositionScale = highResMesh.PositionScale; meta.LocalAabb = BoundingBox.CreateInvalid(); m_lowVertices.Clear(); m_highVertices.Clear(); m_lowToHighMapping.Clear(); m_highToLowMapping.Clear(); m_highTriangles.Clear(); ProcessLowMesh(highResMesh, lowResMesh); // Increase lookup count, so we will think that all vertices in helper arrays are new foreach (var lookup in SM_BatchLookups.Values) { lookup.ResetBatch(); } //for (int i = 0; i < highResMesh.TrianglesCount; i++) //{ // var v0 = highResMesh.Triangles[i].VertexIndex0; // var v1 = highResMesh.Triangles[i].VertexIndex1; // var v2 = highResMesh.Triangles[i].VertexIndex2; // MyVoxelVertex vertex; // ProcessHighVertex(highResMesh, v0, ref meta, out vertex); // ProcessHighVertex(highResMesh, v1, ref meta, out vertex); // ProcessHighVertex(highResMesh, v2, ref meta, out vertex); // m_highTriangles.Add(new MyVoxelTriangle() // { // VertexIndex0 = (ushort)(i * 3), // VertexIndex1 = (ushort)(i * 3 + 1), // VertexIndex2 = (ushort)(i * 3 + 2), // }); //} for (int i = 0; i < highResMesh.TrianglesCount; i++) { m_highTriangles.Add(highResMesh.Triangles[i]); } for (int i = 0; i < highResMesh.VerticesCount; i++) { MyVoxelVertex vertex; ProcessHighVertex(highResMesh, i, ref meta, out vertex); } if (lowResMesh != null) { //Closest vertex for (int i = 0; i < m_highVertices.Count; i++) { float ldist = float.MaxValue; int bestV = -1; for (int l = 0; l < m_lowVertices.Count; l++) { var dist = Vector3.DistanceSquared(m_lowVertices[l].Target.Position, m_highVertices[i].Position); if (dist < ldist) { ldist = dist; bestV = l; } } var vtx = m_highVertices[i]; vtx.PositionMorph = m_lowVertices[bestV].Target.Position; vtx.Normal = m_lowVertices[bestV].Target.Normal; vtx.Material = m_lowVertices[bestV].Target.Material; vtx.Ambient = m_lowVertices[bestV].Target.Ambient; m_highVertices[i] = vtx; } //// //HashSet<int> alreadySetHighTris = new HashSet<int>(); ////all low tris must have at least one tri from high set, otherwise holes appear. //for (int l = 0; l < lowResMesh.TrianglesCount; l++) //{ // float triDist = float.MaxValue; // int bestT = -1; // for (int i = 0; i < m_highTriangles.Count; i++) // { // if (alreadySetHighTris.Contains(i)) // continue; // float dist = 0; // dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position); // dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position); // dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position); // if (dist < triDist) // { // triDist = dist; // bestT = i; // } // } // if (bestT == -1) // { // //Happens when LOD0 has less tris than LOD1 // bestT = 0; // } // alreadySetHighTris.Add(bestT); // var v0 = m_highVertices[m_highTriangles[bestT].VertexIndex0]; // v0.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position; // v0.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Normal; // v0.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Ambient; // m_highVertices[m_highTriangles[bestT].VertexIndex0] = v0; // var v1 = m_highVertices[m_highTriangles[bestT].VertexIndex1]; // v1.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position; // v1.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Normal; // v1.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Ambient; // m_highVertices[m_highTriangles[bestT].VertexIndex1] = v1; // var v2 = m_highVertices[m_highTriangles[bestT].VertexIndex2]; // v2.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position; // v2.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Normal; // v2.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Ambient; // m_highVertices[m_highTriangles[bestT].VertexIndex2] = v2; //} //List<MyVoxelTriangle> restHighTriangles = new List<MyVoxelTriangle>(m_highTriangles); //List<int> toRemove = new List<int>(); //foreach (var i in alreadySetHighTris) //{ // toRemove.Add(i); //} //toRemove.Sort(); //for (int i = toRemove.Count - 1; i >= 0; i--) //{ // restHighTriangles.RemoveAt(toRemove[i]); //} //for (int i = 0; i < restHighTriangles.Count; i++) //{ // float triDist = float.MaxValue; // int bestT = -1; // int swtch = 0; // for (int l = 0; l < lowResMesh.TrianglesCount; l++) // { // float dist = 0; // dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position); // dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position); // dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position); // float dist1 = 0; // dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position); // dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position); // dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position); // float dist2 = 0; // dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position); // dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position); // dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position); // int sw = 0; // if (dist1 < dist && dist1 < dist2) // { // dist = dist1; // sw = 1; // } // if (dist2 < dist && dist2 < dist1) // { // dist = dist2; // sw = 2; // } // if (dist < triDist) // { // triDist = dist; // bestT = l; // swtch = sw; // } // } // //bestT = i % lowResMesh.TrianglesCount; // //bestT = MyUtils.GetRandomInt(lowResMesh.TrianglesCount); // int vi0 = lowResMesh.Triangles[bestT].VertexIndex0; // int vi1 = lowResMesh.Triangles[bestT].VertexIndex1; // int vi2 = lowResMesh.Triangles[bestT].VertexIndex2; // if (swtch == 1) // { // vi0 = lowResMesh.Triangles[bestT].VertexIndex1; // vi1 = lowResMesh.Triangles[bestT].VertexIndex2; // vi2 = lowResMesh.Triangles[bestT].VertexIndex0; // } // if (swtch == 2) // { // vi0 = lowResMesh.Triangles[bestT].VertexIndex2; // vi1 = lowResMesh.Triangles[bestT].VertexIndex0; // vi2 = lowResMesh.Triangles[bestT].VertexIndex1; // } // var v0 = m_highVertices[restHighTriangles[i].VertexIndex0]; // v0.PositionMorph = m_lowVertices[vi0].Target.Position; // v0.NormalMorph = m_lowVertices[vi0].Target.Normal; // v0.AmbientMorph = m_lowVertices[vi0].Target.Ambient; // m_highVertices[restHighTriangles[i].VertexIndex0] = v0; // var v1 = m_highVertices[restHighTriangles[i].VertexIndex1]; // v1.PositionMorph = m_lowVertices[vi1].Target.Position; // v1.NormalMorph = m_lowVertices[vi1].Target.Normal; // v1.AmbientMorph = m_lowVertices[vi1].Target.Ambient; // m_highVertices[restHighTriangles[i].VertexIndex1] = v1; // var v2 = m_highVertices[restHighTriangles[i].VertexIndex2]; // v2.PositionMorph = m_lowVertices[vi2].Target.Position; // v2.NormalMorph = m_lowVertices[vi2].Target.Normal; // v2.AmbientMorph = m_lowVertices[vi2].Target.Ambient; // m_highVertices[restHighTriangles[i].VertexIndex2] = v2; //} ////add low lod //for (int i = 0; i < lowResMesh.TrianglesCount; i++) //{ // var lt = lowResMesh.Triangles[i]; // m_highTriangles.Add(new MyVoxelTriangle() // { // VertexIndex0 = (ushort)(lt.VertexIndex0 + m_highVertices.Count), // VertexIndex1 = (ushort)(lt.VertexIndex1 + m_highVertices.Count), // VertexIndex2 = (ushort)(lt.VertexIndex2 + m_highVertices.Count), // } // ); //} //for (int i = 0; i < m_lowVertices.Count; i++) //{ // var vertex = new MyVoxelVertex(); // vertex.Position = m_lowVertices[i].Target.Position; // vertex.Normal = m_lowVertices[i].Target.Normal; // vertex.Material = m_lowVertices[i].Target.Material; // vertex.Ambient = 0; // vertex.PositionMorph = vertex.Position; // vertex.NormalMorph = vertex.Normal; // vertex.MaterialMorph = vertex.Material; // vertex.AmbientMorph = vertex.Ambient; // m_highVertices.Add(vertex); //} // List<MyVoxelTriangle> newTriangles = new List<MyVoxelTriangle>(); // for (int i = 0; i < m_highTriangles.Count; i++) // { // MyVoxelVertex v0 = m_highVertices[m_highTriangles[i].VertexIndex0]; // MyVoxelVertex v1 = m_highVertices[m_highTriangles[i].VertexIndex1]; // MyVoxelVertex v2 = m_highVertices[m_highTriangles[i].VertexIndex2]; // for (int v = 0; v < m_highVertices.Count; v++) // { // if (v0.Position == m_highVertices[v].Position) // { // if (v0.PositionMorph == m_highVertices[v].PositionMorph) // { // var t = m_highTriangles[i]; // t.VertexIndex0 = (ushort)v; // m_highTriangles[i] = t; // break; // } // else // { // var vert1 = m_highVertices[m_highTriangles[i].VertexIndex1]; // var vert2 = m_highVertices[m_highTriangles[i].VertexIndex2]; // vert1.Position = m_highVertices[v].Position; // vert2.Position = m_highVertices[v].Position; // m_highVertices.Add(vert1); // m_highVertices.Add(vert2); // newTriangles.Add(new MyVoxelTriangle() // { // VertexIndex0 = (ushort)v, // VertexIndex1 = (ushort)(m_highVertices.Count - 2), // VertexIndex2 = (ushort)(m_highVertices.Count - 1) // }); // } // } // } // for (int v = 0; v < m_highVertices.Count; v++) // { // if (v1.Position == m_highVertices[v].Position) // { // if (v1.PositionMorph == m_highVertices[v].PositionMorph) // { // var t = m_highTriangles[i]; // t.VertexIndex1 = (ushort)v; // m_highTriangles[i] = t; // break; // } // else // { // var vert0 = m_highVertices[m_highTriangles[i].VertexIndex0]; // var vert2 = m_highVertices[m_highTriangles[i].VertexIndex2]; // vert0.Position = m_highVertices[v].Position; // vert2.Position = m_highVertices[v].Position; // m_highVertices.Add(vert0); // m_highVertices.Add(vert2); // newTriangles.Add(new MyVoxelTriangle() // { // VertexIndex0 = (ushort)(m_highVertices.Count - 2), // VertexIndex1 = (ushort)v, // VertexIndex2 = (ushort)(m_highVertices.Count - 1) // }); // } // } // } // for (int v = 0; v < m_highVertices.Count; v++) // { // if (v2.Position == m_highVertices[v].Position) // { // if (v2.PositionMorph == m_highVertices[v].PositionMorph) // { // var t = m_highTriangles[i]; // t.VertexIndex2 = (ushort)v; // m_highTriangles[i] = t; // break; // } // else // { // var vert0 = m_highVertices[m_highTriangles[i].VertexIndex0]; // var vert1 = m_highVertices[m_highTriangles[i].VertexIndex1]; // vert0.Position = m_highVertices[v].Position; // vert1.Position = m_highVertices[v].Position; // m_highVertices.Add(vert0); // m_highVertices.Add(vert1); // newTriangles.Add(new MyVoxelTriangle() // { // VertexIndex0 = (ushort)(m_highVertices.Count - 2), // VertexIndex1 = (ushort)(m_highVertices.Count - 1), // VertexIndex2 = (ushort)v // }); // } // } // } // } // foreach (var t in newTriangles) // { // m_highTriangles.Add(t); // } float largestDistance = float.MinValue; for (int i = 0; i < m_highVertices.Count; i++) { MyVoxelVertex vertex = m_highVertices[i]; float p1 = vertex.Position.AbsMax(); if (p1 > largestDistance) { largestDistance = p1; } float p2 = vertex.PositionMorph.AbsMax(); if (p2 > largestDistance) { largestDistance = p2; } } for (int i = 0; i < m_highVertices.Count; i++) { MyVoxelVertex vertex = m_highVertices[i]; vertex.Position /= largestDistance; vertex.PositionMorph /= largestDistance; m_highVertices[i] = vertex; } meta.PositionScale *= largestDistance; } else { } for (int i = 0; i < m_highVertices.Count; i++) { MyVoxelVertex vertex = m_highVertices[i]; meta.LocalAabb.Include(vertex.Position * meta.PositionScale + meta.PositionOffset); meta.LocalAabb.Include(vertex.PositionMorph * meta.PositionScale + meta.PositionOffset); Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); } for (int i = 0; i < m_highTriangles.Count; i++) { MyVoxelTriangle srcTriangle = m_highTriangles[i]; MyVoxelVertex vertex0, vertex1, vertex2; vertex0 = m_highVertices[srcTriangle.VertexIndex0]; vertex1 = m_highVertices[srcTriangle.VertexIndex1]; vertex2 = m_highVertices[srcTriangle.VertexIndex2]; if (vertex0.Material == vertex1.Material && vertex0.Material == vertex2.Material && vertex0.Material == vertex0.MaterialMorph && vertex0.Material == vertex1.MaterialMorph && vertex0.Material == vertex2.MaterialMorph) { // single material var matIdx = vertex0.Material; // This is single-texture triangleVertexes, so we can choose material from any edge SingleMaterialHelper materialHelper; if (!SM_Helpers.TryGetValue(matIdx, out materialHelper)) { if (!SM_HelperPool.TryDequeue(out materialHelper)) { materialHelper = new SingleMaterialHelper(); } materialHelper.Material = matIdx; SM_Helpers.Add(matIdx, materialHelper); } VertexInBatchLookup batchLookup; if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup)) { if (!SM_BatchLookupPool.TryDequeue(out batchLookup)) { batchLookup = new VertexInBatchLookup(); } SM_BatchLookups.Add(matIdx, batchLookup); } AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0); AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1); AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2); // Add indices int nextTriangleIndex = materialHelper.IndexCount; materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0); materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1); materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2); materialHelper.IndexCount += 3; if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) || (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP)) { // If this batch is almost full (or is full), we end it and start with new one EndSingleMaterial(materialHelper, outBatches); } } else { Vector3I materials = GetMaterials(ref vertex0, ref vertex1, ref vertex2); var voxelMaterialCount = MyDefinitionManager.Static.VoxelMaterialCount; int id = materials.X + voxelMaterialCount * (materials.Y + materials.Z * voxelMaterialCount); // Assign current material MultiMaterialHelper helper = null; if (!MM_Helpers.TryGetValue(id, out helper)) { if (!MM_HelperPool.TryDequeue(out helper)) { helper = new MultiMaterialHelper(); } helper.Material0 = materials.X; helper.Material1 = materials.Y; helper.Material2 = materials.Z; MM_Helpers.Add(id, helper); } helper.AddVertex(ref vertex0); helper.AddVertex(ref vertex1); helper.AddVertex(ref vertex2); if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP) { EndMultiMaterial(helper, outBatches); } } } { //renderCell.End(); foreach (var helper in SM_Helpers.Values) { Debug.Assert(helper != null); if (helper.IndexCount > 0) { EndSingleMaterial(helper, outBatches); } helper.IndexCount = 0; helper.VertexCount = 0; SM_HelperPool.Enqueue(helper); } SM_Helpers.Clear(); foreach (var helper in MM_Helpers.Values) { if (helper.Vertices.Count > 0) { EndMultiMaterial(helper, outBatches); } helper.Vertices.Clear(); MM_HelperPool.Enqueue(helper); } MM_Helpers.Clear(); foreach (var lookup in SM_BatchLookups.Values) { SM_BatchLookupPool.Enqueue(lookup); } SM_BatchLookups.Clear(); } m_morphMap.Clear(); }
public void Init(Vector3[] positions, int vertexCount, MyVoxelTriangle[] triangles, int triangleCount, out MyVoxelTriangle[] sortedTriangles) { for (int i = 0; i < NODE_COUNT; i++) { m_firstTriangleIndex[i] = 0; m_triangleCount[i] = 0; } for (int i = 0; i < 9; i++) { m_childEmpty[i] = 0; } // compute bounding box { BoundingBox bbox = BoundingBox.CreateInvalid(); for (int i = 0; i < vertexCount; i++) bbox.Include(ref positions[i]); m_bbMin = bbox.Min; var scale = bbox.Max - bbox.Min; m_bbInvScale = Vector3.One; // minimum bounding box size = 1 (in each dimension) if (scale.X > 1) m_bbInvScale.X = 1 / scale.X; if (scale.Y > 1) m_bbInvScale.Y = 1 / scale.Y; if (scale.Z > 1) m_bbInvScale.Z = 1 / scale.Z; } // compute triangle counts for (int i = 0; i < triangleCount; i++) { var t = triangles[i]; BoundingBox bbox = BoundingBox.CreateInvalid(); bbox.Include(ref positions[t.VertexIndex0], ref positions[t.VertexIndex1], ref positions[t.VertexIndex2]); short count = m_triangleCount[GetNode(ref bbox)]++; } // accumulate triangle counts m_firstTriangleIndex[0] = m_triangleCount[0]; for (int i = 1; i < NODE_COUNT; i++) { m_firstTriangleIndex[i] = (short)(m_firstTriangleIndex[i - 1] + m_triangleCount[i]); } // m_firstTriangleIndex[i] now contains the first index AFTER where the node's triangles will be, e.g.: // m_triangleCount: 2 0 4 3 // m_firstTriangleIndex: 2 2 6 9 // bucketsort triangles into the output array according to the nodes they're in var newSortedTriangles = new MyVoxelTriangle[triangleCount]; for (int i = 0; i < triangleCount; i++) { var t = triangles[i]; BoundingBox bbox = BoundingBox.CreateInvalid(); bbox.Include(ref positions[t.VertexIndex0], ref positions[t.VertexIndex1], ref positions[t.VertexIndex2]); newSortedTriangles[--m_firstTriangleIndex[GetNode(ref bbox)]] = t; } sortedTriangles = newSortedTriangles; // "out sortedTriangles" may be the same as "triangles" // find empty children for (int i = NODE_COUNT - 1; i > 0; i--) if (m_triangleCount[i] == 0 && (i > 8 || m_childEmpty[i] == 0xFF)) // no triangles AND (no children OR all children empty) m_childEmpty[i - 1 >> 3] |= (byte)(1 << (i - 1 & 7)); }
public bool Intersects(ref BoundingSphereD localSphere) { MyPrecalcComponent.AssertUpdateThread(); // Get min and max cell coordinate where boundingBox can fit BoundingBoxD sphereBoundingBox = BoundingBoxD.CreateInvalid(); sphereBoundingBox.Include(ref localSphere); Vector3I cellCoordMin, cellCoordMax; { Vector3D minD = sphereBoundingBox.Min; Vector3D maxD = sphereBoundingBox.Max; MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref minD, out cellCoordMin); MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref maxD, out cellCoordMax); } // Fix min and max cell coordinates so they don't overlap the voxelmap ClampCellCoord(ref cellCoordMin); ClampCellCoord(ref cellCoordMax); MyCellCoord cell = new MyCellCoord(); for (cell.CoordInLod.X = cellCoordMin.X; cell.CoordInLod.X <= cellCoordMax.X; cell.CoordInLod.X++) { for (cell.CoordInLod.Y = cellCoordMin.Y; cell.CoordInLod.Y <= cellCoordMax.Y; cell.CoordInLod.Y++) { for (cell.CoordInLod.Z = cellCoordMin.Z; cell.CoordInLod.Z <= cellCoordMax.Z; cell.CoordInLod.Z++) { // If no overlap between bounding box of data cell and the sphere BoundingBox cellBoundingBox; MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref cell.CoordInLod, out cellBoundingBox); if (cellBoundingBox.Intersects(ref localSphere) == false) { continue; } // Get cell from cache. If not there, precalc it and store in the cache. // If null is returned, we know that cell doesn't contain any triangleVertexes so we don't need to do intersections. CellData cachedData = GetCell(ref cell); if (cachedData == null) { continue; } for (int i = 0; i < cachedData.VoxelTrianglesCount; i++) { MyVoxelTriangle voxelTriangle = cachedData.VoxelTriangles[i]; MyTriangle_Vertexes triangle; cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex0, out triangle.Vertex0); cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex1, out triangle.Vertex1); cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex2, out triangle.Vertex2); BoundingBox localTriangleAABB = BoundingBox.CreateInvalid(); localTriangleAABB.Include(ref triangle.Vertex0); localTriangleAABB.Include(ref triangle.Vertex1); localTriangleAABB.Include(ref triangle.Vertex2); // First test intersection of triangle's bounding box with line's bounding box. And only if they overlap or intersect, do further intersection tests. if (localTriangleAABB.Intersects(ref localSphere)) { PlaneD trianglePlane = new PlaneD(triangle.Vertex0, triangle.Vertex1, triangle.Vertex2); if (MyUtils.GetSphereTriangleIntersection(ref localSphere, ref trianglePlane, ref triangle) != null) { // If intersection found - we are finished. We don't need to look for more. return(true); } } } } } } return(false); }
public unsafe bool Intersects(ref BoundingSphere localSphere) { Vector3I vectori; Vector3I vectori2; BoundingBox box = BoundingBox.CreateInvalid(); box.Include(ref localSphere); Vector3 min = box.Min; Vector3 max = box.Max; MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref min, out vectori); MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref max, out vectori2); this.ClampCellCoord(ref vectori); this.ClampCellCoord(ref vectori2); MyCellCoord cell = new MyCellCoord { CoordInLod = { X = vectori.X } }; while (cell.CoordInLod.X <= vectori2.X) { cell.CoordInLod.Y = vectori.Y; while (true) { if (cell.CoordInLod.Y > vectori2.Y) { int *numPtr3 = (int *)ref cell.CoordInLod.X; numPtr3[0]++; break; } cell.CoordInLod.Z = vectori.Z; while (true) { BoundingBox box2; if (cell.CoordInLod.Z > vectori2.Z) { int *numPtr2 = (int *)ref cell.CoordInLod.Y; numPtr2[0]++; break; } MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref cell.CoordInLod, out box2); if (box2.Intersects(ref localSphere)) { CellData data = this.GetCell(ref cell); if (data != null) { for (int i = 0; i < data.VoxelTrianglesCount; i++) { MyTriangle_Vertices vertices; MyVoxelTriangle triangle = data.VoxelTriangles[i]; data.GetUnpackedPosition(triangle.V0, out vertices.Vertex0); data.GetUnpackedPosition(triangle.V1, out vertices.Vertex1); data.GetUnpackedPosition(triangle.V2, out vertices.Vertex2); BoundingBox box3 = BoundingBox.CreateInvalid(); box3.Include(ref vertices.Vertex0); box3.Include(ref vertices.Vertex1); box3.Include(ref vertices.Vertex2); if (box3.Intersects(ref localSphere)) { Plane trianglePlane = new Plane(vertices.Vertex0, vertices.Vertex1, vertices.Vertex2); if (MyUtils.GetSphereTriangleIntersection(ref localSphere, ref trianglePlane, ref vertices) != null) { return(true); } } } } } int *numPtr1 = (int *)ref cell.CoordInLod.Z; numPtr1[0]++; } } } return(false); }
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(); }