// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Content/BinaryAsset.h" #include "Engine/Core/Math/BoundingBox.h" #include "Engine/Physics/Types.h" class Model; class ModelData; /// /// A storage data type. /// API_ENUM() enum class CollisionDataType { /// /// Nothing. /// None = 0, /// /// A convex polyhedron represented as a set of vertices and polygonal faces. The number of vertices and faces of a convex mesh is limited to 255. /// ConvexMesh = 1, /// /// A collision triangle mesh consists of a collection of vertices and the triangle indices. /// TriangleMesh = 2, }; /// /// Set of flags used to generate model convex mesh. Allows to customize process. /// API_ENUM(Attributes="Flags") enum class ConvexMeshGenerationFlags { /// /// Nothing. /// None = 0, /// /// Disables the convex mesh validation to speed-up hull creation. /// Creating a convex mesh with invalid input data without prior validation /// may result in undefined behavior. /// SkipValidation = 1, /// /// Enables plane shifting vertex limit algorithm. /// /// Plane shifting is an alternative algorithm for the case when the computed hull has more vertices /// than the specified vertex limit. /// /// The default algorithm computes the full hull, and an OBB around the input vertices. This OBB is then sliced /// with the hull planes until the vertex limit is reached. The default algorithm requires the vertex limit /// to be set to at least 8, and typically produces results that are much better quality than are produced /// by plane shifting. /// /// When plane shifting is enabled, the hull computation stops when vertex limit is reached.The hull planes /// are then shifted to contain all input vertices, and the new plane intersection points are then used to /// generate the final hull with the given vertex limit.Plane shifting may produce sharp edges to vertices /// very far away from the input cloud, and does not guarantee that all input vertices are inside the resulting /// hull. However, it can be used with a vertex limit as low as 4. /// UsePlaneShifting = 2, /// /// Inertia tensor computation is faster using SIMD code, but the precision is lower, which may result /// in incorrect inertia for very thin hulls. /// UseFastInteriaComputation = 4, /// /// Convex hull input vertices are shifted to be around origin to provide better computation stability. /// It is recommended to provide input vertices around the origin, otherwise use this flag to improve /// numerical stability. /// ShiftVertices = 8, }; DECLARE_ENUM_OPERATORS(ConvexMeshGenerationFlags); /// /// The collision data asset cooking options. /// API_STRUCT() struct CollisionDataOptions { DECLARE_SCRIPTING_TYPE_NO_SPAWN(CollisionDataOptions); /// /// The data type. /// API_FIELD() CollisionDataType Type; /// /// The source model asset id. /// API_FIELD() Guid Model; /// /// The source model LOD index. /// API_FIELD() int32 ModelLodIndex; /// /// The cooked collision bounds. /// API_FIELD() BoundingBox Box; /// /// The convex generation flags. /// API_FIELD() ConvexMeshGenerationFlags ConvexFlags; /// /// The convex vertices limit (maximum amount). /// API_FIELD() int32 ConvexVertexLimit; CollisionDataOptions() { Type = CollisionDataType::None; Model = Guid::Empty; ModelLodIndex = 0; Box = BoundingBox::Zero; ConvexFlags = ConvexMeshGenerationFlags::None; ConvexVertexLimit = 0; } }; /// /// Represents a physics mesh that can be used with a MeshCollider. Physics mesh can be a generic triangle mesh or a convex mesh. /// API_CLASS(NoSpawn) class FLAXENGINE_API CollisionData : public BinaryAsset { DECLARE_BINARY_ASSET_HEADER(CollisionData, 1); public: /// /// A raw structure stored in the binary asset. It has fixed size so it's easier to add new parameters to it. It's loaded and changed into Options structure used at runtime. /// struct SerializedOptions { CollisionDataType Type; Guid Model; int32 ModelLodIndex; ConvexMeshGenerationFlags ConvexFlags; int32 ConvexVertexLimit; byte Padding[96]; }; static_assert(sizeof(SerializedOptions) == 128, "Invalid collision data options size. Change the padding."); private: CollisionDataOptions _options; PxConvexMesh* _convexMesh; PxTriangleMesh* _triangleMesh; public: /// /// Gets the options. /// /// The options. API_PROPERTY() FORCE_INLINE const CollisionDataOptions& GetOptions() const { return _options; } /// /// Gets the convex mesh object (valid only if asset is loaded and has cooked convex data). /// /// The convex mesh FORCE_INLINE PxConvexMesh* GetConvex() const { return _convexMesh; } /// /// Gets the triangle mesh object (valid only if asset is loaded and has cooked triangle data). /// /// The triangle mesh FORCE_INLINE PxTriangleMesh* GetTriangle() const { return _triangleMesh; } public: #if COMPILE_WITH_PHYSICS_COOKING /// /// Cooks the mesh collision data and updates the virtual asset. action cannot be performed on a main thread. /// /// /// Can be used only for virtual assets (see and ). /// /// The collision data type. /// The source model. /// The source model LOD index. /// The convex mesh generation flags. /// The convex mesh vertex limit. Use values in range [8;255] API_FUNCTION() bool CookCollision(CollisionDataType type, Model* model, int32 modelLodIndex = 0, ConvexMeshGenerationFlags convexFlags = ConvexMeshGenerationFlags::None, int32 convexVertexLimit = 255); /// /// Cooks the mesh collision data and updates the virtual asset. action cannot be performed on a main thread. /// /// /// Can be used only for virtual assets (see and ). /// /// The collision data type. /// The source geometry vertex buffer with vertices positions. Cannot be empty. /// The source data index buffer (triangles list). Uses 32-bit stride buffer. Cannot be empty. Length must be multiple of 3 (as 3 vertices build a triangle). /// The convex mesh generation flags. /// The convex mesh vertex limit. Use values in range [8;255] API_FUNCTION() bool CookCollision(CollisionDataType type, const Span& vertices, const Span& triangles, ConvexMeshGenerationFlags convexFlags = ConvexMeshGenerationFlags::None, int32 convexVertexLimit = 255); /// /// Cooks the mesh collision data and updates the virtual asset. action cannot be performed on a main thread. /// /// /// Can be used only for virtual assets (see and ). /// /// The collision data type. /// The custom geometry. /// The convex mesh generation flags. /// The convex mesh vertex limit. Use values in range [8;255] bool CookCollision(CollisionDataType type, ModelData* modelData, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit); #endif /// /// Extracts the collision data geometry into list of triangles. /// /// The output vertex buffer. /// The output index buffer. API_FUNCTION() void ExtractGeometry(API_PARAM(Out) Array& vertexBuffer, API_PARAM(Out) Array& indexBuffer) const; public: // MeshCollider is drawing debug view of the collision data, allow to share it across instances #if USE_EDITOR private: bool _hasMissingDebugLines = true; Array _debugLines; public: const Array& GetDebugLines(); #endif private: LoadResult load(const SerializedOptions* options, byte* dataPtr, int32 dataSize); protected: // [BinaryAsset] LoadResult load() override; void unload(bool isReloading) override; AssetChunksFlag getChunksToPreload() const override; };