diff --git a/Source/Editor/Content/Import/ModelImportEntry.cs b/Source/Editor/Content/Import/ModelImportEntry.cs index 58e438c46..23a15157a 100644 --- a/Source/Editor/Content/Import/ModelImportEntry.cs +++ b/Source/Editor/Content/Import/ModelImportEntry.cs @@ -163,6 +163,12 @@ namespace FlaxEditor.Content.Import [EditorOrder(90), DefaultValue(ModelLightmapUVsSource.Disable), EditorDisplay("Geometry", "Lightmap UVs Source"), Tooltip("Model lightmap UVs source")] public ModelLightmapUVsSource LightmapUVsSource { get; set; } = ModelLightmapUVsSource.Disable; + /// + /// If specified, all meshes which name starts with this prefix will be imported as a separate collision data (excluded used for rendering). + /// + [EditorOrder(100), DefaultValue(""), EditorDisplay("Geometry")] + public string CollisionMeshesPrefix { get; set; } + /// /// Custom uniform import scale. /// @@ -284,7 +290,7 @@ namespace FlaxEditor.Content.Import /// [EditorOrder(420), DefaultValue(true), EditorDisplay("Materials", "Restore Materials On Reimport"), Tooltip("If checked, the importer will try to restore the assigned materials to the model slots.")] public bool RestoreMaterialsOnReimport { get; set; } = true; - + /// /// If checked, the imported mesh/animations are splitted into separate assets. Used if ObjectIndex is set to -1. /// @@ -314,6 +320,7 @@ namespace FlaxEditor.Content.Import public byte ImportVertexColors; public byte ImportBlendShapes; public ModelLightmapUVsSource LightmapUVsSource; + public string CollisionMeshesPrefix; // Transform public float Scale; @@ -364,6 +371,7 @@ namespace FlaxEditor.Content.Import ImportVertexColors = (byte)(ImportVertexColors ? 1 : 0), ImportBlendShapes = (byte)(ImportBlendShapes ? 1 : 0), LightmapUVsSource = LightmapUVsSource, + CollisionMeshesPrefix = CollisionMeshesPrefix, Scale = Scale, Rotation = Rotation, Translation = Translation, @@ -403,6 +411,7 @@ namespace FlaxEditor.Content.Import ImportVertexColors = options.ImportVertexColors != 0; ImportBlendShapes = options.ImportBlendShapes != 0; LightmapUVsSource = options.LightmapUVsSource; + CollisionMeshesPrefix = options.CollisionMeshesPrefix; Scale = options.Scale; Rotation = options.Rotation; Translation = options.Translation; diff --git a/Source/Editor/Content/Proxy/CollisionDataProxy.cs b/Source/Editor/Content/Proxy/CollisionDataProxy.cs index da82f73c5..c07873189 100644 --- a/Source/Editor/Content/Proxy/CollisionDataProxy.cs +++ b/Source/Editor/Content/Proxy/CollisionDataProxy.cs @@ -86,6 +86,7 @@ namespace FlaxEditor.Content { foreach (var child in modelItem.ParentFolder.Children) { + // Check if there is collision that was made with this model if (child is BinaryAssetItem b && b.IsOfType()) { var collisionData = FlaxEngine.Content.Load(b.ID); @@ -97,6 +98,25 @@ namespace FlaxEditor.Content return; } } + + // Check if there is a auto-imported collision + if (child is ContentFolder childFolder && childFolder.ShortName == modelItem.ShortName) + { + foreach (var childFolderChild in childFolder.Children) + { + if (childFolderChild is BinaryAssetItem c && c.IsOfType()) + { + var collisionData = FlaxEngine.Content.Load(c.ID); + if (collisionData && collisionData.Options.Model == model.ID || collisionData.Options.Model == Guid.Empty) + { + Editor.Instance.Windows.ContentWin.Select(c); + if (created != null) + FlaxEngine.Scripting.InvokeOnUpdate(() => created(collisionData)); + return; + } + } + } + } } } diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp index da04854ec..b02267647 100644 --- a/Source/Editor/Managed/ManagedEditor.Internal.cpp +++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp @@ -166,6 +166,7 @@ struct InternalModelOptions byte ImportVertexColors; byte ImportBlendShapes; ModelLightmapUVsSource LightmapUVsSource; + MonoString* CollisionMeshesPrefix; // Transform float Scale; @@ -212,7 +213,7 @@ struct InternalModelOptions to->ImportLODs = from->ImportLODs; to->ImportVertexColors = from->ImportVertexColors; to->ImportBlendShapes = from->ImportBlendShapes; - to->LightmapUVsSource = from->LightmapUVsSource; + to->CollisionMeshesPrefix = MUtils::ToString(from->CollisionMeshesPrefix); to->Scale = from->Scale; to->Rotation = from->Rotation; to->Translation = from->Translation; @@ -251,6 +252,7 @@ struct InternalModelOptions to->ImportVertexColors = from->ImportVertexColors; to->ImportBlendShapes = from->ImportBlendShapes; to->LightmapUVsSource = from->LightmapUVsSource; + to->CollisionMeshesPrefix = MUtils::ToString(from->CollisionMeshesPrefix); to->Scale = from->Scale; to->Rotation = from->Rotation; to->Translation = from->Translation; diff --git a/Source/Engine/ContentImporters/CreateCollisionData.h b/Source/Engine/ContentImporters/CreateCollisionData.h index 3126cfd56..547a10485 100644 --- a/Source/Engine/ContentImporters/CreateCollisionData.h +++ b/Source/Engine/ContentImporters/CreateCollisionData.h @@ -6,7 +6,9 @@ #if COMPILE_WITH_ASSETS_IMPORTER +#if COMPILE_WITH_PHYSICS_COOKING #include "Engine/Physics/CollisionCooking.h" +#endif /// /// Creating collision data asset utility @@ -23,7 +25,6 @@ public: static CreateAssetResult Create(CreateAssetContext& context); #if COMPILE_WITH_PHYSICS_COOKING - /// /// Cooks the mesh collision data and saves it to the asset using format. /// @@ -31,7 +32,6 @@ public: /// The input argument data. /// True if failed, otherwise false. See log file to track errors better. static bool CookMeshCollision(const String& outputPath, CollisionCooking::Argument& arg); - #endif }; diff --git a/Source/Engine/Graphics/Models/ModelData.cpp b/Source/Engine/Graphics/Models/ModelData.cpp index 4b39cef65..d1e867c6c 100644 --- a/Source/Engine/Graphics/Models/ModelData.cpp +++ b/Source/Engine/Graphics/Models/ModelData.cpp @@ -589,6 +589,17 @@ void MeshData::Merge(MeshData& other) } } +bool MaterialSlotEntry::UsesProperties() const +{ + return Diffuse.Color != Color::White || + Diffuse.TextureIndex != -1 || + Emissive.Color != Color::Transparent || + Emissive.TextureIndex != -1 || + !Math::IsOne(Opacity.Value) || + Opacity.TextureIndex != -1 || + Normals.TextureIndex != -1; +} + void ModelData::CalculateLODsScreenSizes() { const float autoComputeLodPowerBase = 0.5f; diff --git a/Source/Engine/Graphics/Models/ModelData.h b/Source/Engine/Graphics/Models/ModelData.h index 2b99d0c83..4d4733fb7 100644 --- a/Source/Engine/Graphics/Models/ModelData.h +++ b/Source/Engine/Graphics/Models/ModelData.h @@ -373,16 +373,7 @@ struct FLAXENGINE_API MaterialSlotEntry bool TwoSided = false; - bool UsesProperties() const - { - return Diffuse.Color != Color::White || - Diffuse.TextureIndex != -1 || - Emissive.Color != Color::Transparent || - Emissive.TextureIndex != -1 || - !Math::IsOne(Opacity.Value) || - Opacity.TextureIndex != -1 || - Normals.TextureIndex != -1; - } + bool UsesProperties() const; }; /// diff --git a/Source/Engine/Tools/ModelTool/ModelTool.Build.cs b/Source/Engine/Tools/ModelTool/ModelTool.Build.cs index 720527cb0..25f43d98a 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.Build.cs +++ b/Source/Engine/Tools/ModelTool/ModelTool.Build.cs @@ -63,6 +63,7 @@ public class ModelTool : EngineModule options.PrivateDependencies.Add("meshoptimizer"); options.PrivateDependencies.Add("MikkTSpace"); + options.PrivateDependencies.Add("Physics"); options.PublicDefinitions.Add("COMPILE_WITH_MODEL_TOOL"); } diff --git a/Source/Engine/Tools/ModelTool/ModelTool.Options.cpp b/Source/Engine/Tools/ModelTool/ModelTool.Options.cpp index d59563160..2b3620616 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.Options.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.Options.cpp @@ -42,6 +42,7 @@ void ModelTool::Options::Serialize(SerializeStream& stream, const void* otherObj SERIALIZE(ImportVertexColors); SERIALIZE(ImportBlendShapes); SERIALIZE(LightmapUVsSource); + SERIALIZE(CollisionMeshesPrefix); SERIALIZE(Scale); SERIALIZE(Rotation); SERIALIZE(Translation); @@ -79,6 +80,7 @@ void ModelTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifi DESERIALIZE(ImportVertexColors); DESERIALIZE(ImportBlendShapes); DESERIALIZE(LightmapUVsSource); + DESERIALIZE(CollisionMeshesPrefix); DESERIALIZE(Scale); DESERIALIZE(Rotation); DESERIALIZE(Translation); diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp index b18392d7d..f014bd571 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp @@ -16,6 +16,7 @@ #include "Engine/Tools/TextureTool/TextureTool.h" #include "Engine/ContentImporters/AssetsImportingManager.h" #include "Engine/ContentImporters/CreateMaterial.h" +#include "Engine/ContentImporters/CreateCollisionData.h" #include "Editor/Utilities/EditorUtilities.h" #include @@ -562,7 +563,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op materialOptions.Opacity.Texture = data.Textures[material.Opacity.TextureIndex].AssetID; if (material.Normals.TextureIndex != -1) materialOptions.Normals.Texture = data.Textures[material.Normals.TextureIndex].AssetID; - if (material.TwoSided | material.Diffuse.HasAlphaMask) + if (material.TwoSided || material.Diffuse.HasAlphaMask) materialOptions.Info.CullMode = CullMode::TwoSided; if (!Math::IsOne(material.Opacity.Value) || material.Opacity.TextureIndex != -1) materialOptions.Info.BlendMode = MaterialBlendMode::Transparent; @@ -624,6 +625,41 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op } } + // Collision mesh output + if (options.CollisionMeshesPrefix.HasChars()) + { + // Extract collision meshes + ModelData collisionModel; + for (auto& lod : data.LODs) + { + for (int32 i = lod.Meshes.Count() - 1; i >= 0; i--) + { + auto mesh = lod.Meshes[i]; + if (mesh->Name.StartsWith(options.CollisionMeshesPrefix, StringSearchCase::IgnoreCase)) + { + if (collisionModel.LODs.Count() == 0) + collisionModel.LODs.AddOne(); + collisionModel.LODs[0].Meshes.Add(mesh); + lod.Meshes.RemoveAtKeepOrder(i); + if (lod.Meshes.IsEmpty()) + break; + } + } + } + if (collisionModel.LODs.HasItems()) + { + // Create collision + CollisionCooking::Argument arg; + arg.Type = CollisionDataType::TriangleMesh; + arg.OverrideModelData = &collisionModel; + auto assetPath = autoImportOutput / StringUtils::GetFileNameWithoutExtension(path) + TEXT("Collision") ASSET_FILES_EXTENSION_WITH_DOT; + if (CreateCollisionData::CookMeshCollision(assetPath, arg)) + { + LOG(Error, "Failed to create collision mesh."); + } + } + } + // For generated lightmap UVs coordinates needs to be moved so all meshes are in unique locations in [0-1]x[0-1] coordinates space if (options.LightmapUVsSource == ModelLightmapUVsSource::Generate && data.LODs.HasItems() && data.LODs[0].Meshes.Count() > 1) { diff --git a/Source/Engine/Tools/ModelTool/ModelTool.h b/Source/Engine/Tools/ModelTool/ModelTool.h index fc38b8192..6e22b4cd6 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.h +++ b/Source/Engine/Tools/ModelTool/ModelTool.h @@ -177,6 +177,7 @@ public: bool ImportVertexColors = true; bool ImportBlendShapes = false; ModelLightmapUVsSource LightmapUVsSource = ModelLightmapUVsSource::Disable; + String CollisionMeshesPrefix; // Transform float Scale = 1.0f;