You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/PhysX/Code/Source/Utils.h

269 lines
14 KiB
C++

/*
* 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 <PhysX/ForceRegionComponentBus.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Vector3.h>
#include <AzFramework/Physics/Material.h>
#include <AzFramework/Physics/Shape.h>
#include <AzFramework/Physics/ShapeConfiguration.h>
#include <AzCore/std/optional.h>
#include <PxPhysicsAPI.h>
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<Physics::CookedMeshShapeConfiguration> CreatePxCookedMeshConfiguration(const AZStd::vector<AZ::Vector3>& 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<Physics::CookedMeshShapeConfiguration> 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<AZStd::vector<AZ::Vector3>> 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<AZ::u8>& 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<typename BusT>
AZStd::vector<typename BusT::BusIdType> FindConnectedBusIds()
{
AZStd::vector<typename BusT::BusIdType> 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<AZ::EntityId>& entityIds, const char* category, const char* message);
//! Logs a warning if there is more than one connected bus of the particular type.
template<typename BusT>
void LogWarningIfMultipleComponents(const char* messageCategroy, const char* messageFormat)
{
const auto entityIds = FindConnectedBusIds<BusT>();
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<AZ::Vector3>& 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<AZStd::shared_ptr<Physics::Shape>>& 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<uint8_t, uint8_t> GetPhysXMaterialIndicesFromHeightfieldSamples(
const AZStd::vector<Physics::HeightMaterialPoint>& 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<AZ::Vector3>;
//! 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<AZ::Vector3>& vertices, AZStd::vector<AZ::u32>& indices);
//! Generates vertices and indices representing the provided capsule geometry
void GetCapsuleGeometry(const physx::PxCapsuleGeometry& geometry, AZStd::vector<AZ::Vector3>& vertices, AZStd::vector<AZ::u32>& 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<AZ::Vector3>& vertices, AZStd::vector<AZ::u32>& indices);
//! Generates vertices and indices representing the provided heightfield geometry, optionally limited to a bounding box
void GetHeightFieldGeometry(const physx::PxHeightFieldGeometry& geometry, AZStd::vector<AZ::Vector3>& vertices, AZStd::vector<AZ::u32>& 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<AZ::Vector3>& vertices, AZStd::vector<AZ::u32>& 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<AZ::Vector3>& vertices, AZStd::vector<AZ::u32>& 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<physx::PxRigidDynamic> CreatePxRigidBody(const AzPhysics::RigidBodyConfiguration& configuration);
AZStd::shared_ptr<physx::PxRigidStatic> 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