private static void AddVertexToBuffer(MySingleMaterialHelper materialHelper, ref MyVoxelVertex vertex0, int matIndex, short vertexIndex0) { if (MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookup[matIndex][vertexIndex0].CalcCounter != MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookupCount[matIndex]) { int nextVertexIndex = materialHelper.VertexCount; // Short overflow check System.Diagnostics.Debug.Assert(nextVertexIndex <= short.MaxValue); // copy position and ambient materialHelper.Vertices[nextVertexIndex].m_positionAndAmbient = vertex0.m_positionAndAmbient; materialHelper.Vertices[nextVertexIndex].Ambient = vertex0.Ambient; // Copy normal #if PACKED_VERTEX_FORMAT materialHelper.Vertices[nextVertexIndex].m_normal = vertex0.m_normal; #else materialHelper.Vertices[nextVertexIndex].Normal = vertex0.Normal; #endif MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookup[matIndex][vertexIndex0].CalcCounter = MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookupCount[matIndex]; MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookup[matIndex][vertexIndex0].VertexIndex = (short)nextVertexIndex; materialHelper.VertexCount++; } }
public void AddVertex(ref MyVoxelVertex vertex)//Vector3 pos, Vector3 normal, MyMwcVoxelMaterialsEnum material, float ambient) { var material = vertex.Material; byte alphaIndex; if (Material0 == material) { alphaIndex = 0; } else if (Material1 == material) { alphaIndex = 1; } else if (Material2 == material) { alphaIndex = 2; } else { throw new System.InvalidOperationException("Should not be there, invalid material"); } Vertices[VertexCount].m_positionAndAmbient = vertex.m_positionAndAmbient; Vertices[VertexCount].Ambient = vertex.Ambient; #if PACKED_VERTEX_FORMAT Vertices[VertexCount].m_normal = vertex.m_normal; #else Vertices[VertexCount].Normal = vertex.Normal; #endif Vertices[VertexCount].MaterialAlphaIndex = alphaIndex; VertexCount++; }
public void PrepareCache(MyVoxelVertex[] vertices, int vertexCount, MyVoxelTriangle[] triangles, int triangleCount) { lock (m_syncRoot) { if (vertexCount == 0) { VoxelVerticesCount = 0; VoxelTrianglesCount = 0; m_octree = null; VoxelVertices = null; return; } MyCommonDebugUtils.AssertDebug(vertexCount <= Int16.MaxValue); MyRender.GetRenderProfiler().StartProfilingBlock("build octree"); if (m_octree == null) m_octree = new MyOctree(); m_octree.Init(ref vertices, ref vertexCount, ref triangles, ref triangleCount, out VoxelTriangles); MyRender.GetRenderProfiler().EndProfilingBlock(); // copy voxel vertices VoxelVertices = new MyVoxelVertex[vertexCount]; for (int i = 0; i < vertexCount; i++) VoxelVertices[i] = vertices[i]; // set size only after the arrays are fully allocated VoxelVerticesCount = vertexCount; VoxelTrianglesCount = triangleCount; } }
public void AddVertex(ref MyVoxelVertex vertex)//Vector3 pos, Vector3 normal, MyVoxelMaterialsEnum material, float ambient) { var material = vertex.Material; byte alphaIndex; if (Material0.Index == material) { alphaIndex = 0; } else if (Material1.Index == material) { alphaIndex = 1; } else if (Material2.Index == material) { alphaIndex = 2; } else { throw new System.InvalidOperationException("Should not be there, invalid material"); } Vertices[VertexCount].Position = vertex.Position; Vertices[VertexCount].Ambient = vertex.Ambient; Vertices[VertexCount].Normal = vertex.Normal; Vertices[VertexCount].MaterialAlphaIndex = alphaIndex; VertexCount++; }
private static void AddVertexToBuffer(MySingleMaterialHelper materialHelper, ref MyVoxelVertex vertex0, int matIndex, short vertexIndex0) { MyVoxelCacheCellRenderHelper.CreateArrayIfNotExist(matIndex); if (MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookup[matIndex][vertexIndex0].CalcCounter != MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookupCount[matIndex]) { int nextVertexIndex = materialHelper.VertexCount; // Short overflow check System.Diagnostics.Debug.Assert(nextVertexIndex <= short.MaxValue); // copy position and ambient materialHelper.Vertices[nextVertexIndex].Position = vertex0.Position; materialHelper.Vertices[nextVertexIndex].Ambient = vertex0.Ambient; // Copy normal materialHelper.Vertices[nextVertexIndex].Normal = vertex0.Normal; MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookup[matIndex][vertexIndex0].CalcCounter = MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookupCount[matIndex]; MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookup[matIndex][vertexIndex0].VertexIndex = (short)nextVertexIndex; materialHelper.VertexCount++; } }
public void AddVertex(ref MyVoxelVertex vertex)//Vector3 pos, Vector3 normal, MyMwcVoxelMaterialsEnum material, float ambient) { var material = vertex.Material; byte alphaIndex; if (Material0 == material) alphaIndex = 0; else if (Material1 == material) alphaIndex = 1; else if (Material2 == material) alphaIndex = 2; else throw new System.InvalidOperationException("Should not be there, invalid material"); Vertices[VertexCount].m_positionAndAmbient = vertex.m_positionAndAmbient; Vertices[VertexCount].Ambient = vertex.Ambient; #if PACKED_VERTEX_FORMAT Vertices[VertexCount].m_normal = vertex.m_normal; #else Vertices[VertexCount].Normal = vertex.Normal; #endif Vertices[VertexCount].MaterialAlphaIndex = alphaIndex; VertexCount++; }
public static MyVoxelVertex?ReadVoxelVertexEx(BinaryReader binaryReader, EndPoint senderEndPoint) { MyMwcVoxelMaterialsEnum?voxelMaterial = MyMwcMessageIn.ReadVoxelMaterialsEnumEx(binaryReader, senderEndPoint); Byte4? normal = MyMwcMessageIn.ReadByte4Ex(binaryReader, senderEndPoint); UInt64?positionAndAmbient = MyMwcMessageIn.ReadUInt64Ex(binaryReader, senderEndPoint); if (voxelMaterial.HasValue && normal.HasValue && positionAndAmbient.HasValue) { MyVoxelVertex result = new MyVoxelVertex { Material = voxelMaterial.Value, m_normal = normal.Value, m_positionAndAmbient = { packed_value = positionAndAmbient.Value } }; return(result); } return(null); }
public void GetUnpackedVertex(int index, out MyVoxelVertex vertex) { vertex = (MyVoxelVertex)m_voxelVertices[index]; vertex.Position = vertex.Position * PositionScale + PositionOffset; }
// This method adds triangles from one data cell into this render cell. Single-texture triangles are added using indices (so we use m_notCompressedIndex buffer). // For this we need to find indices. We use lookup array for it. // Now we support only 16-bit indices, so vertex buffer can't have more then short.MaxValue vertices. public void AddTriangles(List <MyVoxelCacheCellData> cacheDataArray) { // MyPerformanceTimer.VoxelGpuBuffersBuild.Start(); //MyMwcVoxelMaterialsEnum? CurrentSingleMaterial = null; // bool triangleAdded = true; // while (triangleAdded) // { // triangleAdded = false; //CurrentSingleMaterial = null; foreach (var cacheData in cacheDataArray) { // Increase lookup count, so we will think that all vertexes in helper arrays are new for (int i = 0; i < MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookupCount.Length; i++) { MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookupCount[i]++; } for (int i = 0; i < cacheData.VoxelTrianglesCount; i++) { MyVoxelTriangle triangle = cacheData.VoxelTriangles[i]; MyVoxelVertex vertex0 = cacheData.VoxelVertices[triangle.VertexIndex0]; MyVoxelVertex vertex1 = cacheData.VoxelVertices[triangle.VertexIndex1]; MyVoxelVertex vertex2 = cacheData.VoxelVertices[triangle.VertexIndex2]; if ((vertex0.Material == vertex1.Material) && (vertex0.Material == vertex2.Material)) { int matIndex = (int)vertex0.Material; // This is single-texture triangleVertexes, so we can choose material from any edge MySingleMaterialHelper materialHelper = MyVoxelCacheCellRenderHelper.GetForMaterial(vertex0.Material); // Add vertex0 to vertex buffer AddVertexToBuffer(materialHelper, ref vertex0, matIndex, triangle.VertexIndex0); // Add vertex1 to vertex buffer AddVertexToBuffer(materialHelper, ref vertex1, matIndex, triangle.VertexIndex1); // Add vertex2 to vertex buffer AddVertexToBuffer(materialHelper, ref vertex2, matIndex, triangle.VertexIndex2); //triangleAdded = true; // Add indices int nextTriangleIndex = materialHelper.IndexCount; materialHelper.Indices[nextTriangleIndex + 0] = MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookup[matIndex][triangle.VertexIndex0].VertexIndex; materialHelper.Indices[nextTriangleIndex + 1] = MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookup[matIndex][triangle.VertexIndex1].VertexIndex; materialHelper.Indices[nextTriangleIndex + 2] = MyVoxelCacheCellRenderHelper.SingleMaterialIndicesLookup[matIndex][triangle.VertexIndex2].VertexIndex; materialHelper.IndexCount += 3; if ((materialHelper.VertexCount >= MyVoxelCacheCellRenderHelper.MAX_VERTICES_COUNT_STOP) || (materialHelper.IndexCount >= MyVoxelCacheCellRenderHelper.MAX_INDICES_COUNT_STOP)) { // If this batch is almost full (or is full), we end it and start with new one EndSingleMaterial(materialHelper); } } else { int id = GetMultimaterialId(vertex0.Material, vertex1.Material, vertex2.Material); // Assign current material MyMultiMaterialHelper multiMaterialHelper = MyVoxelCacheCellRenderHelper.GetForMultimaterial(vertex0.Material, vertex1.Material, vertex2.Material); //triangleAdded = true; #if PACKED_VERTEX_FORMAT // Copy packed normals multiMaterialHelper.Vertices[multiMaterialHelper.VertexCount + 0].PackedNormal = vertex0.PackedNormal; multiMaterialHelper.Vertices[multiMaterialHelper.VertexCount + 1].PackedNormal = vertex0.PackedNormal; multiMaterialHelper.Vertices[multiMaterialHelper.VertexCount + 2].PackedNormal = vertex0.PackedNormal; #endif multiMaterialHelper.AddVertex(ref vertex0); multiMaterialHelper.AddVertex(ref vertex1); multiMaterialHelper.AddVertex(ref vertex2); if (multiMaterialHelper.VertexCount >= MyVoxelCacheCellRenderHelper.MAX_VERTICES_COUNT_STOP) { EndMultiMaterial(multiMaterialHelper); } } } /* * if (multiMaterialHelper != null) * { * int id = GetMultimaterialId(multiMaterialHelper.Material0, multiMaterialHelper.Material1, multiMaterialHelper.Material2); * MyVoxelCacheCellRenderHelper.FinishedMultiMaterials[id] = true; * EndMultimaterial(multiMaterialHelper); * } * * if (singleMaterialHelper != null) * { * MyVoxelCacheCellRenderHelper.FinishedSingleMaterials[(int)singleMaterialHelper.Material] = true; * EndSingleMaterial(singleMaterialHelper); * } */ } // } //MyPerformanceTimer.VoxelGpuBuffersBuild.End(); }
public static MyVoxelVertex? ReadVoxelVertexEx(BinaryReader binaryReader, EndPoint senderEndPoint) { MyMwcVoxelMaterialsEnum? voxelMaterial = MyMwcMessageIn.ReadVoxelMaterialsEnumEx(binaryReader, senderEndPoint); Byte4? normal = MyMwcMessageIn.ReadByte4Ex(binaryReader, senderEndPoint); UInt64? positionAndAmbient = MyMwcMessageIn.ReadUInt64Ex(binaryReader, senderEndPoint); if (voxelMaterial.HasValue && normal.HasValue && positionAndAmbient.HasValue) { MyVoxelVertex result = new MyVoxelVertex { Material = voxelMaterial.Value, m_normal = normal.Value, m_positionAndAmbient = { packed_value = positionAndAmbient.Value } }; return result; } return null; }
public static void WriteVoxelVertex(MyVoxelVertex voxelVertex, BinaryWriter binaryWriter) { MyMwcMessageOut.WriteVoxelMaterialsEnum(voxelVertex.Material, binaryWriter); MyMwcMessageOut.WriteByte4(voxelVertex.m_normal, binaryWriter); binaryWriter.Write(voxelVertex.m_positionAndAmbient.packed_value); }
public void Init(ref MyVoxelVertex[] vertices, ref int vertexCount, ref MyVoxelTriangle[] triangles, ref 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 = BoundingBoxHelper.InitialBox; for (int i = 0; i < vertexCount; i++) BoundingBoxHelper.AddPoint(vertices[i].Position, ref bbox); 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 = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddTriangle(ref bbox, vertices[t.VertexIndex0].Position, vertices[t.VertexIndex1].Position, vertices[t.VertexIndex2].Position); 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 = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddTriangle(ref bbox, vertices[t.VertexIndex0].Position, vertices[t.VertexIndex1].Position, vertices[t.VertexIndex2].Position); 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)); }
// We want to skip all wrong triangles, those that have two vertex at almost the same location, etc. bool IsWrongTriangle(ref MyVoxelVertex edge0, ref MyVoxelVertex edge1, ref MyVoxelVertex edge2) { return(MyMeshPartSolver.IsWrongTriangle(edge0.Position, edge1.Position, edge2.Position)); }
private void CreateTriangles(ref Vector3I coord0, int cubeIndex, ref Vector3I tempVoxelCoord0) { MyVoxelVertex tmpVertex = new MyVoxelVertex(); Vector3I edge = new Vector3I(coord0.X - 1, coord0.Y - 1, coord0.Z - 1); for (int i = 0; MyMarchingCubesConstants.TriangleTable[cubeIndex, i] != -1; i += 3) { // Edge indexes inside the cube int edgeIndex0 = MyMarchingCubesConstants.TriangleTable[cubeIndex, i + 0]; int edgeIndex1 = MyMarchingCubesConstants.TriangleTable[cubeIndex, i + 1]; int edgeIndex2 = MyMarchingCubesConstants.TriangleTable[cubeIndex, i + 2]; MyEdge edge0 = m_edges[edgeIndex0]; MyEdge edge1 = m_edges[edgeIndex1]; MyEdge edge2 = m_edges[edgeIndex2]; // Edge indexes inside the cell Vector4I edgeConversion0 = MyMarchingCubesConstants.EdgeConversion[edgeIndex0]; Vector4I edgeConversion1 = MyMarchingCubesConstants.EdgeConversion[edgeIndex1]; Vector4I edgeConversion2 = MyMarchingCubesConstants.EdgeConversion[edgeIndex2]; MyEdgeVertex edgeVertex0 = m_edgeVertex[edge.X + edgeConversion0.X][edge.Y + edgeConversion0.Y][edge.Z + edgeConversion0.Z][edgeConversion0.W]; MyEdgeVertex edgeVertex1 = m_edgeVertex[edge.X + edgeConversion1.X][edge.Y + edgeConversion1.Y][edge.Z + edgeConversion1.Z][edgeConversion1.W]; MyEdgeVertex edgeVertex2 = m_edgeVertex[edge.X + edgeConversion2.X][edge.Y + edgeConversion2.Y][edge.Z + edgeConversion2.Z][edgeConversion2.W]; MyVoxelVertex compressedVertex0 = new MyVoxelVertex(); compressedVertex0.Position = edge0.Position; MyVoxelVertex compressedVertex1 = new MyVoxelVertex(); compressedVertex1.Position = edge1.Position; MyVoxelVertex compressedVertex2 = new MyVoxelVertex(); compressedVertex2.Position = edge2.Position; // We want to skip all wrong triangles, those that have two vertex at almost the same location, etc. // We do it simply, by calculating triangle normal and then checking if this normal has length large enough if (IsWrongTriangle(ref compressedVertex0, ref compressedVertex1, ref compressedVertex2) == true) { continue; } // Vertex at edge 0 if (edgeVertex0.CalcCounter != m_edgeVertexCalcCounter) { // If vertex at edge0 wasn't calculated for this cell during this precalc, we need to add it // Short overflow check System.Diagnostics.Debug.Assert(m_resultVerticesCounter <= short.MaxValue); edgeVertex0.CalcCounter = m_edgeVertexCalcCounter; edgeVertex0.VertexIndex = m_resultVerticesCounter; tmpVertex.Position = (edge0.Position - m_originPosition) / m_positionScale; tmpVertex.Normal = edge0.Normal; tmpVertex.Ambient = edge0.Ambient; tmpVertex.Material = edge0.Material; m_resultVertices[m_resultVerticesCounter] = tmpVertex; m_resultVerticesCounter++; } // Vertex at edge 1 if (edgeVertex1.CalcCounter != m_edgeVertexCalcCounter) { // If vertex at edge1 wasn't calculated for this cell during this precalc, we need to add it // Short overflow check System.Diagnostics.Debug.Assert(m_resultVerticesCounter <= short.MaxValue); edgeVertex1.CalcCounter = m_edgeVertexCalcCounter; edgeVertex1.VertexIndex = m_resultVerticesCounter; tmpVertex.Position = (edge1.Position - m_originPosition) / m_positionScale; tmpVertex.Normal = edge1.Normal; tmpVertex.Ambient = edge1.Ambient; tmpVertex.Material = edge1.Material; m_resultVertices[m_resultVerticesCounter] = tmpVertex; m_resultVerticesCounter++; } // Vertex at edge 2 if (edgeVertex2.CalcCounter != m_edgeVertexCalcCounter) { // If vertex at edge2 wasn't calculated for this cell during this precalc, we need to add it // Short overflow check System.Diagnostics.Debug.Assert(m_resultVerticesCounter <= short.MaxValue); edgeVertex2.CalcCounter = m_edgeVertexCalcCounter; edgeVertex2.VertexIndex = m_resultVerticesCounter; tmpVertex.Position = (edge2.Position - m_originPosition) / m_positionScale; tmpVertex.Normal = edge2.Normal; tmpVertex.Ambient = edge2.Ambient; tmpVertex.Material = edge2.Material; m_resultVertices[m_resultVerticesCounter] = tmpVertex; m_resultVerticesCounter++; } // Triangle m_resultTriangles[m_resultTrianglesCounter].VertexIndex0 = edgeVertex0.VertexIndex; m_resultTriangles[m_resultTrianglesCounter].VertexIndex1 = edgeVertex1.VertexIndex; m_resultTriangles[m_resultTrianglesCounter].VertexIndex2 = edgeVertex2.VertexIndex; Debug.Assert(edgeVertex0.VertexIndex < m_resultVerticesCounter); Debug.Assert(edgeVertex1.VertexIndex < m_resultVerticesCounter); Debug.Assert(edgeVertex2.VertexIndex < m_resultVerticesCounter); m_resultTrianglesCounter++; } }
// We want to skip all wrong triangles, those that have two vertex at almost the same location, etc. // We do it simply, by calculating triangle normal and then checking if this normal has length large enough bool IsWrongTriangle(ref MyVoxelVertex edge0, ref MyVoxelVertex edge1, ref MyVoxelVertex edge2) { // Distance between two vertices is the fastest test Vector3 triangleEdgeVector1 = edge2.Position - edge0.Position; if (triangleEdgeVector1.LengthSquared() <= MyMwcMathConstants.EPSILON_SQUARED) return true; // Distance between two vertexes is the fastest test Vector3 triangleEdgeVector2 = edge1.Position - edge0.Position; if (triangleEdgeVector2.LengthSquared() <= MyMwcMathConstants.EPSILON_SQUARED) return true; // Distance between two vertexes is the fastest test Vector3 triangleEdgeVector3 = edge1.Position - edge2.Position; if (triangleEdgeVector3.LengthSquared() <= MyMwcMathConstants.EPSILON_SQUARED) return true; // We don't need to do this advanced test, because it has zero improvement on voxel triangles (and testing takes time too) /*Vector3 norm; Vector3.Cross(ref triangleEdgeVector1, ref triangleEdgeVector2, out norm); if (norm.Length() < MyMwcMathConstants.EPSILON) return true;*/ return false; }
//// Copy shadow values of surrounding cells //void CopyShadowValues() //{ // if (m_precalcType == MyLodTypeEnum.LOD0) // { // // This is cell we are trying to precalculate // MyMwcVector3Int precalculatedCellCoord = m_voxelMap.GetDataCellCoordinate(ref m_voxelStart); // for (int x = 0; x < SHADOW_CELLS; x++) // { // for (int y = 0; y < SHADOW_CELLS; y++) // { // for (int z = 0; z < SHADOW_CELLS; z++) // { // MyMwcVector3Int tempCellCoord = new MyMwcVector3Int(precalculatedCellCoord.X + x - 1, precalculatedCellCoord.Y + y - 1, precalculatedCellCoord.Z + z - 1); // // This is coordinate of cell's middle and it may contain values that are outside voxel map. It is OK, because we use it for bilinear/average calculations. // m_shadows[x][y][z].CoordOfDataCellCenter = m_voxelMap.GetVoxelCoordinatesOfCenterOfDataCell(ref tempCellCoord); // if (m_voxelMap.IsDataCellInVoxelMap(ref tempCellCoord) == false) // { // // Data cell isn't in this voxel map, so it can't cast shadow map // m_shadows[x][y][z].ShadowValue = 1.0f; // } // else // { // m_shadows[x][y][z].ShadowValue = (float)m_voxelMap.GetDataCellShadow(ref tempCellCoord) / 255.0f; // } // } // } // } // } //} // Precalculate voxel cell into cache (makes triangles and vertex buffer from voxels) public void Precalc(MyVoxelPrecalcTaskItem task) { m_precalcType = task.Type; m_resultVerticesCounter = 0; m_resultTrianglesCounter = 0; m_edgeVertexCalcCounter++; m_voxelMap = task.VoxelMap; m_voxelStart = task.VoxelStart; try { //m_voxelMap.LockAcquireWriterLock(Timeout.Infinite); CalcPolygCubeSize(); //CopyShadowValues(); // Copy voxels into temp array bool totallyEmptyOrTotallyFull = CopyVoxelContents(); if (totallyEmptyOrTotallyFull == false) { // Size of voxel or cell (in meters) and size of voxel map / voxel cells float size; if (m_precalcType == MyLodTypeEnum.LOD0) { size = MyVoxelConstants.VOXEL_SIZE_IN_METRES; m_sizeMinusOne = m_voxelMap.SizeMinusOne; } else if (m_precalcType == MyLodTypeEnum.LOD1) { size = MyVoxelConstants.VOXEL_DATA_CELL_SIZE_IN_METRES; m_sizeMinusOne = m_voxelMap.DataCellsCountMinusOne; } else { throw new MyMwcExceptionApplicationShouldNotGetHere(); } // Origin position for voxels (in meters) Vector3 originPosition; if (m_precalcType == MyLodTypeEnum.LOD0) { originPosition = m_voxelMap.GetVoxelCenterPositionRelative(ref m_voxelStart); } else if (m_precalcType == MyLodTypeEnum.LOD1) { originPosition = m_voxelMap.GetDataCellCenterPositionRelative(ref m_voxelStart); } else { throw new MyMwcExceptionApplicationShouldNotGetHere(); } MyMwcVector3Int coord0; for (coord0.X = 1; coord0.X <= (m_polygCubesX - 1); coord0.X++) { for (coord0.Y = 1; coord0.Y <= (m_polygCubesY - 1); coord0.Y++) { for (coord0.Z = 1; coord0.Z <= (m_polygCubesZ - 1); coord0.Z++) { // 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. MyTemporaryVoxel tempVoxel0 = m_temporaryVoxels[coord0.X][coord0.Y][coord0.Z]; MyTemporaryVoxel tempVoxel1 = m_temporaryVoxels[coord0.X + 1][coord0.Y][coord0.Z]; MyTemporaryVoxel tempVoxel2 = m_temporaryVoxels[coord0.X + 1][coord0.Y][coord0.Z + 1]; MyTemporaryVoxel tempVoxel3 = m_temporaryVoxels[coord0.X][coord0.Y][coord0.Z + 1]; MyTemporaryVoxel tempVoxel4 = m_temporaryVoxels[coord0.X][coord0.Y + 1][coord0.Z]; MyTemporaryVoxel tempVoxel5 = m_temporaryVoxels[coord0.X + 1][coord0.Y + 1][coord0.Z]; MyTemporaryVoxel tempVoxel6 = m_temporaryVoxels[coord0.X + 1][coord0.Y + 1][coord0.Z + 1]; MyTemporaryVoxel tempVoxel7 = m_temporaryVoxels[coord0.X][coord0.Y + 1][coord0.Z + 1]; System.Diagnostics.Debug.Assert(tempVoxel0.Content_CalcCounter == m_temporaryVoxelsCounter); System.Diagnostics.Debug.Assert(tempVoxel1.Content_CalcCounter == m_temporaryVoxelsCounter); System.Diagnostics.Debug.Assert(tempVoxel2.Content_CalcCounter == m_temporaryVoxelsCounter); System.Diagnostics.Debug.Assert(tempVoxel3.Content_CalcCounter == m_temporaryVoxelsCounter); System.Diagnostics.Debug.Assert(tempVoxel4.Content_CalcCounter == m_temporaryVoxelsCounter); System.Diagnostics.Debug.Assert(tempVoxel5.Content_CalcCounter == m_temporaryVoxelsCounter); System.Diagnostics.Debug.Assert(tempVoxel6.Content_CalcCounter == m_temporaryVoxelsCounter); System.Diagnostics.Debug.Assert(tempVoxel7.Content_CalcCounter == m_temporaryVoxelsCounter); // 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. int cubeIndex = 0; if (tempVoxel0.Content < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 1; if (tempVoxel1.Content < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 2; if (tempVoxel2.Content < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 4; if (tempVoxel3.Content < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 8; if (tempVoxel4.Content < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 16; if (tempVoxel5.Content < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 32; if (tempVoxel6.Content < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 64; if (tempVoxel7.Content < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 128; // Cube is entirely in/out of the surface if (MyVoxelPrecalcConstants.EdgeTable[cubeIndex] == 0) { continue; } MyMwcVector3Int coord1 = new MyMwcVector3Int(coord0.X + 1, coord0.Y, coord0.Z); MyMwcVector3Int coord2 = new MyMwcVector3Int(coord0.X + 1, coord0.Y, coord0.Z + 1); MyMwcVector3Int coord3 = new MyMwcVector3Int(coord0.X, coord0.Y, coord0.Z + 1); MyMwcVector3Int coord4 = new MyMwcVector3Int(coord0.X, coord0.Y + 1, coord0.Z); MyMwcVector3Int coord5 = new MyMwcVector3Int(coord0.X + 1, coord0.Y + 1, coord0.Z); MyMwcVector3Int coord6 = new MyMwcVector3Int(coord0.X + 1, coord0.Y + 1, coord0.Z + 1); MyMwcVector3Int coord7 = new MyMwcVector3Int(coord0.X, coord0.Y + 1, coord0.Z + 1); MyMwcVector3Int tempVoxelCoord0 = new MyMwcVector3Int(m_voxelStart.X + coord0.X - 1, m_voxelStart.Y + coord0.Y - 1, m_voxelStart.Z + coord0.Z - 1); MyMwcVector3Int tempVoxelCoord1 = new MyMwcVector3Int(m_voxelStart.X + coord1.X - 1, m_voxelStart.Y + coord1.Y - 1, m_voxelStart.Z + coord1.Z - 1); MyMwcVector3Int tempVoxelCoord2 = new MyMwcVector3Int(m_voxelStart.X + coord2.X - 1, m_voxelStart.Y + coord2.Y - 1, m_voxelStart.Z + coord2.Z - 1); MyMwcVector3Int tempVoxelCoord3 = new MyMwcVector3Int(m_voxelStart.X + coord3.X - 1, m_voxelStart.Y + coord3.Y - 1, m_voxelStart.Z + coord3.Z - 1); MyMwcVector3Int tempVoxelCoord4 = new MyMwcVector3Int(m_voxelStart.X + coord4.X - 1, m_voxelStart.Y + coord4.Y - 1, m_voxelStart.Z + coord4.Z - 1); MyMwcVector3Int tempVoxelCoord5 = new MyMwcVector3Int(m_voxelStart.X + coord5.X - 1, m_voxelStart.Y + coord5.Y - 1, m_voxelStart.Z + coord5.Z - 1); MyMwcVector3Int tempVoxelCoord6 = new MyMwcVector3Int(m_voxelStart.X + coord6.X - 1, m_voxelStart.Y + coord6.Y - 1, m_voxelStart.Z + coord6.Z - 1); MyMwcVector3Int tempVoxelCoord7 = new MyMwcVector3Int(m_voxelStart.X + coord7.X - 1, m_voxelStart.Y + coord7.Y - 1, m_voxelStart.Z + coord7.Z - 1); tempVoxel0.Position.X = originPosition.X + (coord0.X - 1) * size; tempVoxel0.Position.Y = originPosition.Y + (coord0.Y - 1) * size; tempVoxel0.Position.Z = originPosition.Z + (coord0.Z - 1) * size; tempVoxel1.Position.X = tempVoxel0.Position.X + size; tempVoxel1.Position.Y = tempVoxel0.Position.Y; tempVoxel1.Position.Z = tempVoxel0.Position.Z; tempVoxel2.Position.X = tempVoxel0.Position.X + size; tempVoxel2.Position.Y = tempVoxel0.Position.Y; tempVoxel2.Position.Z = tempVoxel0.Position.Z + size; tempVoxel3.Position.X = tempVoxel0.Position.X; tempVoxel3.Position.Y = tempVoxel0.Position.Y; tempVoxel3.Position.Z = tempVoxel0.Position.Z + size; tempVoxel4.Position.X = tempVoxel0.Position.X; tempVoxel4.Position.Y = tempVoxel0.Position.Y + size; tempVoxel4.Position.Z = tempVoxel0.Position.Z; tempVoxel5.Position.X = tempVoxel0.Position.X + size; tempVoxel5.Position.Y = tempVoxel0.Position.Y + size; tempVoxel5.Position.Z = tempVoxel0.Position.Z; tempVoxel6.Position.X = tempVoxel0.Position.X + size; tempVoxel6.Position.Y = tempVoxel0.Position.Y + size; tempVoxel6.Position.Z = tempVoxel0.Position.Z + size; tempVoxel7.Position.X = tempVoxel0.Position.X; tempVoxel7.Position.Y = tempVoxel0.Position.Y + size; tempVoxel7.Position.Z = tempVoxel0.Position.Z + size; // Normals at grid corners (calculated from gradient) GetVoxelNormal(tempVoxel0, ref coord0, ref tempVoxelCoord0, tempVoxel0); GetVoxelNormal(tempVoxel1, ref coord1, ref tempVoxelCoord1, tempVoxel0); GetVoxelNormal(tempVoxel2, ref coord2, ref tempVoxelCoord2, tempVoxel0); GetVoxelNormal(tempVoxel3, ref coord3, ref tempVoxelCoord3, tempVoxel0); GetVoxelNormal(tempVoxel4, ref coord4, ref tempVoxelCoord4, tempVoxel0); GetVoxelNormal(tempVoxel5, ref coord5, ref tempVoxelCoord5, tempVoxel0); GetVoxelNormal(tempVoxel6, ref coord6, ref tempVoxelCoord6, tempVoxel0); GetVoxelNormal(tempVoxel7, ref coord7, ref tempVoxelCoord7, tempVoxel0); // Ambient occlusion colors at grid corners // IMPORTANT: At this point normals must be calculated because GetVoxelAmbientAndSun() will be retrieving them from temp table and not checking if there is actual value GetVoxelAmbient(tempVoxel0, ref coord0, ref tempVoxelCoord0); GetVoxelAmbient(tempVoxel1, ref coord1, ref tempVoxelCoord1); GetVoxelAmbient(tempVoxel2, ref coord2, ref tempVoxelCoord2); GetVoxelAmbient(tempVoxel3, ref coord3, ref tempVoxelCoord3); GetVoxelAmbient(tempVoxel4, ref coord4, ref tempVoxelCoord4); GetVoxelAmbient(tempVoxel5, ref coord5, ref tempVoxelCoord5); GetVoxelAmbient(tempVoxel6, ref coord6, ref tempVoxelCoord6); GetVoxelAmbient(tempVoxel7, ref coord7, ref tempVoxelCoord7); // Materials at grid corners GetVoxelMaterial(tempVoxel0, ref tempVoxelCoord0); GetVoxelMaterial(tempVoxel1, ref tempVoxelCoord1); GetVoxelMaterial(tempVoxel2, ref tempVoxelCoord2); GetVoxelMaterial(tempVoxel3, ref tempVoxelCoord3); GetVoxelMaterial(tempVoxel4, ref tempVoxelCoord4); GetVoxelMaterial(tempVoxel5, ref tempVoxelCoord5); GetVoxelMaterial(tempVoxel6, ref tempVoxelCoord6); GetVoxelMaterial(tempVoxel7, ref tempVoxelCoord7); // Find the vertices where the surface intersects the cube if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 1) == 1) { GetVertexInterpolation(tempVoxel0, tempVoxel1, 0); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 2) == 2) { GetVertexInterpolation(tempVoxel1, tempVoxel2, 1); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 4) == 4) { GetVertexInterpolation(tempVoxel2, tempVoxel3, 2); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 8) == 8) { GetVertexInterpolation(tempVoxel3, tempVoxel0, 3); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 16) == 16) { GetVertexInterpolation(tempVoxel4, tempVoxel5, 4); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 32) == 32) { GetVertexInterpolation(tempVoxel5, tempVoxel6, 5); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 64) == 64) { GetVertexInterpolation(tempVoxel6, tempVoxel7, 6); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 128) == 128) { GetVertexInterpolation(tempVoxel7, tempVoxel4, 7); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 256) == 256) { GetVertexInterpolation(tempVoxel0, tempVoxel4, 8); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 512) == 512) { GetVertexInterpolation(tempVoxel1, tempVoxel5, 9); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 1024) == 1024) { GetVertexInterpolation(tempVoxel2, tempVoxel6, 10); } if ((MyVoxelPrecalcConstants.EdgeTable[cubeIndex] & 2048) == 2048) { GetVertexInterpolation(tempVoxel3, tempVoxel7, 11); } // Create the triangles MyMwcVector3Int edge = new MyMwcVector3Int(coord0.X - 1, coord0.Y - 1, coord0.Z - 1); for (int i = 0; MyVoxelPrecalcConstants.TriangleTable[cubeIndex, i] != -1; i += 3) { // Edge indexes inside the cube int edgeIndex0 = MyVoxelPrecalcConstants.TriangleTable[cubeIndex, i + 0]; int edgeIndex1 = MyVoxelPrecalcConstants.TriangleTable[cubeIndex, i + 1]; int edgeIndex2 = MyVoxelPrecalcConstants.TriangleTable[cubeIndex, i + 2]; MyEdge edge0 = m_edges[edgeIndex0]; MyEdge edge1 = m_edges[edgeIndex1]; MyEdge edge2 = m_edges[edgeIndex2]; // Edge indexes inside the cell MyMwcVector4Int edgeConversion0 = MyVoxelPrecalcConstants.EdgeConversion[edgeIndex0]; MyMwcVector4Int edgeConversion1 = MyVoxelPrecalcConstants.EdgeConversion[edgeIndex1]; MyMwcVector4Int edgeConversion2 = MyVoxelPrecalcConstants.EdgeConversion[edgeIndex2]; MyEdgeVertex edgeVertex0 = m_edgeVertex[edge.X + edgeConversion0.X][edge.Y + edgeConversion0.Y][edge.Z + edgeConversion0.Z][edgeConversion0.W]; MyEdgeVertex edgeVertex1 = m_edgeVertex[edge.X + edgeConversion1.X][edge.Y + edgeConversion1.Y][edge.Z + edgeConversion1.Z][edgeConversion1.W]; MyEdgeVertex edgeVertex2 = m_edgeVertex[edge.X + edgeConversion2.X][edge.Y + edgeConversion2.Y][edge.Z + edgeConversion2.Z][edgeConversion2.W]; MyVoxelVertex compressedVertex0 = new MyVoxelVertex(); compressedVertex0.Position = edge0.Position; MyVoxelVertex compressedVertex1 = new MyVoxelVertex(); compressedVertex1.Position = edge1.Position; MyVoxelVertex compressedVertex2 = new MyVoxelVertex(); compressedVertex2.Position = edge2.Position; // We want to skip all wrong triangles, those that have two vertex at almost the same location, etc. // We do it simply, by calculating triangle normal and then checking if this normal has length large enough if (IsWrongTriangle(ref compressedVertex0, ref compressedVertex1, ref compressedVertex2) == true) { continue; } // Vertex at edge 0 if (edgeVertex0.CalcCounter != m_edgeVertexCalcCounter) { // If vertex at edge0 wasn't calculated for this cell during this precalc, we need to add it // Short overflow check System.Diagnostics.Debug.Assert(m_resultVerticesCounter <= short.MaxValue); edgeVertex0.CalcCounter = m_edgeVertexCalcCounter; edgeVertex0.VertexIndex = m_resultVerticesCounter; m_resultVertices[m_resultVerticesCounter].Position = edge0.Position; m_resultVertices[m_resultVerticesCounter].Normal = edge0.Normal; m_resultVertices[m_resultVerticesCounter].Ambient = edge0.Ambient; m_resultVertices[m_resultVerticesCounter].Material = edge0.Material; //m_resultVertices[m_resultVerticesCounter].OnRenderCellEdge = false; if (IsCoordOnRenderCellEdge(tempVoxelCoord0)) { //m_resultVertices[m_resultVerticesCounter].OnRenderCellEdge = true; } m_resultVerticesCounter++; } // Vertex at edge 1 if (edgeVertex1.CalcCounter != m_edgeVertexCalcCounter) { // If vertex at edge1 wasn't calculated for this cell during this precalc, we need to add it // Short overflow check System.Diagnostics.Debug.Assert(m_resultVerticesCounter <= short.MaxValue); edgeVertex1.CalcCounter = m_edgeVertexCalcCounter; edgeVertex1.VertexIndex = m_resultVerticesCounter; m_resultVertices[m_resultVerticesCounter].Position = edge1.Position; m_resultVertices[m_resultVerticesCounter].Normal = edge1.Normal; m_resultVertices[m_resultVerticesCounter].Ambient = edge1.Ambient; m_resultVertices[m_resultVerticesCounter].Material = edge1.Material; //m_resultVertices[m_resultVerticesCounter].OnRenderCellEdge = false; if (IsCoordOnRenderCellEdge(tempVoxelCoord0)) { //m_resultVertices[m_resultVerticesCounter].OnRenderCellEdge = true; } m_resultVerticesCounter++; } // Vertex at edge 2 if (edgeVertex2.CalcCounter != m_edgeVertexCalcCounter) { // If vertex at edge2 wasn't calculated for this cell during this precalc, we need to add it // Short overflow check System.Diagnostics.Debug.Assert(m_resultVerticesCounter <= short.MaxValue); edgeVertex2.CalcCounter = m_edgeVertexCalcCounter; edgeVertex2.VertexIndex = m_resultVerticesCounter; m_resultVertices[m_resultVerticesCounter].Position = edge2.Position; m_resultVertices[m_resultVerticesCounter].Normal = edge2.Normal; m_resultVertices[m_resultVerticesCounter].Ambient = edge2.Ambient; m_resultVertices[m_resultVerticesCounter].Material = edge2.Material; //m_resultVertices[m_resultVerticesCounter].OnRenderCellEdge = false; if (IsCoordOnRenderCellEdge(tempVoxelCoord0)) { // m_resultVertices[m_resultVerticesCounter].OnRenderCellEdge = true; } m_resultVerticesCounter++; } // Triangle m_resultTriangles[m_resultTrianglesCounter].VertexIndex0 = edgeVertex0.VertexIndex; m_resultTriangles[m_resultTrianglesCounter].VertexIndex1 = edgeVertex1.VertexIndex; m_resultTriangles[m_resultTrianglesCounter].VertexIndex2 = edgeVertex2.VertexIndex; Debug.Assert(edgeVertex0.VertexIndex < m_resultVerticesCounter); Debug.Assert(edgeVertex1.VertexIndex < m_resultVerticesCounter); Debug.Assert(edgeVertex2.VertexIndex < m_resultVerticesCounter); // Each voxel triangleVertexes has unique ID in whole game (but only on client side) //m_resultTriangles[m_resultTrianglesCounter].TriangleId = m_triangleIdCounter++; m_resultTrianglesCounter++; } } } } } // Cache the vertices and triangles and precalculate the octree task.Cache.PrepareCache(m_resultVertices, m_resultVerticesCounter, m_resultTriangles, m_resultTrianglesCounter); } finally { //m_voxelMap.Lock.ReleaseWriterLock(); } }