/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #pragma once #include #include #include #include #include #include #include #include #include namespace AzPhysics { class CollisionGroup; struct RigidBodyConfiguration; struct StaticRigidBodyConfiguration; struct StaticRigidBody; class Scene; } namespace Physics { class RigidBodyConfiguration; class ColliderConfiguration; class ShapeConfiguration; } namespace PhysX { class Shape; class ActorData; class Material; struct TerrainConfiguration; namespace Pipeline { class MeshAssetData; } // namespace Pipeline namespace Utils { bool CreatePxGeometryFromConfig(const Physics::ShapeConfiguration& shapeConfiguration, physx::PxGeometryHolder& pxGeometry); physx::PxShape* CreatePxShapeFromConfig( const Physics::ColliderConfiguration& colliderConfiguration, const Physics::ShapeConfiguration& shapeConfiguration, AzPhysics::CollisionGroup& assignedCollisionGroup ); AzPhysics::Scene* GetDefaultScene(); //! Creates a PhysX cooked mesh config from the given points. //! //! @param pointList Vector of points to build the mesh from. //! @param scale Scale to be assigned to the cooked mesh. //! @return Either a valid cooked mesh or none if the cooking failed. //! AZStd::optional CreatePxCookedMeshConfiguration(const AZStd::vector& pointList, const AZ::Vector3& scale); //! Returns whether a shape configuration describes a primitive shape such as a box or sphere, as opposed to mesh geometry. bool IsPrimitiveShape(const Physics::ShapeConfiguration& shapeConfig); //! Minimum and maximum values for the level of subdivision used when approximating capsules and spheres with convex meshes. //! The maximum value is chosen so that the number of faces and vertices generated by CreateConvexFromPrimitive will be within //! the limit imposed by PhysX (255). //! @{ constexpr AZ::u8 MinCapsuleSubdivisionLevel = 1; constexpr AZ::u8 MaxCapsuleSubdivisionLevel = 5; //! @} AZStd::optional CreateConvexFromPrimitive( const Physics::ColliderConfiguration& colliderConfig, const Physics::ShapeConfiguration& primitiveShapeConfig, AZ::u8 subdivisionLevel, const AZ::Vector3& scale); // 255 is the hard limit for PhysX number of vertices/faces. Upper bound is set to something sensible and less than this hard limit. constexpr AZ::u8 MinFrustumSubdivisions = 3; constexpr AZ::u8 MaxFrustumSubdivisions = 125; //! Creates the points for a given frustum along the z axis as specified by the supplied arguements. //! //! @param height Height of the frustum. Must be greater than 0. //! @param bottomRadius Radius of bottom cace of frustum. Must be greater than 0 if topRadius is 0, otherwise can be 0. //! @param topRadius Radius of top face of frustum. Must be greater than 0 if bottompRadius is 0, otherwise can be 0. //! @param subdivisionsNumber of angular subdivisions. Must be between 3 and 125 inclusive. //! @return Either a valid point list or none if any of the arguements are invalid. //! AZStd::optional> CreatePointsAtFrustumExtents(float height, float bottomRadius, float topRadius, AZ::u8 subdivisions); AZStd::string ConvexCookingResultToString(physx::PxConvexMeshCookingResult::Enum convexCookingResultCode); AZStd::string TriMeshCookingResultToString(physx::PxTriangleMeshCookingResult::Enum triangleCookingResultCode); bool WriteCookedMeshToFile(const AZStd::string& filePath, const Pipeline::MeshAssetData& assetData); bool WriteCookedMeshToFile(const AZStd::string& filePath, const AZStd::vector& physxData, Physics::CookedMeshShapeConfiguration::MeshType meshType); bool CookConvexToPxOutputStream(const AZ::Vector3* vertices, AZ::u32 vertexCount, physx::PxOutputStream& stream); bool CookTriangleMeshToToPxOutputStream(const AZ::Vector3* vertices, AZ::u32 vertexCount, const AZ::u32* indices, AZ::u32 indexCount, physx::PxOutputStream& stream); bool MeshDataToPxGeometry(physx::PxBase* meshData, physx::PxGeometryHolder &pxGeometry, const AZ::Vector3& scale); //! Returns all connected busIds of the specified type. template AZStd::vector FindConnectedBusIds() { AZStd::vector busIds; BusT::EnumerateHandlers([&busIds](typename BusT::Events* /*handler*/) { busIds.emplace_back(*BusT::GetCurrentBusId()); return true; }); return busIds; } //! Logs a warning message using the names of the entities provided. void WarnEntityNames(const AZStd::vector& entityIds, const char* category, const char* message); //! Logs a warning if there is more than one connected bus of the particular type. template void LogWarningIfMultipleComponents(const char* messageCategroy, const char* messageFormat) { const auto entityIds = FindConnectedBusIds(); if (entityIds.size() > 1) { WarnEntityNames(entityIds, messageCategroy, messageFormat); } } //! Converts collider position and orientation offsets to a transform. AZ::Transform GetColliderLocalTransform(const AZ::Vector3& colliderRelativePosition , const AZ::Quaternion& colliderRelativeRotation); //! Gets the local transform for a collider (the position and rotation relative to its entity). AZ::Transform GetColliderLocalTransform(const AZ::EntityComponentIdPair& idPair); //! Combines collider position and orientation offsets and world transform to a transform. AZ::Transform GetColliderWorldTransform(const AZ::Transform& worldTransform , const AZ::Vector3& colliderRelativePosition , const AZ::Quaternion& colliderRelativeRotation); //! Converts points in a collider's local space to world space positions //! accounting for collider position and orientation offsets. void ColliderPointsLocalToWorld(AZStd::vector& pointsInOut , const AZ::Transform& worldTransform , const AZ::Vector3& colliderRelativePosition , const AZ::Quaternion& colliderRelativeRotation , const AZ::Vector3& nonUniformScale); //! Returns AABB of collider by constructing PxGeometry from collider and shape configuration, //! and invoking physx::PxGeometryQuery::getWorldBounds. //! This function is used only by editor components. AZ::Aabb GetColliderAabb(const AZ::Transform& worldTransform , bool hasNonUniformScale , AZ::u8 subdivisionLevel , const ::Physics::ShapeConfiguration& shapeConfiguration , const ::Physics::ColliderConfiguration& colliderConfiguration); bool TriggerColliderExists(AZ::EntityId entityId); void GetShapesFromAsset(const Physics::PhysicsAssetShapeConfiguration& assetConfiguration, const Physics::ColliderConfiguration& originalColliderConfiguration, bool hasNonUniformScale, AZ::u8 subdivisionLevel, AZStd::vector>& resultingShapes); void GetColliderShapeConfigsFromAsset(const Physics::PhysicsAssetShapeConfiguration& assetConfiguration, const Physics::ColliderConfiguration& originalColliderConfiguration, bool hasNonUniformScale, AZ::u8 subdivisionLevel, AzPhysics::ShapeColliderPairList& resultingColliderShapes); //! Gets the scale from the entity's Transform component. AZ::Vector3 GetTransformScale(AZ::EntityId entityId); //! Returns a vector scale with each element equal to the max element from the entity's Transform component. AZ::Vector3 GetUniformScale(AZ::EntityId entityId); //! Gets the scale from the entity's Non-Uniform Scale component, if it is present. //! Otherwise (1, 1, 1) is returned. AZ::Vector3 GetNonUniformScale(AZ::EntityId entityId); //! Gets the overall scale, taking into account the scale from both the entity's Transform component and the //! Non-Uniform Scale component, if it is present. AZ::Vector3 GetOverallScale(AZ::EntityId entityId); //! Returns defaultValue if the input is infinite or NaN, otherwise returns the input unchanged. const AZ::Vector3& Sanitize(const AZ::Vector3& input, const AZ::Vector3& defaultValue = AZ::Vector3::CreateZero()); AZStd::pair GetPhysXMaterialIndicesFromHeightfieldSamples( const AZStd::vector& samples, const int32_t row, const int32_t col, const int32_t numRows, const int32_t numCols); Physics::HeightfieldShapeConfiguration CreateHeightfieldShapeConfiguration(AZ::EntityId entityId); void SetMaterialsFromHeightfieldProvider(const AZ::EntityId& heightfieldProviderId, Physics::MaterialSelection& materialSelection); namespace Geometry { using PointList = AZStd::vector; //! Generates a list of points on a box. PointList GenerateBoxPoints(const AZ::Vector3& min, const AZ::Vector3& max); //! Generates a list of points on the surface of a sphere. PointList GenerateSpherePoints(float radius); //! Generates a list of points on the surface of a cylinder. PointList GenerateCylinderPoints(float height, float radius); //! Generates vertices and indices representing the provided box geometry void GetBoxGeometry(const physx::PxBoxGeometry& geometry, AZStd::vector& vertices, AZStd::vector& indices); //! Generates vertices and indices representing the provided capsule geometry void GetCapsuleGeometry(const physx::PxCapsuleGeometry& geometry, AZStd::vector& vertices, AZStd::vector& indices, const AZ::u32 stacks, const AZ::u32 slices); //! Generates vertices and indices representing the provided convex mesh geometry void GetConvexMeshGeometry(const physx::PxConvexMeshGeometry& geometry, AZStd::vector& vertices, AZStd::vector& indices); //! Generates vertices and indices representing the provided heightfield geometry, optionally limited to a bounding box void GetHeightFieldGeometry(const physx::PxHeightFieldGeometry& geometry, AZStd::vector& vertices, AZStd::vector& indices, AZ::Aabb* optionalBounds); //! Generates vertices and indices representing the provided sphere geometry and optional stacks and slices void GetSphereGeometry(const physx::PxSphereGeometry& geometry, AZStd::vector& vertices, AZStd::vector& indices, const AZ::u32 stacks, const AZ::u32 slices); //! Generates vertices and indices representing the provided triangle mesh geometry void GetTriangleMeshGeometry(const physx::PxTriangleMeshGeometry& geometry, AZStd::vector& vertices, AZStd::vector& indices); } // namespace Geometry //! Returns the World transform of an entity with scale. //! This can be used if ComputeJointLocalTransform will be invoked with the result as an argument since ComputeJointLocalTransform will remove scale. AZ::Transform GetEntityWorldTransformWithScale(AZ::EntityId entityId); //! Returns the World transform of an entity without scale. AZ::Transform GetEntityWorldTransformWithoutScale(AZ::EntityId entityId); //! Computes the local transform of joint from an entity given the joint's world transform and the entity's world transform. AZ::Transform ComputeJointLocalTransform(const AZ::Transform& jointWorldTransform, const AZ::Transform& entityWorldTransform); //! Computes the world transform of joint given the joint's local transform from an entity and the entity's world transform. AZ::Transform ComputeJointWorldTransform(const AZ::Transform& jointLocalTransform, const AZ::Transform& entityWorldTransform); } // namespace Utils namespace ReflectionUtils { //! Reflect API specific to PhysX physics. Generic physics API should be reflected in Physics::ReflectionUtils::ReflectPhysicsApi. void ReflectPhysXOnlyApi(AZ::ReflectContext* context); } // namespace ReflectionUtils namespace PxActorFactories { AZStd::shared_ptr CreatePxRigidBody(const AzPhysics::RigidBodyConfiguration& configuration); AZStd::shared_ptr CreatePxStaticRigidBody(const AzPhysics::StaticRigidBodyConfiguration& configuration); } // namespace PxActorFactories namespace StaticRigidBodyUtils { bool CanCreateRuntimeComponent(const AZ::Entity& editorEntity); bool TryCreateRuntimeComponent(const AZ::Entity& editorEntity, AZ::Entity& gameEntity); } // namespace StaticRigidBodyComponent } // namespace PhysX