From e0d8a5be5d57b664efdd7bec2abe7c2c84639448 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 5 Nov 2021 11:49:10 +0100 Subject: [PATCH] Add `CollisionData.GetModelTriangle` to retrieve source geometry triangle index from the raycast hit info --- Source/Engine/Physics/CollisionCooking.cpp | 1 + Source/Engine/Physics/CollisionData.cpp | 48 ++++++++++++++++++++++ Source/Engine/Physics/CollisionData.h | 39 ++++++++++-------- Source/Engine/Physics/Physics.h | 3 +- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/Source/Engine/Physics/CollisionCooking.cpp b/Source/Engine/Physics/CollisionCooking.cpp index 2001fb7fe..18d11b718 100644 --- a/Source/Engine/Physics/CollisionCooking.cpp +++ b/Source/Engine/Physics/CollisionCooking.cpp @@ -366,6 +366,7 @@ bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::Seriali outputOptions.ModelLodIndex = arg.ModelLodIndex; outputOptions.ConvexFlags = arg.ConvexFlags; outputOptions.ConvexVertexLimit = arg.ConvexVertexLimit; + outputOptions.MaterialSlotsMask = arg.MaterialSlotsMask; return false; } diff --git a/Source/Engine/Physics/CollisionData.cpp b/Source/Engine/Physics/CollisionData.cpp index 10dc38e6b..9de47a0f0 100644 --- a/Source/Engine/Physics/CollisionData.cpp +++ b/Source/Engine/Physics/CollisionData.cpp @@ -133,6 +133,53 @@ bool CollisionData::CookCollision(CollisionDataType type, ModelData* modelData, #endif +bool CollisionData::GetModelTriangle(uint32 faceIndex, MeshBase*& mesh, uint32& meshTriangleIndex) const +{ + mesh = nullptr; + meshTriangleIndex = MAX_uint32; + if (!IsLoaded()) + return false; + ScopeLock lock(Locker); + if (_triangleMesh && faceIndex < _triangleMesh->getNbTriangles()) + { + if (const PxU32* remap = _triangleMesh->getTrianglesRemap()) + { + // Get source triangle index from the triangle mesh + meshTriangleIndex = remap[faceIndex]; + + // Check if model was used when cooking + AssetReference model; + model = _options.Model; + if (!model) + return true; + + // Follow code-path similar to CollisionCooking.cpp to pick a mesh that contains this triangle (collision is cooked from merged all source meshes from the model) + if (model->WaitForLoaded()) + return false; + const int32 lodIndex = Math::Clamp(_options.ModelLodIndex, 0, model->GetLODsCount()); + Array meshes; + model->GetMeshes(meshes, lodIndex); + uint32 triangleCounter = 0; + for (int32 meshIndex = 0; meshIndex < meshes.Count(); meshIndex++) + { + MeshBase* m = meshes[meshIndex]; + if ((_options.MaterialSlotsMask & (1 << m->GetMaterialSlotIndex())) == 0) + continue; + const uint32 count = m->GetTriangleCount(); + if (meshTriangleIndex - triangleCounter <= count) + { + mesh = m; + meshTriangleIndex -= triangleCounter; + return true; + } + triangleCounter += count; + } + } + } + + return false; +} + void CollisionData::ExtractGeometry(Array& vertexBuffer, Array& indexBuffer) const { vertexBuffer.Clear(); @@ -298,6 +345,7 @@ CollisionData::LoadResult CollisionData::load(const SerializedOptions* options, _options.ModelLodIndex = options->ModelLodIndex; _options.ConvexFlags = options->ConvexFlags; _options.ConvexVertexLimit = options->ConvexVertexLimit < 4 ? 255 : options->ConvexVertexLimit; + _options.MaterialSlotsMask = options->MaterialSlotsMask == 0 ? MAX_uint32 : options->MaterialSlotsMask; // Load data (rest of the chunk is a cooked collision data) if (_options.Type == CollisionDataType::None && dataSize > 0) diff --git a/Source/Engine/Physics/CollisionData.h b/Source/Engine/Physics/CollisionData.h index b0cf9b9ba..e95f73c77 100644 --- a/Source/Engine/Physics/CollisionData.h +++ b/Source/Engine/Physics/CollisionData.h @@ -8,6 +8,7 @@ class Model; class ModelBase; class ModelData; +class MeshBase; namespace physx { @@ -104,42 +105,37 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(CollisionDataOptions); /// /// The data type. /// - API_FIELD() CollisionDataType Type; + API_FIELD() CollisionDataType Type = CollisionDataType::None; /// /// The source model asset id. /// - API_FIELD() Guid Model; + API_FIELD() Guid Model = Guid::Empty; /// /// The source model LOD index. /// - API_FIELD() int32 ModelLodIndex; + API_FIELD() int32 ModelLodIndex = 0; /// /// The cooked collision bounds. /// - API_FIELD() BoundingBox Box; + API_FIELD() BoundingBox Box = BoundingBox::Zero; /// /// The convex generation flags. /// - API_FIELD() ConvexMeshGenerationFlags ConvexFlags; + API_FIELD() ConvexMeshGenerationFlags ConvexFlags = ConvexMeshGenerationFlags::None; /// /// The convex vertices limit (maximum amount). /// - API_FIELD() int32 ConvexVertexLimit; + API_FIELD() int32 ConvexVertexLimit = 0; - CollisionDataOptions() - { - Type = CollisionDataType::None; - Model = Guid::Empty; - ModelLodIndex = 0; - Box = BoundingBox::Zero; - ConvexFlags = ConvexMeshGenerationFlags::None; - ConvexVertexLimit = 0; - } + /// + /// The source model material slots mask. One bit per-slot. Can be used to exclude particular material slots from collision cooking. + /// + API_FIELD() uint32 MaterialSlotsMask = MAX_uint32; }; /// @@ -160,7 +156,8 @@ public: int32 ModelLodIndex; ConvexMeshGenerationFlags ConvexFlags; int32 ConvexVertexLimit; - byte Padding[96]; + uint32 MaterialSlotsMask; + byte Padding[92]; }; static_assert(sizeof(SerializedOptions) == 128, "Invalid collision data options size. Change the padding."); @@ -259,6 +256,16 @@ public: #endif + /// + /// Extracts the triangle index of the original mesh data used for cooking this collision data. Can be used to get vertex attributes of the triangle mesh hit by the raycast. + /// + /// Supported only for collision data built as triangle mesh and without flag set. + /// The face index of the collision mesh. + /// The result source mesh used to build this collision data (can be null if collision data was cooked using custom geometry without source Model set). + /// The result triangle index of the source geometry used to build this collision data. + /// True if got a valid triangle index, otherwise false. + API_FUNCTION() bool GetModelTriangle(uint32 faceIndex, API_PARAM(Out) MeshBase*& mesh, API_PARAM(Out) uint32& meshTriangleIndex) const; + /// /// Extracts the collision data geometry into list of triangles. /// diff --git a/Source/Engine/Physics/Physics.h b/Source/Engine/Physics/Physics.h index 7fc21c16f..96048b829 100644 --- a/Source/Engine/Physics/Physics.h +++ b/Source/Engine/Physics/Physics.h @@ -23,7 +23,7 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit); /// /// The collider that was hit. /// - API_FIELD() PhysicsColliderActor* Collider; + API_FIELD() PhysicsColliderActor* Collider = nullptr; /// /// The normal of the surface the ray hit. @@ -43,6 +43,7 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit); /// /// The index of the face that was hit. Valid only for convex mesh (polygon index), triangle mesh (triangle index) and height field (triangle index). /// + /// API_FIELD() uint32 FaceIndex; ///