1f9b284de2
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> # Conflicts: # Code/Editor/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin_precompiled.h # Code/Editor/Plugins/EditorCommon/EditorCommon_precompiled.h # Code/Editor/Plugins/EditorCommon/stdafx.cpp # Code/Editor/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.h # Code/Editor/Plugins/PerforcePlugin/PerforcePlugin_precompiled.h # Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsTool_precompiled.h # Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFramework_precompiled.h # Code/Tools/AssetProcessor/native/precompiled.h # Code/Tools/Standalone/StandaloneTools_precompiled.h # Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer_precompiled.h # Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessing_precompiled.h # Gems/Atom/RHI/DX12/Code/Source/RHI/Atom_RHI_DX12_precompiled.h # Gems/Atom/RHI/Metal/Code/Include/Platform/Mac/Atom_RHI_Metal_precompiled_Platform.h # Gems/Atom/RHI/Metal/Code/Include/Platform/iOS/Atom_RHI_Metal_precompiled_Platform.h # Gems/Atom/RHI/Metal/Code/Source/Atom_RHI_Metal_precompiled.h # Gems/Atom/RHI/Metal/Code/atom_rhi_metal_common_files.cmake # Gems/Atom/RHI/Null/Code/Source/Atom_RHI_Null_precompiled.h # Gems/Atom/RHI/Null/Code/atom_rhi_null_common_files.cmake # Gems/Atom/RHI/Vulkan/Code/Include/Platform/Android/Atom_RHI_Vulkan_precompiled_Platform.h # Gems/Atom/RHI/Vulkan/Code/Include/Platform/Linux/Atom_RHI_Vulkan_precompiled_Platform.h # Gems/Atom/RHI/Vulkan/Code/Include/Platform/Mac/Atom_RHI_Vulkan_precompiled_Platform.h # Gems/Atom/RHI/Vulkan/Code/Include/Platform/Windows/Atom_RHI_Vulkan_precompiled_Platform.h # Gems/Atom/RHI/Vulkan/Code/Source/Atom_RHI_Vulkan_precompiled.h # Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp # Gems/Atom/RHI/Vulkan/Code/atom_rhi_vulkan_common_files.cmake # Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont_precompiled.h # Gems/Blast/Code/Source/StdAfx.cpp # Gems/Camera/Code/Source/Camera_precompiled.h # Gems/EMotionFX/Code/Source/EMotionFX_precompiled.h # Gems/FastNoise/Code/Source/FastNoise_precompiled.h # Gems/Gestures/Code/Source/Gestures_precompiled.h # Gems/GradientSignal/Code/Source/GradientSignal_precompiled.h # Gems/GraphCanvas/Code/precompiled.h # Gems/ImGui/Code/Source/ImGui_precompiled.h # Gems/InAppPurchases/Code/Source/InAppPurchases_precompiled.h # Gems/LmbrCentral/Code/Source/LmbrCentral_precompiled.h # Gems/LmbrCentral/Code/Tests/ShapeGeometryUtilTest.cpp # Gems/LyShine/Code/Editor/UiCanvasEditor_precompiled.h # Gems/LyShine/Code/Source/Animation/LyShine_precompiled.h # Gems/LyShine/Code/Source/LyShine_precompiled.h # Gems/LyShineExamples/Code/Source/LyShineExamples_precompiled.h # Gems/Maestro/Code/Source/Cinematics/Maestro_precompiled.h # Gems/Maestro/Code/Source/Maestro_precompiled.h # Gems/MessagePopup/Code/Source/MessagePopup_precompiled.h # Gems/Metastream/Code/Source/Metastream_precompiled.h # Gems/Microphone/Code/Source/Microphone_precompiled.h # Gems/Multiplayer/Code/Source/Multiplayer_precompiled.h # Gems/PhysX/Code/NumericalMethods/Source/NumericalMethods_precompiled.h # Gems/PhysX/Code/Source/PhysXUnsupported_precompiled.h # Gems/PhysX/Code/Source/PhysX_precompiled.h # Gems/PhysX/Code/physx_unsupported_files.cmake # Gems/PhysXDebug/Code/Source/PhysXDebugUnsupported_precompiled.h # Gems/PhysXDebug/Code/Source/PhysXDebug_precompiled.h # Gems/ScriptCanvas/Code/Editor/precompiled.h # Gems/ScriptCanvas/Code/Source/precompiled.h # Gems/ScriptCanvasDeveloper/Code/Source/precompiled.h # Gems/ScriptCanvasPhysics/Code/Source/ScriptCanvasPhysics_precompiled.h # Gems/ScriptEvents/Code/Source/precompiled.h # Gems/ScriptEvents/Code/Tests/Editor/EditorTests.cpp # Gems/ScriptedEntityTweener/Code/Source/ScriptedEntityTweener_precompiled.h # Gems/SliceFavorites/Code/Source/SliceFavorites_precompiled.h # Gems/StartingPointCamera/Code/Source/StartingPointCamera_precompiled.h # Gems/StartingPointInput/Code/Source/StartingPointInput_precompiled.h # Gems/StartingPointMovement/Code/Source/StartingPointMovement_precompiled.h # Gems/SurfaceData/Code/Source/SurfaceData_precompiled.h # Gems/TextureAtlas/Code/Source/TextureAtlas_precompiled.h # Gems/TickBusOrderViewer/Code/Source/TickBusOrderViewer_precompiled.h # Gems/Twitch/Code/Source/Twitch_precompiled.h # Gems/VirtualGamepad/Code/Source/VirtualGamepad_precompiled.h # Gems/WhiteBox/Code/Source/WhiteBoxUnsupported_precompiled.h # Gems/WhiteBox/Code/Source/WhiteBox_precompiled.h
443 lines
15 KiB
C++
443 lines
15 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
|
|
*
|
|
*/
|
|
|
|
#include <algorithm>
|
|
|
|
#include <AzCore/std/algorithm.h>
|
|
#include <AzCore/std/smart_ptr/make_shared.h>
|
|
|
|
#include <Source/Pipeline/PrimitiveShapeFitter/AbstractShapeParameterization.h>
|
|
|
|
namespace PhysX::Pipeline
|
|
{
|
|
// Implementation of the abstract shape class for spheres.
|
|
class SphereParameterization
|
|
: public AbstractShapeParameterization
|
|
{
|
|
public:
|
|
SphereParameterization(
|
|
const Vector& origin,
|
|
[[maybe_unused]] const Vector& xAxis,
|
|
[[maybe_unused]] const Vector& yAxis,
|
|
[[maybe_unused]] const Vector& zAxis,
|
|
const Vector& halfRanges
|
|
)
|
|
: m_origin(origin)
|
|
, m_radius((halfRanges[0] + halfRanges[1] + halfRanges[2]) / 3.0)
|
|
{
|
|
}
|
|
|
|
AZ::u32 GetDegreesOfFreedom() const override
|
|
{
|
|
return 4;
|
|
}
|
|
|
|
AZStd::vector<double> PackArguments() const override
|
|
{
|
|
// The parameters will be packed as follows:
|
|
// [ originVector ] [ radius ]
|
|
// 0 2 3 3
|
|
//
|
|
// Where:
|
|
// - originVector is m_origin
|
|
// - radius is m_radius
|
|
|
|
AZStd::vector<double> args;
|
|
args.reserve(GetDegreesOfFreedom());
|
|
|
|
args.insert(args.end(), m_origin.begin(), m_origin.end());
|
|
args.insert(args.end(), m_radius);
|
|
|
|
return args;
|
|
}
|
|
|
|
void UnpackArguments(const AZStd::vector<double>& args) override
|
|
{
|
|
auto it = args.begin();
|
|
|
|
std::copy_n(it, 3, m_origin.begin());
|
|
it += 3;
|
|
|
|
m_radius = fabs(*it);
|
|
}
|
|
|
|
double GetVolume() const override
|
|
{
|
|
return FourThirdsPi * m_radius * m_radius * m_radius;
|
|
}
|
|
|
|
double SquaredDistanceToShape(const Vector& vertex) const override
|
|
{
|
|
// Get the vector from the origin to the given vertex, compute its length and subtract the radius.
|
|
const double distanceToShape = Norm(vertex - m_origin) - m_radius;
|
|
return distanceToShape * distanceToShape;
|
|
}
|
|
|
|
MeshAssetData::ShapeConfigurationPair GetShapeConfigurationPair() const override
|
|
{
|
|
MeshAssetData::ShapeConfigurationPair result(nullptr, nullptr);
|
|
|
|
// Don't return a shape if the sphere is too small.
|
|
if (IsAbsoluteValueWithinEpsilon(m_radius))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
// Create shape.
|
|
result.second = AZStd::make_shared<Physics::SphereShapeConfiguration>((float)m_radius);
|
|
|
|
// Create transform.
|
|
result.first = AZStd::make_shared<AssetColliderConfiguration>();
|
|
result.first->m_transform = AZ::Transform::CreateTranslation(VecToAZVec3(m_origin));
|
|
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
Vector m_origin;
|
|
double m_radius;
|
|
};
|
|
|
|
// Implementation of the abstract shape class for boxes.
|
|
class BoxParameterization
|
|
: public AbstractShapeParameterization
|
|
{
|
|
public:
|
|
BoxParameterization(
|
|
const Vector& origin,
|
|
const Vector& xAxis,
|
|
const Vector& yAxis,
|
|
const Vector& zAxis,
|
|
const Vector& halfRanges
|
|
)
|
|
: m_origin(origin)
|
|
, m_xAxis(xAxis)
|
|
, m_yAxis(yAxis)
|
|
, m_zAxis(zAxis)
|
|
, m_xHalfLength(halfRanges[0])
|
|
, m_yHalfLength(halfRanges[1])
|
|
, m_zHalfLength(halfRanges[2])
|
|
{
|
|
}
|
|
|
|
AZ::u32 GetDegreesOfFreedom() const override
|
|
{
|
|
return 9;
|
|
}
|
|
|
|
AZStd::vector<double> PackArguments() const override
|
|
{
|
|
// The parameters will be packed as follows:
|
|
// [ originVector ] [ eulerAngles ] [ xHalfLenght ] [ yHalfLenght ] [ zHalfLenght ]
|
|
// 0 2 3 5 6 6 7 7 8 8
|
|
//
|
|
// Where:
|
|
// - originVector is m_origin
|
|
// - eulerAngles are the three Euler angles that describe the rotation of the box
|
|
// - xHalfLenght is m_xHalfLength
|
|
// - yHalfLenght is m_yHalfLength
|
|
// - zHalfLenght is m_zHalfLength
|
|
|
|
AZStd::vector<double> args;
|
|
args.reserve(GetDegreesOfFreedom());
|
|
|
|
args.insert(args.end(), m_origin.begin(), m_origin.end());
|
|
|
|
const Vector eulerAngles = RotationMatrixToEulerAngles(m_xAxis, m_yAxis, m_zAxis);
|
|
args.insert(args.end(), eulerAngles.begin(), eulerAngles.end());
|
|
|
|
args.insert(args.end(), m_xHalfLength);
|
|
args.insert(args.end(), m_yHalfLength);
|
|
args.insert(args.end(), m_zHalfLength);
|
|
|
|
return args;
|
|
}
|
|
|
|
void UnpackArguments(const AZStd::vector<double>& args) override
|
|
{
|
|
auto it = args.begin();
|
|
|
|
std::copy_n(it, 3, m_origin.begin());
|
|
it += 3;
|
|
|
|
Vector eulerAngles{{0.0, 0.0, 0.0}};
|
|
std::copy_n(it, 3, eulerAngles.begin());
|
|
m_xAxis = EulerAnglesToBasisX(eulerAngles);
|
|
m_yAxis = EulerAnglesToBasisY(eulerAngles);
|
|
m_zAxis = EulerAnglesToBasisZ(eulerAngles);
|
|
it += 3;
|
|
|
|
m_xHalfLength = fabs(*(it++));
|
|
m_yHalfLength = fabs(*(it++));
|
|
m_zHalfLength = fabs(*it);
|
|
}
|
|
|
|
double GetVolume() const override
|
|
{
|
|
return 8.0 * m_xHalfLength * m_yHalfLength * m_zHalfLength;
|
|
}
|
|
|
|
double SquaredDistanceToShape(const Vector& vertex) const override
|
|
{
|
|
// Convert the coordinates of the vertex to box space. Due to symmetry we can take the absolute value of the
|
|
// coordinates.
|
|
const Vector vertexInBoxSpace{{
|
|
fabs(Dot(vertex - m_origin, m_xAxis)),
|
|
fabs(Dot(vertex - m_origin, m_yAxis)),
|
|
fabs(Dot(vertex - m_origin, m_zAxis)),
|
|
}};
|
|
|
|
if (
|
|
vertexInBoxSpace[0] < m_xHalfLength &&
|
|
vertexInBoxSpace[1] < m_yHalfLength &&
|
|
vertexInBoxSpace[2] < m_zHalfLength
|
|
)
|
|
{
|
|
// The point is inside the box.
|
|
const double distanceToXFace = m_xHalfLength - vertexInBoxSpace[0];
|
|
const double distanceToYFace = m_yHalfLength - vertexInBoxSpace[1];
|
|
const double distanceToZFace = m_zHalfLength - vertexInBoxSpace[2];
|
|
|
|
const double distanceToShape = std::min({distanceToXFace, distanceToYFace, distanceToZFace});
|
|
return distanceToShape * distanceToShape;
|
|
}
|
|
else
|
|
{
|
|
// The closest point on the box is the one where we clamp the vertex's coordinates at the box boundary.
|
|
const Vector closestPointOnBox = {{
|
|
AZStd::clamp(vertexInBoxSpace[0], 0.0, m_xHalfLength),
|
|
AZStd::clamp(vertexInBoxSpace[1], 0.0, m_yHalfLength),
|
|
AZStd::clamp(vertexInBoxSpace[2], 0.0, m_zHalfLength)
|
|
}};
|
|
|
|
return NormSquared(vertexInBoxSpace - closestPointOnBox);
|
|
}
|
|
}
|
|
|
|
MeshAssetData::ShapeConfigurationPair GetShapeConfigurationPair() const override
|
|
{
|
|
MeshAssetData::ShapeConfigurationPair result(nullptr, nullptr);
|
|
|
|
// Don't return a shape if the box is too small or not well-shaped.
|
|
if (
|
|
IsAbsoluteValueWithinEpsilon(m_xHalfLength) ||
|
|
IsAbsoluteValueWithinEpsilon(m_yHalfLength) ||
|
|
IsAbsoluteValueWithinEpsilon(m_zHalfLength) ||
|
|
!IsAbsolueValueRatioWithinThreshold(m_xHalfLength, m_yHalfLength) ||
|
|
!IsAbsolueValueRatioWithinThreshold(m_xHalfLength, m_zHalfLength) ||
|
|
!IsAbsolueValueRatioWithinThreshold(m_yHalfLength, m_zHalfLength)
|
|
)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
// Create shape.
|
|
const Vector dimensions = Vector{ {m_xHalfLength, m_yHalfLength, m_zHalfLength} } * 2.0;
|
|
result.second = AZStd::make_shared<Physics::BoxShapeConfiguration>(VecToAZVec3(dimensions));
|
|
|
|
// Create transform.
|
|
result.first = AZStd::make_shared<AssetColliderConfiguration>();
|
|
result.first->m_transform = CreateTransformFromCoordinateSystem(m_origin, m_xAxis, m_yAxis, m_zAxis);
|
|
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
Vector m_origin;
|
|
Vector m_xAxis;
|
|
Vector m_yAxis;
|
|
Vector m_zAxis;
|
|
double m_xHalfLength;
|
|
double m_yHalfLength;
|
|
double m_zHalfLength;
|
|
};
|
|
|
|
// Implementation of the abstract shape class for capsules.
|
|
class CapsuleParameterization
|
|
: public AbstractShapeParameterization
|
|
{
|
|
public:
|
|
CapsuleParameterization(
|
|
const Vector& origin,
|
|
const Vector& xAxis,
|
|
const Vector& yAxis,
|
|
const Vector& zAxis,
|
|
const Vector& halfRanges
|
|
)
|
|
: m_origin(origin)
|
|
, m_xAxis(xAxis)
|
|
, m_yAxis(yAxis)
|
|
, m_zAxis(zAxis)
|
|
, m_radius(halfRanges[1])
|
|
, m_halfInnerHeight(AZStd::max(halfRanges[0] - halfRanges[1], 0.0))
|
|
{
|
|
}
|
|
|
|
AZ::u32 GetDegreesOfFreedom() const override
|
|
{
|
|
return 7;
|
|
}
|
|
|
|
AZStd::vector<double> PackArguments() const override
|
|
{
|
|
// The parameters will be packed as follows:
|
|
// [ originVector ] [ halfInnerHeightVector ] [ radius ]
|
|
// 0 2 3 5 6 6
|
|
//
|
|
// Where:
|
|
// - originVector is m_origin
|
|
// - halfInnerHeightVector is the vector from the origin to the center of the semi-sphere along the x axis
|
|
// - radius is m_radius
|
|
|
|
AZStd::vector<double> args;
|
|
args.reserve(GetDegreesOfFreedom());
|
|
|
|
args.insert(args.end(), m_origin.begin(), m_origin.end());
|
|
|
|
const Vector halfInnerHeightVector = m_xAxis * m_halfInnerHeight;
|
|
args.insert(args.end(), halfInnerHeightVector.begin(), halfInnerHeightVector.end());
|
|
|
|
args.insert(args.end(), m_radius);
|
|
|
|
return args;
|
|
}
|
|
|
|
void UnpackArguments(const AZStd::vector<double>& args) override
|
|
{
|
|
auto it = args.begin();
|
|
|
|
std::copy_n(it, 3, m_origin.begin());
|
|
it += 3;
|
|
|
|
Vector halfInnerHeightVector{{0.0, 0.0, 0.0}};
|
|
std::copy_n(it, 3, halfInnerHeightVector.begin());
|
|
m_halfInnerHeight = Norm(halfInnerHeightVector);
|
|
m_xAxis = m_halfInnerHeight > 0 ? halfInnerHeightVector / m_halfInnerHeight : Vector{{1.0, 0.0, 0.0}};
|
|
it += 3;
|
|
|
|
m_radius = fabs(*it);
|
|
m_yAxis = ComputeAnyOrthogonalVector(m_xAxis);
|
|
m_zAxis = Cross(m_xAxis, m_yAxis);
|
|
}
|
|
|
|
double GetVolume() const override
|
|
{
|
|
return FourThirdsPi * m_radius * m_radius * (1.5 * m_halfInnerHeight + m_radius);
|
|
}
|
|
|
|
double SquaredDistanceToShape(const Vector& vertex) const override
|
|
{
|
|
// Convert the coordinates of the vertex to capsule space. Due to symmetry we can take the absolute value of
|
|
// the projection onto the x axis.
|
|
const Vector vertexInCapsuleSpace{{
|
|
fabs(Dot(vertex - m_origin, m_xAxis)),
|
|
Dot(vertex - m_origin, m_yAxis),
|
|
Dot(vertex - m_origin, m_zAxis),
|
|
}};
|
|
|
|
// Compute the squared perpendicular distance of the point from the x axis.
|
|
const double squaredDistanceFromVertexToXAxis
|
|
= vertexInCapsuleSpace[1] * vertexInCapsuleSpace[1] + vertexInCapsuleSpace[2] * vertexInCapsuleSpace[2];
|
|
|
|
double distanceToShape = 0.0;
|
|
|
|
if (vertexInCapsuleSpace[0] <= m_halfInnerHeight)
|
|
{
|
|
// The closest point is on the cylindrical part.
|
|
distanceToShape = sqrt(squaredDistanceFromVertexToXAxis) - m_radius;
|
|
}
|
|
else
|
|
{
|
|
// The closest point is on the spherical part.
|
|
const double distanceFromSphereCenterToVertexXCoordinate = vertexInCapsuleSpace[0] - m_halfInnerHeight;
|
|
|
|
const double squaredDistanceFromVertexToSphereCenter = squaredDistanceFromVertexToXAxis
|
|
+ distanceFromSphereCenterToVertexXCoordinate * distanceFromSphereCenterToVertexXCoordinate;
|
|
|
|
distanceToShape = sqrt(squaredDistanceFromVertexToSphereCenter) - m_radius;
|
|
}
|
|
|
|
return distanceToShape * distanceToShape;
|
|
}
|
|
|
|
MeshAssetData::ShapeConfigurationPair GetShapeConfigurationPair() const override
|
|
{
|
|
MeshAssetData::ShapeConfigurationPair result(nullptr, nullptr);
|
|
|
|
// Don't return a shape if the capsule is too small or not well-shaped.
|
|
if (
|
|
IsAbsoluteValueWithinEpsilon(m_radius) ||
|
|
IsAbsoluteValueWithinEpsilon(m_halfInnerHeight) ||
|
|
!IsAbsolueValueRatioWithinThreshold(m_radius, m_halfInnerHeight + m_radius)
|
|
)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
// Create shape.
|
|
result.second = AZStd::make_shared<Physics::CapsuleShapeConfiguration>(
|
|
(float)(2.0 * (m_halfInnerHeight + m_radius)), (float)m_radius
|
|
);
|
|
|
|
// Create transform. For capsules the primary axis is the z-axis.
|
|
result.first = AZStd::make_shared<AssetColliderConfiguration>();
|
|
result.first->m_transform = CreateTransformFromCoordinateSystem(m_origin, m_yAxis, m_zAxis, m_xAxis);
|
|
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
Vector m_origin;
|
|
Vector m_xAxis;
|
|
Vector m_yAxis;
|
|
Vector m_zAxis;
|
|
double m_radius;
|
|
double m_halfInnerHeight;
|
|
};
|
|
|
|
// Factory function for creating shapes.
|
|
template<typename SHAPE>
|
|
AbstractShapeParameterization::Ptr CreateAbstractShape(
|
|
const Vector& origin,
|
|
const Vector& xAxis,
|
|
const Vector& yAxis,
|
|
const Vector& zAxis,
|
|
const Vector& halfRanges
|
|
)
|
|
{
|
|
return AZStd::make_unique<SHAPE>(origin, xAxis, yAxis, zAxis, halfRanges);
|
|
}
|
|
|
|
// Explicitly template instantiation for spheres.
|
|
template AbstractShapeParameterization::Ptr CreateAbstractShape<SphereParameterization>(
|
|
const Vector&,
|
|
const Vector&,
|
|
const Vector&,
|
|
const Vector&,
|
|
const Vector&
|
|
);
|
|
|
|
// Explicitly template instantiation for boxes.
|
|
template AbstractShapeParameterization::Ptr CreateAbstractShape<BoxParameterization>(
|
|
const Vector&,
|
|
const Vector&,
|
|
const Vector&,
|
|
const Vector&,
|
|
const Vector&
|
|
);
|
|
|
|
// Explicitly template instantiation for capsules.
|
|
template AbstractShapeParameterization::Ptr CreateAbstractShape<CapsuleParameterization>(
|
|
const Vector&,
|
|
const Vector&,
|
|
const Vector&,
|
|
const Vector&,
|
|
const Vector&
|
|
);
|
|
} // PhysX::Pipeline
|