static void SaveVoxel(MyVoxelMap voxelMap) { Debug.Assert(voxelMap.EntityId != null); using (var voxelStream = new FileStream(GetVoxelPath(voxelMap), FileMode.Create)) using (var voxelWriter = new BinaryWriter(voxelStream)) { voxelWriter.Write(MyMwcFinalBuildConstants.VOXEL_CACHE_FILE_VERSION); MyMwcVector3Int cellCoord; for (cellCoord.X = 0; cellCoord.X < voxelMap.DataCellsCount.X; cellCoord.X++) { for (cellCoord.Y = 0; cellCoord.Y < voxelMap.DataCellsCount.Y; cellCoord.Y++) { for (cellCoord.Z = 0; cellCoord.Z < voxelMap.DataCellsCount.Z; cellCoord.Z++) { var dataCell = MyVoxelCacheData.GetCell(voxelMap, ref cellCoord, false); if (dataCell != null/* && dataCell.VoxelTrianglesCount > 0*/) { voxelWriter.Write(cellCoord.X); voxelWriter.Write(cellCoord.Y); voxelWriter.Write(cellCoord.Z); dataCell.Write(voxelWriter); //Log("update", sectorIdentifier, checkpointName, sector.Version); } } } } } }
public MyVoxelPrecalcTaskItem(MyLodTypeEnum type, MyVoxelMap voxelMap, MyVoxelCacheCellData cache, MyMwcVector3Int voxelStart) { Type = type; VoxelMap = voxelMap; Cache = cache; VoxelStart = voxelStart; }
public static Dictionary<MyMwcVoxelMaterialsEnum, int> CutOutSphereFastWithMaterials(MyVoxelMap voxelMap, BoundingSphere sphere, float removeRatio = 1) { var exactCutOutMaterials = new Dictionary<MyMwcVoxelMaterialsEnum, int>(); MyMwcVoxelMaterialsEnum? voxelMaterial_unused; float voxelContentRemovedInPercent_unused; MyVoxelGenerator.CutOutSphereFast(voxelMap, sphere, out voxelContentRemovedInPercent_unused, out voxelMaterial_unused, false, removeRatio, exactCutOutMaterials); return exactCutOutMaterials; }
public MyEditorActionVoxelHand(MyVoxelMap voxelMap, MyVoxelHandShape voxelHandShape) : base(voxelMap) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("MyEditorActionVoxelHand::ctor"); m_voxelHandShape = voxelHandShape; m_voxelShapes = voxelMap.GetVoxelHandShapes(); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); }
static string GetVoxelPath(MyVoxelMap voxelMap) { var sectorIdentifier = MyGuiScreenGamePlay.Static.GetSectorIdentifier(); int sectorVersion = MyGuiScreenGamePlay.Static.SectorVersion; string path = MyLocalCache.CachePath; if (sectorIdentifier.UserId != null) // TODO change? { path = MyLocalCache.CurrentSavePath; } if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } return Path.Combine(path, GetVoxelName(voxelMap, sectorIdentifier, sectorVersion) + ".mwv"); }
public MyVoxelMapOreDepositCell(MyVoxelMap voxelMap, MyMwcVector3Int coord) { m_voxelMap = voxelMap; m_coord = coord; m_positionIsDirty = true; m_totalSumOfOreContent = 0; m_oreWithContent = new List<MyMwcVoxelMaterialsEnum>(MyVoxelMapOreMaterials.RareOreCount()); /* int allMaterialsCount = MyMwcUtils.GetMaxValueFromEnum<MyMwcVoxelMaterialsEnum>() + 1; m_allMaterialsContent = new int[allMaterialsCount]; m_allMaterialsPositions = new Vector3?[allMaterialsCount]; m_helpersMaxContentForMaterial = new byte[allMaterialsCount]; */ m_allMaterialsContent = new Dictionary<int, int>(); m_allMaterialsPositions = new Dictionary<int, Vector3?>(); m_helpersMaxContentForMaterial = new Dictionary<int, byte>(); }
static string GetVoxelName(MyVoxelMap voxelMap, MyMwcSectorIdentifier sectorIdentifier, int sectorVersion) { string name; switch (sectorIdentifier.SectorType) { case MyMwcSectorTypeEnum.STORY: name = "STORY"; break; case MyMwcSectorTypeEnum.SANDBOX: name = "SANDBOX"; break; default: throw new MyMwcExceptionApplicationShouldNotGetHere(); } string userId = sectorIdentifier.UserId.HasValue ? sectorIdentifier.UserId.Value.ToString(CultureInfo.InvariantCulture) : "NULL"; Debug.Assert(voxelMap.EntityId != null, "voxelMap.EntityId != null"); return String.Format("{0}_{1}_{2}_{3}_{4}_{5}_{6}_{7}", name, userId, sectorIdentifier.Position.X, sectorIdentifier.Position.Y, sectorIdentifier.Position.Z, sectorVersion, voxelMap.VoxelMapId, voxelMap.EntityId.Value.NumericValue); }
// Because this class is reused in buffers, it isn't really initialized by constructor. We make real initialization here. public void Start(MyVoxelMap voxelMap, ref MyMwcVector3Int renderCellCoord, MyDecalTexturesEnum decalTexture, ref BoundingBox renderCellBoundingBox) { VoxelMap = voxelMap; RenderCellCoord = renderCellCoord; DecalTexture = decalTexture; m_status = MyDecalsBufferState.READY; m_fadingOutStartTime = 0; RenderCellBoundingBox = renderCellBoundingBox; if (MyDecals.IsLargeTexture(decalTexture) == true) { m_capacityAfterStart = MyDecalsConstants.MAX_DECAL_TRIANGLES_IN_BUFFER_LARGE; m_fadingOutStartLimit = (int)(m_capacityAfterStart * MyDecalsConstants.TEXTURE_LARGE_FADING_OUT_START_LIMIT_PERCENT); m_fadingOutMinimalTriangleCount = (int)(m_capacityAfterStart * MyDecalsConstants.TEXTURE_LARGE_FADING_OUT_MINIMAL_TRIANGLE_COUNT_PERCENT); MaxNeighbourTriangles = MyDecalsConstants.TEXTURE_LARGE_MAX_NEIGHBOUR_TRIANGLES; } else { m_capacityAfterStart = MyDecalsConstants.MAX_DECAL_TRIANGLES_IN_BUFFER_SMALL; m_fadingOutStartLimit = (int)(m_capacityAfterStart * MyDecalsConstants.TEXTURE_SMALL_FADING_OUT_START_LIMIT_PERCENT); m_fadingOutMinimalTriangleCount = (int)(m_capacityAfterStart * MyDecalsConstants.TEXTURE_SMALL_FADING_OUT_MINIMAL_TRIANGLE_COUNT_PERCENT); MaxNeighbourTriangles = MyDecalsConstants.TEXTURE_SMALL_MAX_NEIGHBOUR_TRIANGLES; } }
Vector3 GetGridCoord(MyVoxelMap voxelMap, int gridPointX, int gridPointY, int gridPointZ) { return voxelMap.PositionLeftBottomCorner + new Vector3( gridPointX * m_gridPointsSize + m_gridPointsSizeHalf, gridPointY * m_gridPointsSize + m_gridPointsSizeHalf, gridPointZ * m_gridPointsSize + m_gridPointsSizeHalf); }
bool PerformSoftenVoxels(MyVoxelMap voxelMap, MyMwcVector3Int voxelCoord, ref bool changed) { bool contentChanged = false; byte originalContent = voxelMap.GetVoxelContent(ref voxelCoord); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { changed = true; voxelMap.SoftenVoxelContent(voxelCoord, MyVoxelConstants.DEFAULT_SOFTEN_WEIGHT); contentChanged = true; } return contentChanged; }
bool PerformRemoveVoxels(MyVoxelMap voxelMap, MyMwcVector3Int voxelCoord, byte content, ref bool changed) { bool contentChanged = false; byte originalContent = voxelMap.GetVoxelContent(ref voxelCoord); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY && content > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { int newVal = originalContent - content; if (newVal < MyVoxelConstants.VOXEL_CONTENT_EMPTY) { newVal = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } changed = true; voxelMap.SetVoxelContent((byte)newVal, ref voxelCoord); contentChanged = true; } return contentChanged; }
bool PerformGridAction(MyVoxelMap voxelMap, MyvoxelImportAction action, int gridX, int gridZ, ref MyMwcVector3Int minChanged, ref MyMwcVector3Int maxChanged, MyMwcVoxelMaterialsEnum? voxelMaterial, ref bool changed) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("PerformGridAction"); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("get content sum"); int[, ,] voxelContentSum = GetVoxelContentSum(voxelMap, gridX, gridZ); if (voxelContentSum == null) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); return false; } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartNextBlock("loop"); bool anyContentChanged = false; // Transform grid values to voxels int voxelStartX = gridX * VOXELS_IN_GRID_IN_ONE_DIRECTION; int voxelStartZ = gridZ * VOXELS_IN_GRID_IN_ONE_DIRECTION; switch (action) { case MyvoxelImportAction.AddVoxels: MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("MyvoxelImportAction.AddVoxels"); for (int x = 0; x < VOXELS_IN_GRID_IN_ONE_DIRECTION; x++) for (int y = 0; y < voxelMap.Size.Y; y++) for (int z = 0; z < VOXELS_IN_GRID_IN_ONE_DIRECTION; z++) { MyMwcVector3Int voxelCoord = new MyMwcVector3Int(voxelStartX + x, y, voxelStartZ + z); byte newContent = (byte)(voxelContentSum[x, y, z] * MyVoxelConstants.VOXEL_CONTENT_FULL / GRID_POINTS_IN_ONE_VOXEL_TOTAL); if (newContent == 0) continue; bool c = PerformAddVoxels(voxelMap, voxelCoord, newContent, ref changed); c |= PerformChangeMaterialVoxels(voxelMap, voxelCoord, voxelMaterial, ref changed); if (c) { anyContentChanged = true; if (voxelCoord.X < minChanged.X) minChanged.X = voxelCoord.X; if (voxelCoord.Y < minChanged.Y) minChanged.Y = voxelCoord.Y; if (voxelCoord.Z < minChanged.Z) minChanged.Z = voxelCoord.Z; if (voxelCoord.X > maxChanged.X) maxChanged.X = voxelCoord.X; if (voxelCoord.Y > maxChanged.Y) maxChanged.Y = voxelCoord.Y; if (voxelCoord.Z > maxChanged.Z) maxChanged.Z = voxelCoord.Z; } } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); break; case MyvoxelImportAction.RemoveVoxels: for (int x = 0; x < VOXELS_IN_GRID_IN_ONE_DIRECTION; x++) for (int y = 0; y < voxelMap.Size.Y; y++) for (int z = 0; z < VOXELS_IN_GRID_IN_ONE_DIRECTION; z++) { MyMwcVector3Int voxelCoord = new MyMwcVector3Int(voxelStartX + x, y, voxelStartZ + z); byte newContent = (byte)(voxelContentSum[x, y, z] * MyVoxelConstants.VOXEL_CONTENT_FULL / GRID_POINTS_IN_ONE_VOXEL_TOTAL); if (newContent == 0) continue; if (PerformRemoveVoxels(voxelMap, voxelCoord, newContent, ref changed)) { anyContentChanged = true; if (voxelCoord.X < minChanged.X) minChanged.X = voxelCoord.X; if (voxelCoord.Y < minChanged.Y) minChanged.Y = voxelCoord.Y; if (voxelCoord.Z < minChanged.Z) minChanged.Z = voxelCoord.Z; if (voxelCoord.X > maxChanged.X) maxChanged.X = voxelCoord.X; if (voxelCoord.Y > maxChanged.Y) maxChanged.Y = voxelCoord.Y; if (voxelCoord.Z > maxChanged.Z) maxChanged.Z = voxelCoord.Z; } } break; case MyvoxelImportAction.ChangeMaterial: for (int x = 0; x < VOXELS_IN_GRID_IN_ONE_DIRECTION; x++) for (int y = 0; y < voxelMap.Size.Y; y++) for (int z = 0; z < VOXELS_IN_GRID_IN_ONE_DIRECTION; z++) { MyMwcVector3Int voxelCoord = new MyMwcVector3Int(voxelStartX + x, y, voxelStartZ + z); byte newContent = (byte)(voxelContentSum[x, y, z] * MyVoxelConstants.VOXEL_CONTENT_FULL / GRID_POINTS_IN_ONE_VOXEL_TOTAL); if (newContent == 0) continue; if (PerformChangeMaterialVoxels(voxelMap, voxelCoord, voxelMaterial, ref changed)) { anyContentChanged = true; if (voxelCoord.X < minChanged.X) minChanged.X = voxelCoord.X; if (voxelCoord.Y < minChanged.Y) minChanged.Y = voxelCoord.Y; if (voxelCoord.Z < minChanged.Z) minChanged.Z = voxelCoord.Z; if (voxelCoord.X > maxChanged.X) maxChanged.X = voxelCoord.X; if (voxelCoord.Y > maxChanged.Y) maxChanged.Y = voxelCoord.Y; if (voxelCoord.Z > maxChanged.Z) maxChanged.Z = voxelCoord.Z; } } break; case MyvoxelImportAction.SoftenVoxels: for (int x = 0; x < VOXELS_IN_GRID_IN_ONE_DIRECTION; x++) for (int y = 0; y < voxelMap.Size.Y; y++) for (int z = 0; z < VOXELS_IN_GRID_IN_ONE_DIRECTION; z++) { MyMwcVector3Int voxelCoord = new MyMwcVector3Int(voxelStartX + x, y, voxelStartZ + z); byte newContent = (byte)(voxelContentSum[x, y, z] * MyVoxelConstants.VOXEL_CONTENT_FULL / GRID_POINTS_IN_ONE_VOXEL_TOTAL); if (newContent == 0) continue; if (PerformSoftenVoxels(voxelMap, voxelCoord, ref changed)) { anyContentChanged = true; if (voxelCoord.X < minChanged.X) minChanged.X = voxelCoord.X; if (voxelCoord.Y < minChanged.Y) minChanged.Y = voxelCoord.Y; if (voxelCoord.Z < minChanged.Z) minChanged.Z = voxelCoord.Z; if (voxelCoord.X > maxChanged.X) maxChanged.X = voxelCoord.X; if (voxelCoord.Y > maxChanged.Y) maxChanged.Y = voxelCoord.Y; if (voxelCoord.Z > maxChanged.Z) maxChanged.Z = voxelCoord.Z; } } break; case MyvoxelImportAction.WrinkleVoxels: for (int x = 0; x < VOXELS_IN_GRID_IN_ONE_DIRECTION; x++) for (int y = 0; y < voxelMap.Size.Y; y++) for (int z = 0; z < VOXELS_IN_GRID_IN_ONE_DIRECTION; z++) { MyMwcVector3Int voxelCoord = new MyMwcVector3Int(voxelStartX + x, y, voxelStartZ + z); byte newContent = (byte)(voxelContentSum[x, y, z] * MyVoxelConstants.VOXEL_CONTENT_FULL / GRID_POINTS_IN_ONE_VOXEL_TOTAL); if (newContent == 0) continue; if (PerformWrinkleVoxels(voxelMap, voxelCoord, ref changed)) { anyContentChanged = true; if (voxelCoord.X < minChanged.X) minChanged.X = voxelCoord.X; if (voxelCoord.Y < minChanged.Y) minChanged.Y = voxelCoord.Y; if (voxelCoord.Z < minChanged.Z) minChanged.Z = voxelCoord.Z; if (voxelCoord.X > maxChanged.X) maxChanged.X = voxelCoord.X; if (voxelCoord.Y > maxChanged.Y) maxChanged.Y = voxelCoord.Y; if (voxelCoord.Z > maxChanged.Z) maxChanged.Z = voxelCoord.Z; } } break; } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); return anyContentChanged; }
// Import one individual grid void ImportGrid(MyVoxelMap voxelMap, int gridX, int gridZ) { int[, ,] voxelContentSum = GetVoxelContentSum(voxelMap, gridX, gridZ); // Transform grid values to voxels int voxelStartX = gridX * VOXELS_IN_GRID_IN_ONE_DIRECTION; int voxelStartZ = gridZ * VOXELS_IN_GRID_IN_ONE_DIRECTION; for (int x = 0; x < VOXELS_IN_GRID_IN_ONE_DIRECTION; x++) { for (int y = 0; y < voxelMap.Size.Y; y++) { for (int z = 0; z < VOXELS_IN_GRID_IN_ONE_DIRECTION; z++) { MyMwcVector3Int voxelCoord = new MyMwcVector3Int(voxelStartX + x, y, voxelStartZ + z); float content = 0; if (voxelContentSum != null) content = (float)voxelContentSum[x, y, z] / (float)GRID_POINTS_IN_ONE_VOXEL_TOTAL; // Content value must be in interval <0..1> MyCommonDebugUtils.AssertRelease((content >= 0.0f) && (content <= 1.0f)); voxelMap.SetVoxelContent((byte)(content * MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT), ref voxelCoord); } } } }
// We splited voxel map to more grids because if voxel map is large, it can't fit in one grid. // So here we iterate over this grid. Everytime clear the grid, fill with triangleVertexes intersections and then set voxels. void Import(MyVoxelMap voxelMap) { // Voxel map size must be multiple of grid size. Or, whole grid must fit exactly into X times into voxel map, without crossing border! MyCommonDebugUtils.AssertRelease((voxelMap.Size.X % VOXELS_IN_GRID_IN_ONE_DIRECTION) == 0); // Voxel map size must be multiple of grid size. Or, whole grid must fit exactly into X times into voxel map, without crossing border! MyCommonDebugUtils.AssertRelease((voxelMap.Size.Z % VOXELS_IN_GRID_IN_ONE_DIRECTION) == 0); int gridsCountX = voxelMap.Size.X / VOXELS_IN_GRID_IN_ONE_DIRECTION; int gridsCountZ = voxelMap.Size.Z / VOXELS_IN_GRID_IN_ONE_DIRECTION; // Space between two grid points in metres m_gridPointsSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES / (float)GRID_POINTS_IN_ONE_VOXEL_IN_ONE_DIRECTION; m_gridPointsSizeHalf = m_gridPointsSize / 2.0f; for (int gridX = 0; gridX < gridsCountX; gridX++) { for (int gridZ = 0; gridZ < gridsCountZ; gridZ++) { ImportGrid(voxelMap, gridX, gridZ); } } }
// Use this static method do one-time import of a voxel map public static void Run(MyVoxelMap voxelMap, string modelName, MyVoxelImportOptions importOptions) { MyVoxelImport voxelMapImport = new MyVoxelImport(voxelMap, modelName, importOptions); }
// Rescales the model to size specified by 'sizeInMetres' void RescaleModel(MyVoxelMap voxelMap, MyVoxelImportOptions importOptions) { Vector3 originalSize = m_maxCoord - m_minCoord; Vector3 originalCenter = (m_maxCoord + m_minCoord) / 2.0f; m_minCoord = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); m_maxCoord = new Vector3(float.MinValue, float.MinValue, float.MinValue); // We don't want to touch borders of a voxel map so we need to subtract size of data cell from each side. // I have choosen data cell (not one or two voxels) because LOD - average content of some data cells that were too close to voxel map border // were almost full data cell so when converted as LOD, hole appear there (originaly I was just multiplying by 0.9, but that is wasting in case of large voxel maps). //Vector3 rescaleFactor = voxelMap.SizeInMetres / originalSize * 0.9f; Vector3 rescaleFactor; rescaleFactor.X = (voxelMap.SizeInMetres.X - 2 * MyVoxelConstants.VOXEL_DATA_CELL_SIZE_IN_METRES) / originalSize.X; rescaleFactor.Y = (voxelMap.SizeInMetres.Y - 2 * MyVoxelConstants.VOXEL_DATA_CELL_SIZE_IN_METRES) / originalSize.Y; rescaleFactor.Z = (voxelMap.SizeInMetres.Z - 2 * MyVoxelConstants.VOXEL_DATA_CELL_SIZE_IN_METRES) / originalSize.Z; switch (importOptions) { case MyVoxelImportOptions.KeepAspectRatio: rescaleFactor.X = rescaleFactor.Y = rescaleFactor.Z = Math.Min(Math.Min(rescaleFactor.X, rescaleFactor.Y), rescaleFactor.Z); break; case MyVoxelImportOptions.KeepScale: //Cannot keep scale if the voxel map isn't big enough to contain it, will keep aspect ratio instead if (rescaleFactor.X >= 1 && rescaleFactor.Y >= 1 && rescaleFactor.Z >= 1) { rescaleFactor = Vector3.One; } else { rescaleFactor.X = rescaleFactor.Y = rescaleFactor.Z = Math.Min(Math.Min(rescaleFactor.X, rescaleFactor.Y), rescaleFactor.Z); } break; } for (int i = 0; i < m_triangles.Count; i++) { // Translate vertexes to the origin m_triangles[i].Vertex0 -= originalCenter; m_triangles[i].Vertex1 -= originalCenter; m_triangles[i].Vertex2 -= originalCenter; // Rescale vertexes m_triangles[i].Vertex0 *= rescaleFactor; m_triangles[i].Vertex1 *= rescaleFactor; m_triangles[i].Vertex2 *= rescaleFactor; // Translate vertexes to voxel map position m_triangles[i].Vertex0 += voxelMap.PositionLeftBottomCorner + voxelMap.SizeInMetresHalf; m_triangles[i].Vertex1 += voxelMap.PositionLeftBottomCorner + voxelMap.SizeInMetresHalf; m_triangles[i].Vertex2 += voxelMap.PositionLeftBottomCorner + voxelMap.SizeInMetresHalf; CheckMinMaxCoords(m_triangles[i].Vertex0); CheckMinMaxCoords(m_triangles[i].Vertex1); CheckMinMaxCoords(m_triangles[i].Vertex2); } }
// Fill lookup array with triangles located at specified voxel positions. Array is 2D. void FillTrianglesLookup(MyVoxelMap voxelMap) { m_trianglesLookupSizeX = voxelMap.Size.X; m_trianglesLookupSizeZ = voxelMap.Size.Z; m_trianglesLookupElementSizeX = voxelMap.SizeInMetres.X / voxelMap.Size.X; m_trianglesLookupElementSizeZ = voxelMap.SizeInMetres.Z / voxelMap.Size.Z; m_trianglesLookup = new List<MyImportTriangle>[m_trianglesLookupSizeX, m_trianglesLookupSizeZ]; // Initialize array for (int x = 0; x < m_trianglesLookupSizeX; x++) { for (int z = 0; z < m_trianglesLookupSizeZ; z++) { m_trianglesLookup[x, z] = new List<MyImportTriangle>(INITIAL_COUNT_OF_TRIANGLES_IN_GRID_POSITION); } } // Iterate over all triangles and put them into correct array positions based on their coordinates for (int i = 0; i < m_triangles.Count; i++) { // Get bounding rectangle for this triangleVertexes (in fact we need only 2D coordinates, but it's clearer to use 3D and ignore Y value) Vector3 minCoord = new Vector3(float.MaxValue, 0, float.MaxValue); Vector3 maxCoord = new Vector3(float.MinValue, 0, float.MinValue); CheckMinMaxCoords2d(ref minCoord, ref maxCoord, m_triangles[i].Vertex0); CheckMinMaxCoords2d(ref minCoord, ref maxCoord, m_triangles[i].Vertex1); CheckMinMaxCoords2d(ref minCoord, ref maxCoord, m_triangles[i].Vertex2); MyMwcVector2Int minCoordInt = GetTriangleLookupCoord(voxelMap, minCoord); MyMwcVector2Int maxCoordInt = GetTriangleLookupCoord(voxelMap, maxCoord); if (minCoordInt.X < 0) minCoordInt.X = 0; if (minCoordInt.Y < 0) minCoordInt.Y = 0; if (minCoordInt.X > m_trianglesLookupSizeX - 1) minCoordInt.X = m_trianglesLookupSizeX - 1; if (minCoordInt.Y > m_trianglesLookupSizeZ - 1) minCoordInt.Y = m_trianglesLookupSizeZ - 1; if (maxCoordInt.X < 0) maxCoordInt.X = 0; if (maxCoordInt.Y < 0) maxCoordInt.Y = 0; if (maxCoordInt.X > m_trianglesLookupSizeX - 1) maxCoordInt.X = m_trianglesLookupSizeX - 1; if (maxCoordInt.Y > m_trianglesLookupSizeZ - 1) maxCoordInt.Y = m_trianglesLookupSizeZ - 1; // Iterate over all elements that may contain this triangleVertexes. // Notice that we swap Y and Z. It's because MyMwcVector2Int has X and Y, but we are working on XZ plane. So it's still Z value, even if its name is Y. for (int x = minCoordInt.X; x <= maxCoordInt.X; x++) { for (int z = minCoordInt.Y; z <= maxCoordInt.Y; z++) { m_trianglesLookup[x, z].Add(m_triangles[i]); } } } }
// Use this static method do one-time import of a voxel map public static void Run(MyVoxelMap voxelMap, MyModel model) { MyVoxelImport voxelMapImport = new MyVoxelImport(voxelMap, model, MyVoxelImportOptions.None); }
// Returns temporary in/out values for voxels int[, ,] GetVoxelContentSum(MyVoxelMap voxelMap, int gridX, int gridZ) { int gridStartPointX = gridX * MAX_GRID_SIZE_IN_ONE_DIRECTION; int gridStartPointZ = gridZ * MAX_GRID_SIZE_IN_ONE_DIRECTION; // Here we store intersections with line and triangles and specified grid point List<MyImportIntersection> intersections = new List<MyImportIntersection>(INITIAL_COUNT_OF_INTERSECTIONS); // Here we store temporary in/out values for voxels. After that, we convert it to common voxel content values (0..255) int[, ,] voxelContentSum = null; for (int gridPointX = 0; gridPointX < MAX_GRID_SIZE_IN_ONE_DIRECTION; gridPointX++) { for (int gridPointZ = 0; gridPointZ < MAX_GRID_SIZE_IN_ONE_DIRECTION; gridPointZ++) { Vector3 gridCoord = GetGridCoord(voxelMap, gridStartPointX + gridPointX, 0, gridStartPointZ + gridPointZ); if (gridCoord.X < m_minCoord.X || gridCoord.Z < m_minCoord.Z || gridCoord.X > m_maxCoord.X || gridCoord.Z > m_maxCoord.Z) { continue; } if (voxelContentSum == null) voxelContentSum = new int[VOXELS_IN_GRID_IN_ONE_DIRECTION, voxelMap.Size.Y, VOXELS_IN_GRID_IN_ONE_DIRECTION]; MyMwcVector2Int triangleLookupCoord = GetTriangleLookupCoord(voxelMap, gridCoord); // We need to clear list of intersections intersections.Clear(); // Get triangles that lie on this grid point/line List<MyImportTriangle> triangles = m_trianglesLookup[triangleLookupCoord.X, triangleLookupCoord.Y]; for (int i = 0; i < triangles.Count; i++) { // Ray is always in Y-axis direction //MyLine line = new MyLine(gridCoord, gridCoord + Vector3.Up * 100000, false); MyLine line = new MyLine(new Vector3(gridCoord.X, m_minCoord.Y, gridCoord.Z) + Vector3.Down * 10, new Vector3(gridCoord.X, m_maxCoord.Y, gridCoord.Z) + Vector3.Up * 10, false); MyTriangle_Vertexes triangle; triangle.Vertex0 = triangles[i].Vertex0; triangle.Vertex1 = triangles[i].Vertex1; triangle.Vertex2 = triangles[i].Vertex2; float? distance = MyUtils.GetLineTriangleIntersection(ref line, ref triangle); if (distance.HasValue == true) { intersections.Add(new MyImportIntersection(line.From + line.Direction * distance.Value, triangles[i].Normal, distance.Value)); } } // SortForSAP intersections by their distance from the origin (from the grid point) intersections.Sort(delegate(MyImportIntersection p1, MyImportIntersection p2) { return p1.Distance.CompareTo(p2.Distance); }); int lastY = 0; bool contentSwitch = false; // This tells us if we will add empty or full voxels. False = until now it's empty. True = it full. for (int i = 0; i < intersections.Count; i++) { Vector3 tempGridCoord = GetGridCoord(voxelMap, gridStartPointX + gridPointX, lastY, gridStartPointZ + gridPointZ); int length = (int)((intersections[i].Intersection.Y - tempGridCoord.Y) / m_gridPointsSize); // this is here, because we must find intersection with triangle out of borders of voxel map, because we can use voxel hand at the borders if (length < 0) { contentSwitch = !contentSwitch; continue; } for (int y = lastY; y < (lastY + length); y++) { MyMwcVector3Int voxelCoord = voxelMap.GetVoxelCoordinateFromMeters(GetGridCoord(voxelMap, gridPointX, y, gridPointZ)); if (voxelCoord.Y < voxelContentSum.GetLength(1) && voxelCoord.Y >= 0) { voxelContentSum[voxelCoord.X, voxelCoord.Y, voxelCoord.Z] += (contentSwitch == false) ? 0 : 1; } } contentSwitch = !contentSwitch; lastY = lastY + length; } } } return voxelContentSum; }
// Use this static method do one-time import of a voxel map public static void Run(MyVoxelMap voxelMap, MyModelObj model, MyVoxelImportOptions importOptions) { MyVoxelImport voxelMapImport = new MyVoxelImport(voxelMap, model, importOptions); }
void PerformAction(MyVoxelMap voxelMap, MyvoxelImportAction action, MyMwcVoxelMaterialsEnum? voxelMaterial, ref bool changed) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("PerformAction"); // Voxel map size must be multiple of grid size. Or, whole grid must fit exactly into X times into voxel map, without crossing border! MyCommonDebugUtils.AssertRelease((voxelMap.Size.X % VOXELS_IN_GRID_IN_ONE_DIRECTION) == 0); // Voxel map size must be multiple of grid size. Or, whole grid must fit exactly into X times into voxel map, without crossing border! MyCommonDebugUtils.AssertRelease((voxelMap.Size.Z % VOXELS_IN_GRID_IN_ONE_DIRECTION) == 0); int gridsCountX = voxelMap.Size.X / VOXELS_IN_GRID_IN_ONE_DIRECTION; int gridsCountZ = voxelMap.Size.Z / VOXELS_IN_GRID_IN_ONE_DIRECTION; // Space between two grid points in metres m_gridPointsSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES / (float)GRID_POINTS_IN_ONE_VOXEL_IN_ONE_DIRECTION; m_gridPointsSizeHalf = m_gridPointsSize / 2.0f; // Get min corner of the box MyMwcVector3Int minCorner = voxelMap.GetVoxelCoordinateFromMeters(m_minCoord); // Get max corner of the box MyMwcVector3Int maxCorner = voxelMap.GetVoxelCoordinateFromMeters(m_maxCoord); voxelMap.FixVoxelCoord(ref minCorner); voxelMap.FixVoxelCoord(ref maxCorner); // We are tracking which voxels were changed, so we can invalidate only needed cells in the cache MyMwcVector3Int minChanged = maxCorner; MyMwcVector3Int maxChanged = minCorner; bool contentChanged = false; for (int gridX = 0; gridX < gridsCountX; gridX++) { for (int gridZ = 0; gridZ < gridsCountZ; gridZ++) { if (PerformGridAction(voxelMap, action, gridX, gridZ, ref minChanged, ref maxChanged, voxelMaterial, ref changed)) { contentChanged = true; } } } if (contentChanged) { // Extend borders for cleaning, so it's one pixel on both sides minChanged.X -= 1; minChanged.Y -= 1; minChanged.Z -= 1; maxChanged.X += 1; maxChanged.Y += 1; maxChanged.Z += 1; voxelMap.FixVoxelCoord(ref minChanged); voxelMap.FixVoxelCoord(ref maxChanged); voxelMap.InvalidateCache(minChanged, maxChanged); } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); }
public static void Run(MyVoxelMap voxelMap, MyModel model, MyvoxelImportAction importAction, Matrix modelWorld, float modelScale, MyMwcVoxelMaterialsEnum? voxelMaterial, ref bool changed) { MyVoxelImport voxelImport = new MyVoxelImport(voxelMap, model, importAction, modelWorld, modelScale, voxelMaterial, ref changed); }
bool PerformAddVoxels(MyVoxelMap voxelMap, MyMwcVector3Int voxelCoord, byte content, ref bool changed) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("PerformAddVoxels"); bool contentChanged = false; byte originalContent = voxelMap.GetVoxelContent(ref voxelCoord); if (content > originalContent) { changed = true; voxelMap.SetVoxelContent(content, ref voxelCoord); contentChanged = true; } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); return contentChanged; }
public static void Run(MyVoxelMap voxelMap, Vector3[] vertexes, MyTriangleVertexIndices[] triangles, MyvoxelImportAction importAction, Matrix modelWorld, MyMwcVoxelMaterialsEnum? voxelMaterial, ref bool changed) { MyVoxelImport voxelImport = new MyVoxelImport(voxelMap, vertexes, triangles, importAction, modelWorld, voxelMaterial, ref changed); }
bool PerformChangeMaterialVoxels(MyVoxelMap voxelMap, MyMwcVector3Int voxelCoord, MyMwcVoxelMaterialsEnum? voxelMaterial, ref bool changed) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("PerformChangeMaterialVoxels"); if (voxelMaterial != null) { byte originalContent = voxelMap.GetVoxelContent(ref voxelCoord); if (originalContent == MyVoxelConstants.VOXEL_CONTENT_EMPTY) { // if there are no voxel content then do nothing MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); return false; } MyMwcVoxelMaterialsEnum originalMaterial; byte originalIndestructibleContent; voxelMap.GetMaterialAndIndestructibleContent(ref voxelCoord, out originalMaterial, out originalIndestructibleContent); if (originalMaterial == voxelMaterial.Value) { // if original material is same as new material then do nothing MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); return false; } byte indestructibleContent = MyVoxelConstants.VOXEL_CONTENT_EMPTY; voxelMap.SetVoxelMaterialAndIndestructibleContent(voxelMaterial.Value, indestructibleContent, ref voxelCoord); changed = true; MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); return true; } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); return false; }
// Model will be scaled/translated to fit voxel map size (X, Y and Z) MyVoxelImport(MyVoxelMap voxelMap, MyModelObj model, MyVoxelImportOptions importOptions) { // Load model, get triangles LoadModel(model); // Rescale the model so it fits voxelMap (three directions!!!) RescaleModel(voxelMap, importOptions); // Fill lookup array with triangles located at specified voxel positions. Array is 2D. FillTrianglesLookup(voxelMap); // Create XZ map where every voxel center gets list of triangles that lie on its Y line // Do this by iterating over all triangles and making references to them from XZ map Import(voxelMap); }
bool PerformWrinkleVoxels(MyVoxelMap voxelMap, MyMwcVector3Int voxelCoord, ref bool changed) { bool contentChanged = false; byte originalContent = voxelMap.GetVoxelContent(ref voxelCoord); voxelMap.WrinkleVoxelContent(voxelCoord, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_ADD, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_REMOVE); byte newContent = voxelMap.GetVoxelContent(ref voxelCoord); if (originalContent != newContent) { contentChanged = true; changed = true; } return contentChanged; }
MyVoxelImport(MyVoxelMap voxelMap, Vector3[] vertexes, MyTriangleVertexIndices[] triangles, MyvoxelImportAction importAction, Matrix modelWorld, MyMwcVoxelMaterialsEnum? voxelMaterial, ref bool changed) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("voxel import"); // Load model, get triangles transformed to model's world matrix MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("load model"); LoadModel(vertexes, triangles, modelWorld); // Fill lookup array with triangles located at specified voxel positions. Array is 2D. MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartNextBlock("fill lookup"); FillTrianglesLookup(voxelMap); // Performs action MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartNextBlock("perform action"); PerformAction(voxelMap, importAction, voxelMaterial, ref changed); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); }
// Converts vertex from 'world coordinates' to 'triangleVertexes lookup array coordinates'. MyMwcVector2Int GetTriangleLookupCoord(MyVoxelMap voxelMap, Vector3 vertex) { return new MyMwcVector2Int( (int)((vertex.X - voxelMap.PositionLeftBottomCorner.X) / m_trianglesLookupElementSizeX), (int)((vertex.Z - voxelMap.PositionLeftBottomCorner.Z) / m_trianglesLookupElementSizeZ)); }
MyVoxelImport(MyVoxelMap voxelMap, MyModel model, MyvoxelImportAction importAction, Matrix modelWorld, float modelScale, MyMwcVoxelMaterialsEnum? voxelMaterial, ref bool changed) { // Load model, get triangles transformed to model's world matrix LoadModel(model, modelWorld, modelScale); RescaleModel(voxelMap, MyVoxelImportOptions.KeepScale); // Fill lookup array with triangles located at specified voxel positions. Array is 2D. FillTrianglesLookup(voxelMap); // Performs action //PerformAction(voxelMap, importAction, voxelMaterial, ref changed); Import(voxelMap); }