internal MyVoxelPhysicsBody(MyVoxelBase voxelMap, float phantomExtend, float predictionSize = 3.0f, bool lazyPhysics = false) : base(voxelMap, RigidBodyFlag.RBF_STATIC) { ProfilerShort.Begin("MyVoxelPhysicsBody("); InvalidCells = new HashSet<Vector3I>[2]; InvalidCells[0] = new HashSet<Vector3I>(); InvalidCells[1] = new HashSet<Vector3I>(); m_predictionSize = predictionSize; m_phantomExtend = phantomExtend; m_voxelMap = voxelMap; Vector3I storageSize = m_voxelMap.Size; Vector3I numCels = storageSize >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; m_cellsOffset = m_voxelMap.StorageMin >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; if (!MyFakes.ENABLE_LAZY_VOXEL_PHYSICS || !lazyPhysics || !ENABLE_AABB_PHANTOM) { CreateRigidBodies(); } ProfilerShort.End(); MaterialType = MyMaterialType.ROCK; }
internal MyVoxelPhysicsBody(MyVoxelBase voxelMap,float phantomExtend): base(voxelMap, RigidBodyFlag.RBF_STATIC) { m_phantomExtend = phantomExtend; m_voxelMap = voxelMap; Vector3I storageSize = m_voxelMap.Size; Vector3I numCels = storageSize >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; m_cellsOffset = m_voxelMap.StorageMin >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; HkUniformGridShape shape = new HkUniformGridShape( new HkUniformGridShapeArgs() { CellsCount = numCels, CellSize = MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_METRES, CellOffset = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF, CellExpand = MyVoxelConstants.VOXEL_SIZE_IN_METRES, }); shape.SetShapeRequestHandler(RequestShapeBlocking); CreateFromCollisionObject(shape, -m_voxelMap.SizeInMetresHalf, m_voxelMap.WorldMatrix, collisionFilter: MyPhysics.VoxelCollisionLayer); shape.Base.RemoveReference(); if (ENABLE_AABB_PHANTOM) { m_aabbPhantom = new Havok.HkpAabbPhantom(new BoundingBox(Vector3.Zero, m_voxelMap.SizeInMetres), 0); m_aabbPhantom.CollidableAdded = AabbPhantom_CollidableAdded; m_aabbPhantom.CollidableRemoved = AabbPhantom_CollidableRemoved; } if (MyFakes.ENABLE_PHYSICS_HIGH_FRICTION) Friction = 0.65f; MaterialType = Sandbox.Common.MyMaterialType.ROCK; }
public void RemoveVoxelMap(MyVoxelBase voxelMap) { if (m_voxelMapsByEntityId.Remove(voxelMap.EntityId)) { var render = voxelMap.Render; if (render is MyRenderComponentVoxelMap) { var clipMapId = (render as MyRenderComponentVoxelMap).ClipmapId; m_renderComponentsByClipmapId.Remove(clipMapId); } } }
// Blends-out triangles affected by explosion (radius + some safe delta). Triangles there have zero alpha are flaged to not-draw at all. public static void HideTrianglesAfterExplosion(MyVoxelBase voxelMap, ref BoundingSphereD explosionSphere) { VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("MyDecals::HideTrianglesAfterExplosion"); //MyMwcVector3Int renderCellCoord = voxelMap.GetVoxelRenderCellCoordinateFromMeters(ref explosionSphere.Center); //m_decalsForVoxels.HideTrianglesAfterExplosion(voxelMap.VoxelMapId, ref renderCellCoord, ref explosionSphere); foreach (uint id in voxelMap.Render.RenderObjectIDs) { VRageRender.MyRenderProxy.HideDecals(id, explosionSphere.Center, (float)explosionSphere.Radius); } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); }
public void Add(MyVoxelBase voxelMap) { if (!Exist(voxelMap)) { m_voxelMapsByEntityId.Add(voxelMap.EntityId, voxelMap); // On dedicated servers, ClipmapIDs are all 0, but it's fine since there is no rendering anyway. var render = voxelMap.Render; if (render is MyRenderComponentVoxelMap) { var clipMapId= (render as MyRenderComponentVoxelMap).ClipmapId; m_renderComponentsByClipmapId[clipMapId] = render as MyRenderComponentVoxelMap; } } }
public void Add(MatrixD worldMatrix, BoundingBox box, Vector4I id, MyVoxelBase voxel) { if (m_list.Count > 1900) m_list.ClearList(); voxel = voxel.RootVoxel; box.Translate(-voxel.SizeInMetresHalf); //box.Translate(voxel.StorageMin); m_list.Add(new PredictionInfo { Id = id, Bounds = MyOrientedBoundingBoxD.Create((BoundingBoxD)box, voxel.WorldMatrix), Body = voxel }); }
public MyVoxelNavigationMesh(MyVoxelBase voxelMap, MyNavmeshCoordinator coordinator, Func<long> timestampFunction) : base(coordinator.Links, 16, timestampFunction) { m_voxelMap = voxelMap; m_cellSize = m_voxelMap.SizeInMetres / m_voxelMap.Storage.Geometry.CellsCount * (1 << NAVMESH_LOD); m_processedCells = new MyVector3ISet(); m_markedForAddition = new MyVector3ISet(); m_toAdd = new MyBinaryStructHeap<float, Vector3I>(128); m_connectionHelper = new MyVoxelConnectionHelper(); m_navmeshCoordinator = coordinator; m_higherLevel = new MyHighLevelGroup(this, coordinator.HighLevelLinks, timestampFunction); m_higherLevelHelper = new MyVoxelHighLevelHelper(this); m_debugCellEdges = new Dictionary<ulong, List<DebugDrawEdge>>(); voxelMap.Storage.RangeChanged += OnStorageChanged; }
private static void VoxelOperationElipsoid_Implementation(long entityId, Vector3 radius, MatrixD Transformation, byte material, OperationType Type) { m_ellipsoidShape.Transformation = Transformation; m_ellipsoidShape.Radius = radius; if (CanPlaceInArea(Type, m_ellipsoidShape)) { MyEntity entity; MyEntities.TryGetEntityById(entityId, out entity); MyVoxelBase voxel = entity as MyVoxelBase; if (voxel != null) { voxel.BeforeContentChanged = true; MyMultiplayer.RaiseEvent(voxel.RootVoxel, x => x.PerformVoxelOperationElipsoid_Implementation, radius, Transformation, material, Type); var amountChanged = voxel.UpdateVoxelShape(Type, m_ellipsoidShape, material); if (Type == OperationType.Cut || Type == OperationType.Fill) { MySession.Static.VoxelHandVolumeChanged += amountChanged; } } } }
static void VoxelOperationSphere_Implementation(long entityId, Vector3D center, float radius, byte material, OperationType Type) { m_sphereShape.Center = center; m_sphereShape.Radius = radius; if (CanPlaceInArea(Type, m_sphereShape)) { MyEntity entity; MyEntities.TryGetEntityById(entityId, out entity); MyVoxelBase voxel = entity as MyVoxelBase; if (voxel != null) { voxel.BeforeContentChanged = true; MyMultiplayer.RaiseEvent(voxel, x => x.PerformVoxelOperationSphere_Implementation, center, radius, material, Type); var amountChanged = voxel.UpdateVoxelShape(Type, m_sphereShape, material); if (Type == OperationType.Cut || Type == OperationType.Fill) { MySession.Static.VoxelHandVolumeChanged += amountChanged; } } } }
private static void VoxelOperationBox_Implementation(long entityId, BoundingBoxD box, MatrixD Transformation, byte material, OperationType Type) { m_boxShape.Transformation = Transformation; m_boxShape.Boundaries.Max = box.Max; m_boxShape.Boundaries.Min = box.Min; if (CanPlaceInArea(Type, m_boxShape)) { MyEntity entity; MyEntities.TryGetEntityById(entityId, out entity); MyVoxelBase voxel = entity as MyVoxelBase; if (voxel != null) { voxel.BeforeContentChanged = true; MyMultiplayer.RaiseEvent(voxel.RootVoxel, x => x.PerformVoxelOperationBox_Implementation, box, Transformation, material, Type); var amountChanged = voxel.UpdateVoxelShape(Type, m_boxShape, material); if (Type == OperationType.Cut || Type == OperationType.Fill) { MySession.Static.VoxelHandVolumeChanged += amountChanged; } } } }
private static void VoxelOperationCapsule_Implementation(long entityId, MyCapsuleShapeParams capsuleParams, OperationType Type) { m_capsuleShape.Transformation = capsuleParams.Transformation; m_capsuleShape.A = capsuleParams.A; m_capsuleShape.B = capsuleParams.B; m_capsuleShape.Radius = capsuleParams.Radius; if (CanPlaceInArea(Type, m_capsuleShape)) { MyEntity entity; MyEntities.TryGetEntityById(entityId, out entity); MyVoxelBase voxel = entity as MyVoxelBase; if (voxel != null) { voxel.BeforeContentChanged = true; MyMultiplayer.RaiseEvent(voxel.RootVoxel, x => x.PerformVoxelOperationCapsule_Implementation, capsuleParams, Type); var amountChanged = voxel.UpdateVoxelShape(Type, m_capsuleShape, capsuleParams.Material); if (Type == OperationType.Cut || Type == OperationType.Fill) { MySession.Static.VoxelHandVolumeChanged += amountChanged; } } } }
public abstract void SendFillRequest(MyVoxelBase voxel, byte newMaterialIndex);
public virtual void SendDrillCutOutRequest(MyVoxelBase voxel, bool damage = false) { }
public abstract void SendCutOutRequest(MyVoxelBase voxelbool);
private static bool TestVoxelOverlap(ref MyGridPlacementSettings settings, ref BoundingBoxD localAabb, ref MatrixD worldMatrix, ref BoundingBoxD worldAabb, ref MyVoxelBase overlappedVoxelMap, bool touchingStaticGrid) { ProfilerShort.Begin("VoxelOverlap"); try { if (MyFakes.GRID_IGNORE_VOXEL_OVERLAP) return true; if (MyFakes.ENABLE_VOXEL_MAP_AABB_CORNER_TEST) { return TestPlacementVoxelMapOverlap(overlappedVoxelMap, ref settings, ref localAabb, ref worldMatrix, touchingStaticGrid: touchingStaticGrid); } else { if (overlappedVoxelMap == null) { // Havok only detects overlap with voxel map surface. This test will detect a voxel map even if we're fully inside it. overlappedVoxelMap = MySession.Static.VoxelMaps.GetVoxelMapWhoseBoundingBoxIntersectsBox(ref worldAabb, null); if (overlappedVoxelMap != null) { //We have just test, if aabb is not completelly inside voxelmap if (!overlappedVoxelMap.IsOverlapOverThreshold(worldAabb)) overlappedVoxelMap = null; } } return TestPlacementVoxelMapPenetration(overlappedVoxelMap, ref settings, ref localAabb, ref worldMatrix, touchingStaticGrid: touchingStaticGrid); } } finally { ProfilerShort.End(); } }
private MySoundPair SelectSound() { MySoundPair soundPair = EmptySoundPair; MyCharacterDefinition myCharDefinition = m_character.Definition; MyStringHash physMaterial = MyStringHash.GetOrCompute(myCharDefinition.PhysicalMaterial); m_isWalking = false; bool updateEmitterSounds = false; MyCharacterMovementEnum movementState = m_character.GetCurrentMovementState(); switch (movementState) { case MyCharacterMovementEnum.Walking: case MyCharacterMovementEnum.BackWalking: case MyCharacterMovementEnum.WalkingLeftFront: case MyCharacterMovementEnum.WalkingRightFront: case MyCharacterMovementEnum.WalkingLeftBack: case MyCharacterMovementEnum.WalkingRightBack: case MyCharacterMovementEnum.WalkStrafingLeft: case MyCharacterMovementEnum.WalkStrafingRight: { if (m_character.Breath != null) m_character.Breath.CurrentState = MyCharacterBreath.State.Calm; soundPair = MyMaterialPropertiesHelper.Static.GetCollisionCue(MovementSoundType.Walk, physMaterial, RayCastGround()); m_isWalking = true; } break; case MyCharacterMovementEnum.Running: case MyCharacterMovementEnum.Backrunning: case MyCharacterMovementEnum.RunStrafingLeft: case MyCharacterMovementEnum.RunStrafingRight: case MyCharacterMovementEnum.RunningRightFront: case MyCharacterMovementEnum.RunningRightBack: case MyCharacterMovementEnum.RunningLeftFront: case MyCharacterMovementEnum.RunningLeftBack: { if (m_character.Breath != null) m_character.Breath.CurrentState = MyCharacterBreath.State.Heated; soundPair = MyMaterialPropertiesHelper.Static.GetCollisionCue(MovementSoundType.Run, physMaterial, RayCastGround()); m_isWalking = true; } break; case MyCharacterMovementEnum.CrouchWalking: case MyCharacterMovementEnum.CrouchBackWalking: case MyCharacterMovementEnum.CrouchWalkingLeftFront: case MyCharacterMovementEnum.CrouchWalkingRightFront: case MyCharacterMovementEnum.CrouchWalkingLeftBack: case MyCharacterMovementEnum.CrouchWalkingRightBack: case MyCharacterMovementEnum.CrouchStrafingLeft: case MyCharacterMovementEnum.CrouchStrafingRight: { if (m_character.Breath != null) m_character.Breath.CurrentState = MyCharacterBreath.State.Calm; soundPair = MyMaterialPropertiesHelper.Static.GetCollisionCue(MovementSoundType.CrouchWalk, physMaterial, RayCastGround()); m_isWalking = true; } break; case MyCharacterMovementEnum.Crouching: case MyCharacterMovementEnum.Standing: { if (m_character.Breath != null) m_character.Breath.CurrentState = MyCharacterBreath.State.Calm; var previousMovementState = m_character.GetPreviousMovementState(); var currentMovementState = m_character.GetCurrentMovementState(); if (previousMovementState != currentMovementState && (previousMovementState == MyCharacterMovementEnum.Standing || previousMovementState == MyCharacterMovementEnum.Crouching)) soundPair = (currentMovementState == MyCharacterMovementEnum.Standing) ? CharacterSounds[(int)CharacterSoundsEnum.CROUCH_UP_SOUND] : CharacterSounds[(int)CharacterSoundsEnum.CROUCH_DOWN_SOUND]; } break; case MyCharacterMovementEnum.Sprinting: { if (m_character.Breath != null) m_character.Breath.CurrentState = MyCharacterBreath.State.VeryHeated; soundPair = MyMaterialPropertiesHelper.Static.GetCollisionCue(MovementSoundType.Sprint, physMaterial, RayCastGround()); m_isWalking = true; } break; case MyCharacterMovementEnum.Jump: { if (!m_jumpReady) break; m_jumpReady = false; m_character.SetPreviousMovementState(m_character.GetCurrentMovementState()); var emitter = MyAudioComponent.TryGetSoundEmitter(); // We need to use another emitter otherwise the sound would be cut by silence next frame if (emitter != null) { emitter.Entity = m_character; emitter.PlaySingleSound(CharacterSounds[(int)CharacterSoundsEnum.JUMP_SOUND]); } if ((m_standingOnGrid != null || m_standingOnVoxel != null) && ShouldUpdateSoundEmitters) updateEmitterSounds = true; m_standingOnGrid = null; m_standingOnVoxel = null; } break; case MyCharacterMovementEnum.Flying: { if (m_character.Breath != null) m_character.Breath.CurrentState = MyCharacterBreath.State.Calm; if (m_character.JetpackComp != null && m_jetpackMinIdleTime <= 0f && m_character.JetpackComp.FinalThrust.LengthSquared() >= 50000f) { soundPair = CharacterSounds[(int)CharacterSoundsEnum.JETPACK_RUN_SOUND]; m_jetpackSustainTimer = Math.Min(JETPACK_TIME_BETWEEN_SOUNDS, m_jetpackSustainTimer + MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS); } else { soundPair = CharacterSounds[(int)CharacterSoundsEnum.JETPACK_IDLE_SOUND]; m_jetpackSustainTimer = Math.Max(0f, m_jetpackSustainTimer - MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS); } m_jetpackMinIdleTime -= MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS; if ((m_standingOnGrid != null || m_standingOnVoxel != null) && ShouldUpdateSoundEmitters) updateEmitterSounds = true; m_standingOnGrid = null; m_standingOnVoxel = null; } break; case MyCharacterMovementEnum.Falling: { if (m_character.Breath != null) m_character.Breath.CurrentState = MyCharacterBreath.State.Calm; if ((m_standingOnGrid != null || m_standingOnVoxel != null) && ShouldUpdateSoundEmitters) updateEmitterSounds = true; m_standingOnGrid = null; m_standingOnVoxel = null; } break; default: { } break; } //MyRenderProxy.DebugDrawText2D(Vector2.Zero, movementState.ToString(), Color.Red, 1.0f); if (movementState != MyCharacterMovementEnum.Flying) { m_jetpackSustainTimer = 0f; m_jetpackMinIdleTime = 0.5f; } if(updateEmitterSounds) MyEntity3DSoundEmitter.UpdateEntityEmitters(true, true, false); return soundPair; }
public static void CutOutShapeWithProperties( MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary<MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false) { ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; var bbox = shape.GetWorldBoundaries(); Vector3I minCorner, maxCorner; ComputeShapeBounds(ref bbox, voxelMap.PositionLeftBottomCorner, voxelMap.Storage.Size, out minCorner, out maxCorner); var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax); { var shapeCenter = bbox.Center; Vector3I exactCenter; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeCenter, out exactCenter); exactCenter -= cacheMin; exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1); voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter)); } for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove continue; Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection continue; var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos)); var toRemove = (int)(maxRemove * voxelMat.DamageRatio); var newVal = MathHelper.Clamp(original - toRemove, 0, maxRemove); var removed = Math.Abs(original - newVal); if (!onlyCheck) m_cache.Content(ref relPos, (byte)newVal); originalSum += original; removedSum += removed; if (exactCutOutMaterials != null) { int value = 0; exactCutOutMaterials.TryGetValue(voxelMat, out value); value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed); exactCutOutMaterials[voxelMat] = value; } } if (removedSum > 0 && !onlyCheck) { // Clear all small voxel that may have been created during explosion. They can be created even outside the range of // explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the // explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we // will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove // B voxels too. //!! TODO AR & MK : check if this is needed !! RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap.SyncObject); } voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; ProfilerShort.End(); }
private static bool TestPlacementVoxelMapPenetration( MyVoxelBase voxelMap, ref MyGridPlacementSettings settings, ref BoundingBoxD localAabb, ref MatrixD worldMatrix, bool touchingStaticGrid = false) { ProfilerShort.Begin("TestPlacementVoxelMapPenetration"); var worldAabb = localAabb.Transform(ref worldMatrix); float penetrationAmountNormalized = 0f; float penetrationRatio = 0f; float penetrationVolume = 0f; if (voxelMap != null) { float unused; penetrationAmountNormalized = voxelMap.GetVoxelContentInBoundingBox_Obsolete(worldAabb, out unused); penetrationVolume = penetrationAmountNormalized * MyVoxelConstants.VOXEL_VOLUME_IN_METERS; penetrationRatio = penetrationVolume / (float)worldAabb.Volume; } bool penetrationTestPassed = true; switch (settings.Penetration.Unit) { case MyGridPlacementSettings.PenetrationUnitEnum.Absolute: penetrationTestPassed = penetrationVolume <= settings.Penetration.MaxAllowed && (penetrationVolume >= settings.Penetration.MinAllowed || (settings.CanAnchorToStaticGrid && touchingStaticGrid)); break; case MyGridPlacementSettings.PenetrationUnitEnum.Ratio: penetrationTestPassed = penetrationRatio <= settings.Penetration.MaxAllowed && (penetrationRatio >= settings.Penetration.MinAllowed || (settings.CanAnchorToStaticGrid && touchingStaticGrid)); break; default: Debug.Fail("Invalid branch."); break; } ProfilerShort.End(); return penetrationTestPassed; }
private void MakeTransparent(MyVoxelBase voxelMap) { voxelMap.Render.Transparency = MyGridConstants.BUILDER_TRANSPARENCY; }
private void MakeVisible(MyVoxelBase voxelMap) { voxelMap.Render.Transparency = 0f; }
public bool Exist(MyVoxelBase voxelMap) { return(m_voxelMapsByEntityId.ContainsKey(voxelMap.EntityId)); }
/// <summary> /// Return reference to voxel map that intersects the box. If not voxel map found, null is returned. /// </summary> public MyVoxelBase GetVoxelMapWhoseBoundingBoxIntersectsBox(ref BoundingBoxD boundingBox, MyVoxelBase ignoreVoxelMap) { foreach (var voxelMap in m_voxelMapsByEntityId.Values) { if (voxelMap == ignoreVoxelMap) { continue; } if (voxelMap is MyVoxelBase) { if (voxelMap.IsBoxIntersectingBoundingBoxOfThisVoxelMap(ref boundingBox)) { return(voxelMap); } } } // If we get here, no intersection was found return(null); }
private static void ComputeShapeBounds(MyVoxelBase voxelMap, ref BoundingBoxD shapeAabb, Vector3D voxelMapMinCorner, Vector3I storageSize, out Vector3I voxelMin, out Vector3I voxelMax) { MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMapMinCorner, ref shapeAabb.Min, out voxelMin); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMapMinCorner, ref shapeAabb.Max, out voxelMax); voxelMin += voxelMap.StorageMin; voxelMax += voxelMap.StorageMin; voxelMax += 1; //what? why? Another hack of MK? storageSize -= 1; Vector3I.Clamp(ref voxelMin, ref Vector3I.Zero, ref storageSize, out voxelMin); Vector3I.Clamp(ref voxelMax, ref Vector3I.Zero, ref storageSize, out voxelMax); }
private void AddVoxelMesh(MyVoxelBase voxelBase, IMyStorage storage, Dictionary<Vector3I, MyIsoMesh> cache, float border, Vector3D originPosition, MyOrientedBoundingBoxD obb, List<BoundingBoxD> bbList) { bool useCache = cache != null; if (useCache) CheckCacheValidity(); obb.HalfExtent += new Vector3D(border, 0, border); BoundingBoxD bb = obb.GetAABB(); int aabbSideSide = (int)Math.Round(bb.HalfExtents.Max() * 2); bb = new BoundingBoxD(bb.Min, bb.Min + aabbSideSide); bb.Translate(obb.Center - bb.Center); // For debug bbList.Add(new BoundingBoxD(bb.Min, bb.Max)); bb = (BoundingBoxD)bb.TransformFast(voxelBase.PositionComp.WorldMatrixInvScaled); bb.Translate(voxelBase.SizeInMetresHalf); Vector3I min = Vector3I.Round(bb.Min); Vector3I max = min + aabbSideSide; Vector3I geomMin, geomMax; MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref min, out geomMin); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref max, out geomMax); var cullBox = obb; cullBox.Transform(voxelBase.PositionComp.WorldMatrixInvScaled); cullBox.Center += voxelBase.SizeInMetresHalf; ProfilerShort.Begin("WOOOORK"); Vector3I_RangeIterator it = new Vector3I_RangeIterator(ref geomMin, ref geomMax); MyCellCoord coord = new MyCellCoord(); BoundingBox localAabb; coord.Lod = NAVMESH_LOD; int hits = 0; MyIsoMesh gMesh; Vector3 offset = originPosition - voxelBase.PositionLeftBottomCorner; // Calculate rotation Vector3 gravityVector = -Vector3.Normalize(GameSystems.MyGravityProviderSystem.CalculateTotalGravityInPoint(originPosition)); Vector3 forwardVector = Vector3.CalculatePerpendicularVector(gravityVector); Quaternion quaternion = Quaternion.CreateFromForwardUp(forwardVector, gravityVector); Matrix rotation = Matrix.CreateFromQuaternion(Quaternion.Inverse(quaternion)); Matrix ownRotation = voxelBase.PositionComp.WorldMatrix.GetOrientation(); while (it.IsValid()) { ProfilerShort.Begin("ITERATOR"); if (useCache && cache.TryGetValue(it.Current, out gMesh)) { if (gMesh != null) { AddMeshTriangles(gMesh, offset, rotation, ownRotation); } it.MoveNext(); ProfilerShort.End(); continue; } coord.CoordInLod = it.Current; MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref coord.CoordInLod, out localAabb); if (!cullBox.Intersects(ref localAabb)) { hits++; it.MoveNext(); ProfilerShort.End(); continue; } ProfilerShort.End(); var debugBB = new BoundingBoxD(localAabb.Min, localAabb.Max).Translate(-voxelBase.SizeInMetresHalf); bbList.Add(debugBB); ProfilerShort.Begin("Mesh Calc"); var voxelStart = coord.CoordInLod * MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS - 1; var voxelEnd = voxelStart + MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS //- 1 + 1 // overlap to neighbor so geometry is stitched together within same LOD + 1; // for eg. 9 vertices in row we need 9 + 1 samples (voxels) var generatedMesh = MyPrecalcComponent.IsoMesher.Precalc(storage, NAVMESH_LOD, voxelStart, voxelEnd, false, false, true); ProfilerShort.End(); if (useCache) cache[it.Current] = generatedMesh; if (generatedMesh != null) { ProfilerShort.Begin("Mesh NOT NULL"); AddMeshTriangles(generatedMesh, offset, rotation, ownRotation); ProfilerShort.End(); } it.MoveNext(); } ProfilerShort.End(); }
public static void PaintInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx) { Vector3I minCorner, maxCorner, numCells; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells); for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext()) { Vector3I cellMinCorner, cellMaxCorner; GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner); m_cache.Resize(cellMinCorner, cellMaxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, 0, ref cellMinCorner, ref cellMaxCorner); for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cellMinCorner; Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); float volume = shape.GetVolume(ref vpos); if (volume > 0.5f) m_cache.Material(ref relPos, materialIdx); // set material } voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Material, ref cellMinCorner, ref cellMaxCorner); } }
private MyStringHash RayCastGround() { MyStringHash walkSurfaceMaterial = new MyStringHash(); float maxDistValue = MyConstants.DEFAULT_GROUND_SEARCH_DISTANCE; var from = m_character.PositionComp.GetPosition() + m_character.PositionComp.WorldMatrix.Up * 0.5; //(needs some small distance from the bottom or the following call to HavokWorld.CastRay will find no hits) var to = from + m_character.PositionComp.WorldMatrix.Down * maxDistValue; MyPhysics.CastRay(from, to, m_hits, MyPhysics.CollisionLayers.CharacterCollisionLayer); // Skips invalid hits (null body, self character) int index = 0; while ((index < m_hits.Count) && ((m_hits[index].HkHitInfo.Body == null) || (m_hits[index].HkHitInfo.GetHitEntity() == Entity.Components))) { index++; } if (m_hits.Count == 0) { if ((m_standingOnGrid != null || m_standingOnVoxel != null) && ShouldUpdateSoundEmitters) { m_standingOnGrid = null; m_standingOnVoxel = null; MyEntity3DSoundEmitter.UpdateEntityEmitters(true, true, false); } else { m_standingOnGrid = null; m_standingOnVoxel = null; } } if (index < m_hits.Count) { // We must take only closest hit (others are hidden behind) var h = m_hits[index]; var entity = h.HkHitInfo.GetHitEntity(); var sqDist = Vector3D.DistanceSquared((Vector3D)h.Position, from); if (sqDist < maxDistValue * maxDistValue) { var cubeGrid = entity as MyCubeGrid; var voxelBase = entity as MyVoxelBase; if (((cubeGrid != null && m_standingOnGrid != cubeGrid) || (voxelBase != null && m_standingOnVoxel != voxelBase)) && ShouldUpdateSoundEmitters) { m_standingOnGrid = cubeGrid; m_standingOnVoxel = voxelBase; MyEntity3DSoundEmitter.UpdateEntityEmitters(true, true, true); } else { m_standingOnGrid = cubeGrid; m_standingOnVoxel = voxelBase; } if(cubeGrid != null || voxelBase != null) m_jumpReady = true; if (cubeGrid != null) walkSurfaceMaterial = cubeGrid.Physics.GetMaterialAt(h.Position + m_character.PositionComp.WorldMatrix.Down * 0.1f); else if (voxelBase != null && voxelBase.Storage != null && voxelBase.Storage.DataProvider != null) { var materialDefinition = voxelBase.GetMaterialAt(ref h.Position); if (materialDefinition != null) walkSurfaceMaterial = MyStringHash.GetOrCompute(materialDefinition.MaterialTypeName); } if (walkSurfaceMaterial.ToString().Length == 0) walkSurfaceMaterial = MyMaterialType.ROCK; } } m_hits.Clear(); return walkSurfaceMaterial; }
private static void GetVoxelShapeDimensions(MyVoxelBase voxelMap, MyShape shape, out Vector3I minCorner, out Vector3I maxCorner, out Vector3I numCells, float extent = 0.0f) { { var bbox = shape.GetWorldBoundaries(); ComputeShapeBounds(ref bbox, voxelMap.PositionLeftBottomCorner, voxelMap.Storage.Size, out minCorner, out maxCorner); } minCorner += voxelMap.StorageMin; maxCorner += voxelMap.StorageMin; numCells = new Vector3I((maxCorner.X - minCorner.X) / CELL_SIZE, (maxCorner.Y - minCorner.Y) / CELL_SIZE, (maxCorner.Z - minCorner.Z) / CELL_SIZE); }
public static bool TestPlacementVoxelMapOverlap( MyVoxelBase voxelMap, ref MyGridPlacementSettings settings, ref BoundingBoxD localAabb, ref MatrixD worldMatrix, bool touchingStaticGrid = false) { ProfilerShort.Begin("TestPlacementVoxelMapOverlap"); var worldAabb = localAabb.Transform(ref worldMatrix); const int IntersectsOrInside = 1; const int Outside = 2; int overlapState = Outside; if (voxelMap == null) voxelMap = MySession.Static.VoxelMaps.GetVoxelMapWhoseBoundingBoxIntersectsBox(ref worldAabb, null); if (voxelMap != null && voxelMap.IsAnyAabbCornerInside(ref worldMatrix, localAabb)) { overlapState = IntersectsOrInside; } bool testPassed = true; switch (overlapState) { case IntersectsOrInside: testPassed = settings.Penetration.MaxAllowed > 0; break; case Outside: testPassed = settings.Penetration.MinAllowed <= 0 || (settings.CanAnchorToStaticGrid && touchingStaticGrid); break; default: Debug.Fail("Invalid branch."); break; } ProfilerShort.End(); return testPassed; }
private void CreateCrater(MyPhysics.MyContactPointEvent value, MyVoxelBase voxel) { if (Math.Abs(Vector3.Normalize(-Entity.WorldMatrix.Forward).Dot(value.ContactPointEvent.ContactPoint.Normal)) < 0.1) { MyParticleEffect impactParticle1; if (InParticleVisibleRange && MyParticlesManager.TryCreateParticleEffect((int)MyParticleEffectsIDEnum.MeteorAsteroidCollision, out impactParticle1)) { impactParticle1.WorldMatrix = Entity.WorldMatrix; impactParticle1.UserScale = (float)Entity.PositionComp.WorldVolume.Radius * 2; } m_particleVectorUp = Vector3.Zero; return; } if (Sync.IsServer) { BoundingSphereD sphere = new BoundingSphere(value.Position, Entity.PositionComp.Scale.Value / 3); Vector3 direction; // if contact was send after reflection we need to get former direction if (value.ContactPointEvent.SeparatingVelocity < 0) direction = Vector3.Normalize(Entity.Physics.LinearVelocity); else direction = Vector3.Normalize(Vector3.Reflect(Entity.Physics.LinearVelocity, value.ContactPointEvent.ContactPoint.Normal)); var material = VoxelMaterial; int tries = MyDefinitionManager.Static.GetVoxelMaterialDefinitions().Count() * 2; // max amount of tries while (!material.IsRare || !material.SpawnsFromMeteorites || material.MinVersion > MySession.Static.Settings.VoxelGeneratorVersion) { if (--tries < 0) // to prevent infinite loops in case all materials are disabled just use the meteorites' initial material { material = VoxelMaterial; break; } material = MyDefinitionManager.Static.GetVoxelMaterialDefinitions().ElementAt(MyUtils.GetRandomInt(MyDefinitionManager.Static.GetVoxelMaterialDefinitions().Count() - 1)); } voxel.CreateVoxelMeteorCrater(sphere.Center, (float)sphere.Radius, -direction, material); MyVoxelGenerator.MakeCrater(voxel, sphere, -direction, material); } m_closeAfterSimulation = Sync.IsServer; }
public static void MakeCrater(MyVoxelBase voxelMap, BoundingSphereD sphere, Vector3 normal, MyVoxelMaterialDefinition material) { ProfilerShort.Begin("MakeCrater"); Vector3I minCorner, maxCorner; { Vector3D sphereMin = sphere.Center - (sphere.Radius - MyVoxelConstants.VOXEL_SIZE_IN_METRES); Vector3D sphereMax = sphere.Center + (sphere.Radius + MyVoxelConstants.VOXEL_SIZE_IN_METRES); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref sphereMin, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref sphereMax, out maxCorner); } voxelMap.Storage.ClampVoxelCoord(ref minCorner); voxelMap.Storage.ClampVoxelCoord(ref maxCorner); // We are tracking which voxels were changed, so we can invalidate only needed cells in the cache bool changed = false; ProfilerShort.Begin("Reading cache"); m_cache.Resize(minCorner, maxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref minCorner, ref maxCorner); ProfilerShort.End(); ProfilerShort.Begin("Changing cache"); int removedVoxelContent = 0; Vector3I tempVoxelCoord; Vector3I cachePos; for (tempVoxelCoord.Z = minCorner.Z, cachePos.Z = 0; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++, ++cachePos.Z) { for (tempVoxelCoord.Y = minCorner.Y, cachePos.Y = 0; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++, ++cachePos.Y) { for (tempVoxelCoord.X = minCorner.X, cachePos.X = 0; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++, ++cachePos.X) { Vector3D voxelPosition; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref tempVoxelCoord, out voxelPosition); float addDist = (float)(voxelPosition - sphere.Center).Length(); float addDiff = (float)(addDist - sphere.Radius); byte newContent; if (addDiff > MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) { newContent = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (addDiff < -MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) { newContent = MyVoxelConstants.VOXEL_CONTENT_FULL; } else { // This formula will work even if diff is positive or negative newContent = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - addDiff / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } byte originalContent = m_cache.Content(ref cachePos); if (newContent > originalContent && originalContent > 0) { if (material != null) { m_cache.Material(ref cachePos, material.Index); } changed = true; m_cache.Content(ref cachePos, newContent); } float delDist = (float)(voxelPosition - (sphere.Center + (float)sphere.Radius * 0.7f * normal)).Length(); float delDiff = (float)(delDist - sphere.Radius); byte contentToRemove; if (delDiff > MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) { contentToRemove = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (delDiff < -MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) { contentToRemove = MyVoxelConstants.VOXEL_CONTENT_FULL; } else { // This formula will work even if diff is positive or negative contentToRemove = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - delDiff / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } originalContent = m_cache.Content(ref cachePos); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY && contentToRemove > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { changed = true; int newVal = originalContent - contentToRemove; if (newVal < MyVoxelConstants.VOXEL_CONTENT_EMPTY) newVal = MyVoxelConstants.VOXEL_CONTENT_EMPTY; m_cache.Content(ref cachePos, (byte)newVal); removedVoxelContent += originalContent - newVal; } float setDist = (float)(voxelPosition - (sphere.Center - (float)sphere.Radius * 0.5f * normal)).Length(); float setDiff = (float)(setDist - sphere.Radius / 4f); if (setDiff <= MyVoxelConstants.VOXEL_SIZE_IN_METRES * 1.5f) // could be VOXEL_SIZE_IN_METRES_HALF, but we want to set material in empty cells correctly { byte indestructibleContentToSet = MyVoxelConstants.VOXEL_CONTENT_FULL; if (setDiff >= MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) // outside { indestructibleContentToSet = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (setDiff >= -MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) // boundary { indestructibleContentToSet = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - setDiff / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } MyVoxelMaterialDefinition originalMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref cachePos)); // Change the material: // - always on boundaries between material and nothing // - smoothly on inner boundaries MyVoxelMaterialDefinition newMaterial = material; if (setDiff > 0) { byte content = m_cache.Content(ref cachePos); if (content == MyVoxelConstants.VOXEL_CONTENT_FULL) newMaterial = originalMaterial; if (setDiff >= MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF && content != MyVoxelConstants.VOXEL_CONTENT_EMPTY) // set material behind boundary only for empty voxels newMaterial = originalMaterial; } if (originalMaterial == newMaterial) { continue; } m_cache.Material(ref cachePos, newMaterial.Index); changed = true; } float dist = (float)(voxelPosition - sphere.Center).Length(); float diff = (float)(dist - sphere.Radius); if (diff <= 0f) { originalContent = m_cache.Content(ref cachePos); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { bool wrinkled = m_cache.WrinkleVoxelContent(ref cachePos, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_ADD, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_REMOVE); if (wrinkled) changed = true; } } } } } ProfilerShort.End(); if (changed) { ProfilerShort.Begin("RemoveSmallVoxelsUsingChachedVoxels"); RemoveSmallVoxelsUsingChachedVoxels(); ProfilerShort.BeginNextBlock("Writing cache"); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, ref minCorner, ref maxCorner); ProfilerShort.End(); } ProfilerShort.End(); }
public override void SendFillRequest(MyVoxelBase voxel, byte newMaterialIndex) { voxel.RequestVoxelOperationRamp(Boundaries, RampNormal, RampNormalW, Transformation, newMaterialIndex, OperationType.Fill); }
public static ulong FillInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx) { Vector3I minCorner, maxCorner, numCells; ulong retValue = 0; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells); for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext()) { Vector3I cellMinCorner, cellMaxCorner; GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner); Vector3I originalMinCorner = cellMinCorner; Vector3I originalMaxCorner = cellMaxCorner; voxelMap.Storage.ClampVoxelCoord(ref cellMinCorner, VOXEL_CLAMP_BORDER_DISTANCE); voxelMap.Storage.ClampVoxelCoord(ref cellMaxCorner, VOXEL_CLAMP_BORDER_DISTANCE); ClampingInfo minCornerClamping = CheckForClamping(originalMinCorner, cellMinCorner); ClampingInfo maxCornerClamping = CheckForClamping(originalMaxCorner, cellMaxCorner); m_cache.Resize(cellMinCorner, cellMaxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cellMinCorner, ref cellMaxCorner); ulong filledSum = 0; for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cellMinCorner; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_FULL) // if there is nothing to add continue; //if there was some claping, fill the clamp region with material if ((it.Current.X == cellMinCorner.X && minCornerClamping.X) || (it.Current.X == cellMaxCorner.X && maxCornerClamping.X) || (it.Current.Y == cellMinCorner.Y && minCornerClamping.Y) || (it.Current.Y == cellMaxCorner.Y && maxCornerClamping.Y) || (it.Current.Z == cellMinCorner.Z && minCornerClamping.Z) || (it.Current.Z == cellMaxCorner.Z && maxCornerClamping.Z)) { m_cache.Material(ref relPos, materialIdx); continue; } Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume <= 0f) // there is nothing to fill continue; m_cache.Material(ref relPos, materialIdx); // set material var toFill = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); long newVal = MathHelper.Clamp(original + toFill, 0, Math.Max(original, toFill)); m_cache.Content(ref relPos, (byte)newVal); filledSum += (ulong)(newVal - original); } if (filledSum > 0) { RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, ref cellMinCorner, ref cellMaxCorner); } retValue += filledSum; } return retValue; }
public override void SendCutOutRequest(MyVoxelBase voxel) { voxel.RequestVoxelOperationCapsule(A, B, Radius, Transformation, 0, OperationType.Cut); }
public static ulong CutOutShape(MyVoxelBase voxelMap, MyShape shape) { Vector3I minCorner, maxCorner, numCells; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells); ulong changedVolumeAmount = 0; for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext()) { Vector3I cellMinCorner, cellMaxCorner; GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner); var cacheMin = cellMinCorner - 1; var cacheMax = cellMaxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); ulong removedSum = 0; m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, 0, ref cacheMin, ref cacheMax); for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove continue; Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection continue; var toRemove = (int)(MyVoxelConstants.VOXEL_CONTENT_FULL - (volume * MyVoxelConstants.VOXEL_CONTENT_FULL)); var newVal = Math.Min(toRemove, original); ulong removed = (ulong)Math.Abs(original - newVal); m_cache.Content(ref relPos, (byte)newVal); removedSum += removed; } if (removedSum > 0) { RemoveSmallVoxelsUsingChachedVoxels(); // must stay because of the around when filling voxels voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } changedVolumeAmount += removedSum; } return changedVolumeAmount; }
public override void SendFillRequest(MyVoxelBase voxel, byte newMaterialIndex) { voxel.RequestVoxelOperationCapsule(A, B, Radius, Transformation, newMaterialIndex, OperationType.Fill); }
private void CreatePlanetMenu() { m_currentVoxel = null; MyGuiControlList list = new MyGuiControlList(size: new Vector2(SCREEN_SIZE.X,1.0f)); Vector2 controlPadding = new Vector2(0.02f, 0.02f); // X: Left & Right, Y: Bottom & Top float textScale = 0.8f; float usableWidth = SCREEN_SIZE.X - HIDDEN_PART_RIGHT - controlPadding.X * 2; m_currentPosition = Vector2.Zero;/* -m_size.Value / 2.0f; m_currentPosition += controlPadding;*/ m_scale = textScale; var label = AddLabel(MyTexts.GetString(MySpaceTexts.ScreenDebugSpawnMenu_SelectAsteroidType), Vector4.One, m_scale); Controls.Remove(label); list.Controls.Add(label); var combo = AddCombo(); combo.AddItem(1, MySpaceTexts.ScreenDebugSpawnMenu_PredefinedAsteroids); combo.AddItem(2, MySpaceTexts.ScreenDebugSpawnMenu_ProceduralAsteroids); combo.AddItem(3, MySpaceTexts.ScreenDebugSpawnMenu_Planets); combo.SelectItemByKey(m_asteroid_showPlanet ? 3 : m_asteroid_showPredefinedOrProcedural ? 1 : 2); combo.ItemSelected += () => { m_asteroid_showPredefinedOrProcedural = combo.GetSelectedKey() == 1; m_asteroid_showPlanet = combo.GetSelectedKey() == 3; RecreateControls(false); }; Controls.Remove(combo); list.Controls.Add(combo); CreatePlanetControls(list, usableWidth); AddSeparator(list); var button = CreateDebugButton(usableWidth, MySpaceTexts.ScreenDebugSpawnMenu_SpawnAsteroid, OnSpawnProceduralAsteroid); Controls.Remove(button); list.Controls.Add(button); Controls.Add(list); }
public static void MakeCrater(MyVoxelBase voxelMap, BoundingSphereD sphere, Vector3 direction, MyVoxelMaterialDefinition material) { ProfilerShort.Begin("MakeCrater"); Vector3 normal = Vector3.Normalize(sphere.Center - voxelMap.RootVoxel.WorldMatrix.Translation); Vector3I minCorner, maxCorner; { Vector3D sphereMin = sphere.Center - (sphere.Radius - MyVoxelConstants.VOXEL_SIZE_IN_METRES) * 1.3f; Vector3D sphereMax = sphere.Center + (sphere.Radius + MyVoxelConstants.VOXEL_SIZE_IN_METRES) * 1.3f; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref sphereMin, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref sphereMax, out maxCorner); } voxelMap.Storage.ClampVoxelCoord(ref minCorner); voxelMap.Storage.ClampVoxelCoord(ref maxCorner); Vector3I worldMinCorner = minCorner + voxelMap.StorageMin; Vector3I worldMaxCorner = maxCorner + voxelMap.StorageMin; // We are tracking which voxels were changed, so we can invalidate only needed cells in the cache bool changed = false; ProfilerShort.Begin("Reading cache"); m_cache.Resize(minCorner, maxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref worldMinCorner, ref worldMaxCorner); ProfilerShort.End(); ProfilerShort.Begin("Changing cache"); int removedVoxelContent = 0; Vector3I tempVoxelCoord; Vector3I cachePos = (maxCorner - minCorner) / 2; byte oldMaterial = m_cache.Material(ref cachePos); float digRatio = 1 - Vector3.Dot(normal, direction); Vector3 newCenter = sphere.Center - normal * (float)sphere.Radius * 1.1f;//0.9f; float sphRadA = (float)(sphere.Radius * 1.5f); float sphRadSqA = (float)(sphRadA * sphRadA); float voxelSizeHalfTransformedPosA = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (2 * sphRadA + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); float voxelSizeHalfTransformedNegA = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (-2 * sphRadA + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); Vector3 newDelCenter = newCenter + normal * (float)sphere.Radius * (0.7f + digRatio) + direction * (float)sphere.Radius * 0.65f; float sphRadD = (float)(sphere.Radius); float sphRadSqD = (float)(sphRadD * sphRadD); float voxelSizeHalfTransformedPosD = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (2 * sphRadD + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); float voxelSizeHalfTransformedNegD = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (-2 * sphRadD + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); Vector3 newSetCenter = newCenter + normal * (float)sphere.Radius * (digRatio) + direction * (float)sphere.Radius * 0.3f; float sphRadS = (float)(sphere.Radius * 0.1f); float sphRadSqS = (float)(sphRadS * sphRadS); float voxelSizeHalfTransformedPosS = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (2 * sphRadS + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); for (tempVoxelCoord.Z = minCorner.Z, cachePos.Z = 0; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++, ++cachePos.Z) { for (tempVoxelCoord.Y = minCorner.Y, cachePos.Y = 0; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++, ++cachePos.Y) { for (tempVoxelCoord.X = minCorner.X, cachePos.X = 0; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++, ++cachePos.X) { Vector3D voxelPosition; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref tempVoxelCoord, out voxelPosition); byte originalContent = m_cache.Content(ref cachePos); //Add sphere if (originalContent != MyVoxelConstants.VOXEL_CONTENT_FULL) { float addDist = (float)(voxelPosition - newCenter).LengthSquared(); float addDiff = (float)(addDist - sphRadSqA); byte newContent; if (addDiff > voxelSizeHalfTransformedPosA) { newContent = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (addDiff < voxelSizeHalfTransformedNegA) { newContent = MyVoxelConstants.VOXEL_CONTENT_FULL; } else { float value = (float)Math.Sqrt(addDist + sphRadSqA - 2 * sphRadA * Math.Sqrt(addDist)); if (addDiff < 0) { value = -value; } // This formula will work even if diff is positive or negative newContent = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - value / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } if (newContent > originalContent) { if (material != null) { m_cache.Material(ref cachePos, oldMaterial); } changed = true; m_cache.Content(ref cachePos, newContent); } } //Delete sphere float delDist = (float)(voxelPosition - newDelCenter).LengthSquared(); float delDiff = (float)(delDist - sphRadSqD); byte contentToRemove; if (delDiff > voxelSizeHalfTransformedPosD) { contentToRemove = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (delDiff < voxelSizeHalfTransformedNegD) { contentToRemove = MyVoxelConstants.VOXEL_CONTENT_FULL; } else { float value = (float)Math.Sqrt(delDist + sphRadSqD - 2 * sphRadD * Math.Sqrt(delDist)); if (delDiff < 0) { value = -value; } // This formula will work even if diff is positive or negative contentToRemove = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - value / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } originalContent = m_cache.Content(ref cachePos); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY && contentToRemove > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { changed = true; int newVal = originalContent - contentToRemove; if (newVal < MyVoxelConstants.VOXEL_CONTENT_EMPTY) newVal = MyVoxelConstants.VOXEL_CONTENT_EMPTY; m_cache.Content(ref cachePos, (byte)newVal); removedVoxelContent += originalContent - newVal; } //Set material float setDist = (float)(voxelPosition - newSetCenter).LengthSquared(); float setDiff = (float)(setDist - sphRadSqS); if (setDiff <= MyVoxelConstants.VOXEL_SIZE_IN_METRES * 1.5f) // could be VOXEL_SIZE_IN_METRES_HALF, but we want to set material in empty cells correctly { MyVoxelMaterialDefinition originalMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref cachePos)); // Change the material: // - always on boundaries between material and nothing // - smoothly on inner boundaries MyVoxelMaterialDefinition newMaterial = material; if (setDiff > 0) { byte content = m_cache.Content(ref cachePos); if (content == MyVoxelConstants.VOXEL_CONTENT_FULL) newMaterial = originalMaterial; if (setDiff >= voxelSizeHalfTransformedPosS && content != MyVoxelConstants.VOXEL_CONTENT_EMPTY) // set material behind boundary only for empty voxels newMaterial = originalMaterial; } if (originalMaterial == newMaterial) { continue; } m_cache.Material(ref cachePos, newMaterial.Index); changed = true; } float dist = (float)(voxelPosition - newCenter).LengthSquared(); float diff = (float)(dist - sphRadSqA); if (diff <= 0f) { originalContent = m_cache.Content(ref cachePos); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { bool wrinkled = m_cache.WrinkleVoxelContent(ref cachePos, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_ADD, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_REMOVE); if (wrinkled) changed = true; } } } } } ProfilerShort.End(); if (changed) { ProfilerShort.Begin("RemoveSmallVoxelsUsingChachedVoxels"); RemoveSmallVoxelsUsingChachedVoxels(); ProfilerShort.BeginNextBlock("Writing cache"); minCorner += voxelMap.StorageMin; maxCorner += voxelMap.StorageMin; voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, ref minCorner, ref maxCorner); MyShapeSphere sphereShape = new MyShapeSphere(); sphereShape.Center = sphere.Center; sphereShape.Radius = (float)(sphere.Radius*1.5); OnVoxelChanged(OperationType.Cut, voxelMap, sphereShape); ProfilerShort.End(); } ProfilerShort.End(); }
private void DebugDrawVertexNames() { //VRageRender.MyRenderProxy.DebugDrawText2D(new Vector2(10, 0), "Voxel names searching", Color.Yellow, 0.5f); LineD line = new LineD(IntersectionStart, IntersectionStart + IntersectionDirection * 500); MyIntersectionResultLineTriangleEx?intersection = MyEntities.GetIntersectionWithLine(ref line, MySession.Static.LocalCharacter, null, false, true, true, VRage.Game.Components.IntersectionFlags.ALL_TRIANGLES, 0, false); if (intersection.HasValue) { if (intersection.Value.Entity is MyVoxelBase) { MyVoxelBase voxels = (MyVoxelBase)intersection.Value.Entity; Vector3D point = intersection.Value.IntersectionPointInWorldSpace; if (intersection.Value.Entity is MyPlanet) { MyRenderProxy.DebugDrawText2D(new Vector2(20, 20), "Type: planet/moon", Color.Yellow, DEBUG_SCALE); MyRenderProxy.DebugDrawText2D(new Vector2(20, 30), "Terrain: " + voxels.GetMaterialAt(ref point), Color.Yellow, DEBUG_SCALE); } else { MyRenderProxy.DebugDrawText2D(new Vector2(20, 20), "Type: asteroid", Color.Yellow, DEBUG_SCALE); MyRenderProxy.DebugDrawText2D(new Vector2(20, 30), "Terrain: " + voxels.GetMaterialAt(ref point), Color.Yellow, DEBUG_SCALE); } MyRenderProxy.DebugDrawText2D(new Vector2(20, 40), "Object size: " + voxels.SizeInMetres, Color.Yellow, DEBUG_SCALE); //location /* * VRageRender.MyRenderProxy.DebugDrawText2D(new Vector2(20, 50), "Location:", Color.Yellow, 0.5f); * VRageRender.MyRenderProxy.DebugDrawText2D(new Vector2(30, 60), "x " + Math.Round(point.X, 3).ToString(), Color.Yellow, 0.5f); * VRageRender.MyRenderProxy.DebugDrawText2D(new Vector2(30, 70), "y " + Math.Round(point.Y, 3).ToString(), Color.Yellow, 0.5f); * VRageRender.MyRenderProxy.DebugDrawText2D(new Vector2(30, 80), "z " + Math.Round(point.Z, 3).ToString(), Color.Yellow, 0.5f);*/ } else if (intersection.Value.Entity is MyCubeGrid) { MyCubeGrid grid = (MyCubeGrid)intersection.Value.Entity; MyRenderProxy.DebugDrawText2D(new Vector2(20, 20), "Detected grid object", Color.Yellow, DEBUG_SCALE); MyRenderProxy.DebugDrawText2D(new Vector2(20, 30), String.Format("Grid name: {0}", grid.DisplayName), Color.Yellow, DEBUG_SCALE); int row = 4; MyIntersectionResultLineTriangleEx?t; MySlimBlock block; if (grid.GetIntersectionWithLine(ref line, out t, out block) && t.HasValue && block != null) { if (block.FatBlock != null) { DebugDrawModelTextures(block.FatBlock, ref row); } else { DebugDrawBareBlockInfo(block, ref row); } } } else { MyRenderProxy.DebugDrawText2D(new Vector2(20, 20), "Unknown object detected", Color.Yellow, DEBUG_SCALE); } } else { MyRenderProxy.DebugDrawText2D(new Vector2(20, 20), "Nothing detected nearby", Color.Yellow, DEBUG_SCALE); } }
public static void CutOutShapeWithProperties( MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary<MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false, bool applyDamageMaterial = false, bool onlyApplyMaterial = false) { if (MySession.Static.EnableVoxelDestruction == false) { voxelsCountInPercent = 0; voxelMaterial = null; return; } ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; bool materials = exactCutOutMaterials != null; // Bring the shape into voxel space. var oldTranmsform = shape.Transformation; var newTransf = oldTranmsform * voxelMap.PositionComp.WorldMatrixInvScaled; newTransf.Translation += voxelMap.SizeInMetresHalf; shape.Transformation = newTransf; // This boundary should now be in our local space var bbox = shape.GetWorldBoundaries(); Vector3I minCorner, maxCorner; ComputeShapeBounds(voxelMap, ref bbox, Vector3.Zero, voxelMap.Storage.Size, out minCorner, out maxCorner); bool readMaterial = exactCutOutMaterials != null || applyDamageMaterial; var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; //try on making the read/write cell alligned see MyOctreeStorage.WriteRange - Micro octree leaf /*const int SHIFT = 4; const int REM = (1 << SHIFT) - 1; const int MASK = ~REM; cacheMin &= MASK; cacheMax = (cacheMax + REM) & MASK;*/ voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); m_cache.ClearMaterials(0); // Advise that the read content shall be cached MyVoxelRequestFlags flags = MyVoxelRequestFlags.AdviseCache; voxelMap.Storage.ReadRange(m_cache, readMaterial ? MyStorageDataTypeFlags.ContentAndMaterial : MyStorageDataTypeFlags.Content, 0, ref cacheMin, ref cacheMax, ref flags); Vector3I center; if (materials) { center = m_cache.Size3D / 2; voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref center)); } else { center = (cacheMin + cacheMax) / 2; voxelMaterial = voxelMap.Storage.GetMaterialAt(ref center); } MyVoxelMaterialDefinition voxelMat = null; ProfilerShort.Begin("Main loop"); Vector3I pos; for (pos.X = minCorner.X; pos.X <= maxCorner.X; ++pos.X) for (pos.Y = minCorner.Y; pos.Y <= maxCorner.Y; ++pos.Y) for (pos.Z = minCorner.Z; pos.Z <= maxCorner.Z; ++pos.Z) { // get original amount var relPos = pos - cacheMin; var lin = m_cache.ComputeLinear(ref relPos); var original = m_cache.Content(lin); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove continue; Vector3D spos = (Vector3D)(pos - voxelMap.StorageMin) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var volume = shape.GetVolume(ref spos); if (volume == 0f) // if there is no intersection continue; var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var toRemove = maxRemove;// (int)(maxRemove * voxelMat.DamageRatio); var newVal = Math.Max(original - toRemove, 0);//MathHelper.Clamp(original - toRemove, 0, original-maxRemove); var removed = original - newVal; if (!onlyCheck && !onlyApplyMaterial) m_cache.Content(lin, (byte)newVal); originalSum += original; removedSum += removed; if (readMaterial) voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(lin)); if (exactCutOutMaterials != null) { int value = 0; exactCutOutMaterials.TryGetValue(voxelMat, out value); value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed); exactCutOutMaterials[voxelMat] = value; } if (applyDamageMaterial && voxelMat.HasDamageMaterial && !onlyCheck) m_cache.Material(lin, voxelMat.DamagedMaterialId); } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap, applyDamageMaterial); } ProfilerShort.BeginNextBlock("Write"); if (removedSum > 0 && !onlyCheck) { // Clear all small voxel that may have been created during explosion. They can be created even outside the range of // explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the // explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we // will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove // B voxels too. //!! TODO AR & MK : check if this is needed !! //RemoveSmallVoxelsUsingChachedVoxels(); var dataTypeFlags = applyDamageMaterial ? MyStorageDataTypeFlags.ContentAndMaterial : MyStorageDataTypeFlags.Content; if (MyFakes.LOG_NAVMESH_GENERATION) MyAIComponent.Static.Pathfinding.VoxelPathfinding.DebugLog.LogStorageWrite(voxelMap, m_cache, dataTypeFlags, cacheMin, cacheMax); voxelMap.Storage.WriteRange(m_cache, dataTypeFlags, ref cacheMin, ref cacheMax); } ProfilerShort.End(); voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; shape.Transformation = oldTranmsform; if (removedSum > 0) OnVoxelChanged(OperationType.Cut, voxelMap, shape); ProfilerShort.End(); }