public void AllocateForDefinition(string model, MyPhysicalModelDefinition definition, int count) { if (string.IsNullOrEmpty(model)) return; ProfilerShort.Begin("Clone"); var data = MyModels.GetModelOnlyData(model); if (MyFakes.LAZY_LOAD_DESTRUCTION && data.HavokBreakableShapes == null) { MyDestructionData.Static.LoadModelDestruction(model, definition, data.BoundingBoxSize); } if (data.HavokBreakableShapes != null && data.HavokBreakableShapes.Length > 0) { if (!m_pools.ContainsKey(definition.Id)) m_pools[definition.Id] = new Dictionary<string, ConcurrentQueue<HkdBreakableShape>>(); if(!m_pools[definition.Id].ContainsKey(model)) m_pools[definition.Id][model] = new ConcurrentQueue<HkdBreakableShape>(); var queue = m_pools[definition.Id][model]; for (int i = 0; i < count; i++) { var shape = data.HavokBreakableShapes[0].Clone(); queue.Enqueue(shape); if (i == 0) { var mp = new HkMassProperties(); shape.BuildMassProperties(ref mp); if (!mp.InertiaTensor.IsValid()) { MyLog.Default.WriteLine(string.Format("Block with wrong destruction! (q.isOk): {0}", definition.Model)); break; } } } } ProfilerShort.End(); }
public short GetModelId(MyPhysicalModelDefinition def) { short id; if (!m_physicalModelToKey.TryGetValue(def, out id)) { id = (short)m_physicalModels.Count; m_physicalModelToKey.Add(def, id); m_physicalModels.Add(def); } return id; }
public static MyPhysicalMaterialDefinition GetPhysicalMaterial(MyPhysicalModelDefinition modelDef, string physicalMaterial) { if (m_physicalMaterials == null) { m_physicalMaterials = new Dictionary<string, MyPhysicalMaterialDefinition>(); foreach (var physMat in MyDefinitionManager.Static.GetPhysicalMaterialDefinitions()) { m_physicalMaterials.Add(physMat.Id.SubtypeName, physMat); } m_physicalMaterials["Default"] = new MyPhysicalMaterialDefinition() { Density = 1920, HorisontalTransmissionMultiplier = 1, HorisontalFragility = 2, CollisionMultiplier = 1.4f, SupportMultiplier = 1.5f }; } if(MyPerGameSettings.Destruction == false) { return m_physicalMaterials["Default"]; } if (!string.IsNullOrEmpty(physicalMaterial)) { if (m_physicalMaterials.ContainsKey(physicalMaterial)) return m_physicalMaterials[physicalMaterial]; else { string s = "ERROR: Physical material " + physicalMaterial + " does not exist!"; System.Diagnostics.Debug.Fail(s); MyLog.Default.WriteLine(s); } } //MyLog.Default.WriteLine("WARNING: " + modelDef.Id.SubtypeName + " has no physical material specified, trying to autodetect from name"); if (modelDef.Id.SubtypeName.Contains("Stone")) { return m_physicalMaterials["Stone"]; } if (modelDef.Id.SubtypeName.Contains("Wood")) { return m_physicalMaterials["Wood"]; } if (modelDef.Id.SubtypeName.Contains("Timber")) { return m_physicalMaterials["Wood"]; } //MyLog.Default.WriteLine("WARNING: Unable to find proper physical material for " + modelDef.Id.SubtypeName + ", using Default"); return m_physicalMaterials["Default"]; }
public void LoadModelDestruction(string modelName, MyPhysicalModelDefinition modelDef, bool dontCreateFracturePieces, Vector3 defaultSize, bool destructionRequired = true, bool useShapeVolume = false) { var model = MyModels.GetModelOnlyData(modelName); var material = modelDef.PhysicalMaterial; //var shapeName = modelDef.Id.SubtypeName; var shapeName = modelName; if (model != null) { bool forceCollisionsInsteadDestruction = false; //if (model.AssetName.Contains("StoneBattlementAdvancedStraightTop")) //{ //} model.LoadUV = true; HkdBreakableShape bShape; bool createPieceData = false; bool recalculateMass = false; bool registerShape = false; //TODO: Dynamic fracturing is workaround. We need to find the way how to serialize fractured model directly into hkt // and then load it from BreakableShapes. if (model.ModelFractures != null) { if (model.HavokCollisionShapes != null && model.HavokCollisionShapes.Length > 0) { CreateBreakableShapeFromCollisionShapes(model, defaultSize, modelDef); var physicsMesh = CreatePhysicsMesh(model); Storage.RegisterShapeWithGraphics(physicsMesh, model.HavokBreakableShapes[0], shapeName); string modPath = null; if (Path.IsPathRooted(model.AssetName)) modPath = model.AssetName.Remove(model.AssetName.LastIndexOf("Models")); FractureBreakableShape(model.HavokBreakableShapes[0], model.ModelFractures, modPath); recalculateMass = true; registerShape = true; createPieceData = true; } } else if (model.HavokDestructionData != null && !forceCollisionsInsteadDestruction) { try { //string dump = Storage.DumpDestructionData(model.HavokDestructionData); if (model.HavokBreakableShapes == null) //models are cached between sessions { model.HavokBreakableShapes = Storage.LoadDestructionDataFromBuffer(model.HavokDestructionData); createPieceData = true; recalculateMass = true; registerShape = true; } } catch { model.HavokBreakableShapes = null; } } model.HavokDestructionData = null; //we dont need to hold the byte data after loading shape model.HavokData = null; if (model.HavokBreakableShapes == null && destructionRequired) { MyLog.Default.WriteLine(model.AssetName + " does not have destruction data"); CreateBreakableShapeFromCollisionShapes(model, defaultSize, modelDef); recalculateMass = true; registerShape = true; if (MyFakes.SHOW_MISSING_DESTRUCTION && destructionRequired) { //Show missing destructions in pink VRageRender.MyRenderProxy.ChangeModelMaterial(model.AssetName, "Debug"); } } if (model.HavokBreakableShapes == null) { MyLog.Default.WriteLine(string.Format("Model {0} - Unable to load havok destruction data", model.AssetName), LoggingOptions.LOADING_MODELS); return; } System.Diagnostics.Debug.Assert(model.HavokBreakableShapes.Length > 0, "Incomplete destruction data"); bShape = model.HavokBreakableShapes[0]; //bShape.GetChildren(m_tmpChildrenList); //if (m_tmpChildrenList.Count == 0) // bShape.UserObject = (uint)HkdBreakableShape.Flags.FRACTURE_PIECE; if (dontCreateFracturePieces) bShape.SetFlagRecursively(HkdBreakableShape.Flags.DONT_CREATE_FRACTURE_PIECE); //m_tmpChildrenList.Clear(); if (registerShape) { bShape.AddReference(); Storage.RegisterShape( bShape, shapeName ); } // Necessary, otherwise materials on fractures would be missing VRageRender.MyRenderProxy.PreloadMaterials(model.AssetName); if (createPieceData) CreatePieceData(model, bShape); if (recalculateMass) { var volume = bShape.CalculateGeometryVolume(); if (volume <= 0 || useShapeVolume) volume = bShape.Volume; var realMass = volume * material.Density; System.Diagnostics.Debug.Assert(realMass > 0, "Invalid mass data"); bShape.SetMassRecursively(MyDestructionHelper.MassToHavok(realMass)); } if(modelDef.Mass > 0) { bShape.SetMassRecursively(MyDestructionHelper.MassToHavok(modelDef.Mass)); } //Debug.Assert(CheckVolumeMassRec(bShape, 0.00001f, 0.01f), "Low volume or mass." + bShape.Name); DisableRefCountRec(bShape); if (MyFakes.LAZY_LOAD_DESTRUCTION) BlockShapePool.AllocateForDefinition(shapeName, modelDef, MyBlockShapePool.PREALLOCATE_COUNT); } else { //No armor in ME! } }
void CreateBreakableShapeFromCollisionShapes(MyModel model, Vector3 defaultSize, MyPhysicalModelDefinition modelDef) { // Make box half edge length of the grid so fractured block is smaller than not fractured, also good for compounds HkShape shape; if (model.HavokCollisionShapes != null && model.HavokCollisionShapes.Length > 0) { if (model.HavokCollisionShapes.Length > 1) { shape = HkListShape.Create(model.HavokCollisionShapes, model.HavokCollisionShapes.Length, HkReferencePolicy.None); } else { shape = model.HavokCollisionShapes[0]; shape.AddReference(); } } else { //modelDef.Size * (modelDef.CubeSize == MyCubeSize.Large ? 2.5f : 0.25f) shape = new HkBoxShape(defaultSize * 0.5f, MyPerGameSettings.PhysicsConvexRadius); } var boxBreakable = new HkdBreakableShape(shape); boxBreakable.Name = model.AssetName; boxBreakable.SetMass(modelDef.Mass); model.HavokBreakableShapes = new HkdBreakableShape[] { boxBreakable }; shape.RemoveReference(); }