public override void Draw() { base.Draw(); if (MySession.Static == null) { return; } if (m_showVoxelProbe) { float halfSize = m_probeSize * .5f; float lodSize = 1 << m_probeLod; if (m_moveProbe) { m_probePosition = MySector.MainCamera.Position + MySector.MainCamera.ForwardVector * m_probeSize * 3; } BoundingBox bb; BoundingBoxD bbp; // Box used for drawing and finding the probe and drawing bb = new BoundingBox(m_probePosition - halfSize, m_probePosition + halfSize); bbp = (BoundingBoxD)bb; m_voxels.Clear(); MyGamePruningStructure.GetAllVoxelMapsInBox(ref bbp, m_voxels); MyVoxelBase map = null; double distance = double.PositiveInfinity; foreach (var vox in m_voxels) { var d = Vector3D.Distance(vox.WorldMatrix.Translation, m_probePosition); if (d < distance) { distance = d; map = vox; } } ContainmentType cont = ContainmentType.Disjoint; if (map != null) { map = map.RootVoxel; Vector3 localPos = Vector3.Transform(m_probePosition, map.PositionComp.WorldMatrixInvScaled); localPos += map.SizeInMetresHalf; // Create similar bounding box in storage space bb = new BoundingBox(localPos - halfSize, localPos + halfSize); m_probedVoxel = map; Section("Probing {1}: {0}", map.StorageName, map.GetType().Name); Text("Probe mode: {0}", m_mode); if (m_mode == ProbeMode.Intersect) { Text("Local Pos: {0}", localPos); Text("Probe Size: {0}", m_probeSize); cont = map.Storage.Intersect(ref bb, false); Text("Result: {0}", cont.ToString()); bbp = (BoundingBoxD)bb; } else { Vector3I min = Vector3I.Floor(bb.Min / lodSize + .5f); Vector3I max = min + ((int)m_probeSize >> m_probeLod) - 1; bbp = new BoundingBoxD(min << m_probeLod, (max + 1) << m_probeLod); bbp.Translate(new Vector3D(-.5)); Text("Probe Size: {0}({1})", (max - min).X + 1, m_probeSize); Text("Probe LOD: {0}", m_probeLod); var requestData = (MyStorageDataTypeEnum)(int)m_mode; MyVoxelRequestFlags flags = MyVoxelRequestFlags.ContentChecked; m_target.Resize(max - min + 1); m_target.Clear(MyStorageDataTypeEnum.Content, 0); m_target.Clear(MyStorageDataTypeEnum.Material, 0); map.Storage.ReadRange(m_target, (MyStorageDataTypeFlags)(1 << (int)requestData), m_probeLod, ref min, ref max, ref flags); if (requestData == MyStorageDataTypeEnum.Content) { if (flags.HasFlag(MyVoxelRequestFlags.EmptyContent)) { cont = ContainmentType.Disjoint; } else if (flags.HasFlag(MyVoxelRequestFlags.FullContent)) { cont = ContainmentType.Contains; } else { int val = m_target.ValueWhenAllEqual(requestData); if (val == -1) { cont = ContainmentType.Intersects; } else if (val >= MyVoxelConstants.VOXEL_ISO_LEVEL) { cont = ContainmentType.Contains; } else { cont = ContainmentType.Disjoint; } } DrawContentsInfo(m_target); } else { cont = ContainmentType.Disjoint; DrawMaterialsInfo(m_target); } Text(Color.Yellow, 1.5f, "Voxel Editing:"); Text("Value to set (Ctrl+Mousewheel): {0}", m_valueToSet); if (m_probeLod != 0) { Text(Color.Red, "Writing to storage is only possible when probe is set to LOD 0"); } else { Text("Use primary mouse button to set."); Text("Position/Extents: {0}/{1}", bbp.Min, bbp.Extents); if (MyInput.Static.IsLeftMousePressed()) { if (requestData == MyStorageDataTypeEnum.Content) { m_target.BlockFillContent(Vector3I.Zero, m_target.Size3D - Vector3I.One, m_valueToSet); } else { m_target.BlockFillMaterial(Vector3I.Zero, m_target.Size3D - Vector3I.One, m_valueToSet); } map.Storage.WriteRange(m_target, (MyStorageDataTypeFlags)(1 << (int)requestData), ref min, ref max); } } } } else { Section("No Voxel Found"); Text("Probe mode: {0}", m_mode); Text("Probe Size: {0}", m_probeSize); } Color c = ColorForContainment(cont); if (map != null) { bbp = bbp.Translate(-map.SizeInMetresHalf); MyOrientedBoundingBoxD oobb = new MyOrientedBoundingBoxD(bbp, map.WorldMatrix); MyRenderProxy.DebugDrawOBB(oobb, c, 0.5f, true, false); } else { MyRenderProxy.DebugDrawAABB(bbp, c, 0.5f, 1.0f, true); } } }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck = false) { // change range so normal can be computed at edges (expand by 1 in all directions) voxelStart -= 1; voxelEnd += 1; if (storage == null) { return(null); } using (storage.Pin()) { if (storage.Closed) { return(null); } MyVoxelRequestFlags request = MyVoxelRequestFlags.ContentChecked; // | (doNotCheck ? MyVoxelRequestFlags.DoNotCheck : 0); //if (lod == 0 && generateMaterials) request |= MyVoxelRequestFlags.AdviseCache; bool readAmbient = false; if (generateMaterials && storage.DataProvider != null && storage.DataProvider.ProvidesAmbient) { readAmbient = true; } m_cache.Resize(voxelStart, voxelEnd); if (readAmbient) { m_cache.StoreOcclusion = true; } storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd, ref request); if (request.HasFlag(MyVoxelRequestFlags.EmptyContent) || request.HasFlag(MyVoxelRequestFlags.FullContent) || (!request.HasFlag(MyVoxelRequestFlags.ContentChecked) && !m_cache.ContainsIsoSurface())) { //if(generateMaterials && lod == 0) Debugger.Break(); //storage.DebugDrawChunk(voxelStart, voxelEnd); return(null); } var center = (storage.Size / 2) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); var vertexCellOffset = voxelStart - AffectedRangeOffset; double numCellsHalf = 0.5 * (m_cache.Size3D.X - 3); var posOffset = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize; if (generateMaterials) { // 255 is the new black m_cache.ClearMaterials(255); } if (readAmbient) { m_cache.Clear(MyStorageDataTypeEnum.Occlusion, 0); } IsoMesher mesher = new IsoMesher(); ProfilerShort.Begin("Dual Contouring"); unsafe { fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content]) fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material]) { var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); mesher.Calculate(size3d.X, content, material, m_buffer, useAmbient, posOffset - center); } } ProfilerShort.End(); if (generateMaterials) { request = 0; request |= MyVoxelRequestFlags.SurfaceMaterial; request |= MyVoxelRequestFlags.ConsiderContent; var req = readAmbient ? MyStorageDataTypeFlags.Material | MyStorageDataTypeFlags.Occlusion : MyStorageDataTypeFlags.Material; storage.ReadRange(m_cache, req, lod, ref voxelStart, ref voxelEnd, ref request); FixCacheMaterial(voxelStart, voxelEnd); unsafe { fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content]) fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material]) { int materialOverride = request.HasFlag(MyVoxelRequestFlags.OneMaterial) ? m_cache.Material(0) : -1; var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); if (readAmbient) fixed(byte *ambient = m_cache[MyStorageDataTypeEnum.Occlusion]) mesher.CalculateMaterials(size3d.X, content, material, ambient, materialOverride); else { mesher.CalculateMaterials(size3d.X, content, material, null, materialOverride); } } } } else { m_cache.ClearMaterials(0); } mesher.Finish(m_buffer); if (m_buffer.VerticesCount == 0 || m_buffer.Triangles.Count == 0) { return(null); } ProfilerShort.Begin("Geometry post-processing"); { var positions = m_buffer.Positions.GetInternalArray(); var vertexCells = m_buffer.Cells.GetInternalArray(); var materials = m_buffer.Materials.GetInternalArray(); for (int i = 0; i < m_buffer.VerticesCount; i++) { Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); vertexCells[i] += vertexCellOffset; Debug.Assert(vertexCells[i].IsInsideInclusive(voxelStart + 1, voxelEnd - 1)); Debug.Assert(materials[i] != MyVoxelConstants.NULL_MATERIAL); } m_buffer.PositionOffset = posOffset; m_buffer.PositionScale = new Vector3((float)(numCellsHalf * voxelSize)); m_buffer.CellStart = voxelStart + 1; m_buffer.CellEnd = voxelEnd - 1; } ProfilerShort.End(); // Replace filled mesh with new one. // This way prevents allocation of meshes which then end up empty. var buffer = m_buffer; m_buffer = new MyIsoMesh(); return(buffer); } }