public static void AddToQueue( MyLodTypeEnum type, MyVoxelMap voxelMap, MyVoxelCacheCellData cache, int voxelStartX, int voxelStartY, int voxelStartZ) { MyVoxelPrecalcTaskItem a = new MyVoxelPrecalcTaskItem(); a.Type = type; a.VoxelMap = voxelMap; a.Cache = cache; a.VoxelStart = new MyMwcVector3Int(voxelStartX, voxelStartY, voxelStartZ); // IMPORTANT: Don't need to lock Tasks, because at this point no other thread should access it. Tasks.Enqueue(a); }
//// 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(); } }
// Precalculate voxel cell into cache (makes triangles and vertex buffer from voxels) // Doesn't use threads, just main thread. Use when you don't want to precalculate many cells in parallel. public static void PrecalcImmediatelly(MyVoxelPrecalcTaskItem task) { m_singleCoreTask.Precalc(task); }