Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,91 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Math/Vector3.h>
#include <AzCore/RTTI/RTTI.h>
namespace AzToolsFramework
{
/**
* Provide unique type alias for AZ::u64 for manipulator, bounds and manager.
*/
template<typename T>
class IdType
{
public:
explicit IdType(AZ::u64 id = 0)
: m_id(id) {}
operator AZ::u64() const { return m_id; }
bool operator==(IdType other) const { return m_id == other.m_id; }
bool operator!=(IdType other) const { return m_id != other.m_id; }
IdType& operator++() // pre-increment
{
++m_id;
return *this;
}
IdType operator++(int) // post-increment
{
IdType temp = *this;
++*this;
return temp;
}
private:
AZ::u64 m_id;
};
namespace Picking
{
class BoundRequestShapeBase;
using RegisteredBoundId = IdType<struct RegisteredBoundType>;
static const RegisteredBoundId InvalidBoundId = RegisteredBoundId(0);
/**
* This class serves as the base class for the actual bound shapes that various DefaultContextBoundManager-derived
* classes return from the function CreateShape.
*/
class BoundShapeInterface
{
public:
AZ_RTTI(BoundShapeInterface, "{C639CB8E-1957-4E4F-B889-3BE1DFBC358D}");
explicit BoundShapeInterface(const RegisteredBoundId boundId)
: m_boundId(boundId)
, m_valid(false)
{}
virtual ~BoundShapeInterface() = default;
RegisteredBoundId GetBoundId() const { return m_boundId; }
/**
* @param rayOrigin The origin of the ray to test with.
* @param rayDir The direction of the ray to test with.
* @param[out] rayIntersectionDistance The distance of the intersecting point closest to the ray origin.
* @return Boolean indicating whether there is a least one intersecting point between this bound shape and the ray.
*/
virtual bool IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) = 0;
virtual void SetShapeData(const BoundRequestShapeBase& shapeData) = 0;
void SetValidity(bool valid) { m_valid = valid; }
bool IsValid() const { return m_valid; }
private:
RegisteredBoundId m_boundId;
bool m_valid;
};
} // namespace Picking
} // namespace AzToolsFramework
@@ -0,0 +1,219 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Spline.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Picking/BoundInterface.h>
#include <AzToolsFramework/Picking/Manipulators/ManipulatorBounds.h>
namespace AzToolsFramework
{
namespace Picking
{
/**
* An interface concrete shape types can implement to create specific BoundShapeInterfaces.
*/
class BoundRequestShapeBase
{
public:
AZ_RTTI(BoundRequestShapeBase, "{60D52E6E-54A6-4236-A397-322FD7607FA3}");
BoundRequestShapeBase() = default;
virtual ~BoundRequestShapeBase() = default;
virtual AZStd::shared_ptr<BoundShapeInterface> MakeShapeInterface(RegisteredBoundId id) const = 0;
};
class BoundShapeBox : public BoundRequestShapeBase
{
public:
AZ_RTTI(BoundShapeBox, "{6BF78BC6-5100-41A1-84E1-6F4E552E2FC5}", BoundRequestShapeBase);
AZ_CLASS_ALLOCATOR(BoundShapeBox, AZ::SystemAllocator, 0);
AZStd::shared_ptr<BoundShapeInterface> MakeShapeInterface(RegisteredBoundId id) const override
{
AZStd::shared_ptr<BoundShapeInterface> box = AZStd::make_shared<ManipulatorBoundBox>(id);
box->SetShapeData(*this);
return box;
}
AZ::Vector3 m_center;
AZ::Quaternion m_orientation;
AZ::Vector3 m_halfExtents;
};
class BoundShapeSphere : public BoundRequestShapeBase
{
public:
AZ_RTTI(BoundShapeSphere, "{786168B7-46BB-4C0E-9642-5A7B94BF00FA}", BoundRequestShapeBase);
AZ_CLASS_ALLOCATOR(BoundShapeSphere, AZ::SystemAllocator, 0);
AZStd::shared_ptr<BoundShapeInterface> MakeShapeInterface(RegisteredBoundId id) const override
{
AZStd::shared_ptr<BoundShapeInterface> sphere = AZStd::make_shared<ManipulatorBoundSphere>(id);
sphere->SetShapeData(*this);
return sphere;
}
AZ::Vector3 m_center;
float m_radius;
};
class BoundShapeCylinder : public BoundRequestShapeBase
{
public:
AZ_RTTI(BoundShapeCylinder, "{3D9A8328-4371-4EC5-BEC2-783998B19200}", BoundRequestShapeBase);
AZ_CLASS_ALLOCATOR(BoundShapeCylinder, AZ::SystemAllocator, 0);
AZStd::shared_ptr<BoundShapeInterface> MakeShapeInterface(RegisteredBoundId id) const override
{
AZStd::shared_ptr<BoundShapeInterface> cylinder = AZStd::make_shared<ManipulatorBoundCylinder>(id);
cylinder->SetShapeData(*this);
return cylinder;
}
AZ::Vector3 m_axis;
AZ::Vector3 m_base;
float m_height;
float m_radius;
};
class BoundShapeCone : public BoundRequestShapeBase
{
public:
AZ_RTTI(BoundShapeCone, "{68D67118-EAC9-4384-BE99-2CAB72A0450A}", BoundRequestShapeBase);
AZ_CLASS_ALLOCATOR(BoundShapeCone, AZ::SystemAllocator, 0);
AZStd::shared_ptr<BoundShapeInterface> MakeShapeInterface(RegisteredBoundId id) const override
{
AZStd::shared_ptr<BoundShapeInterface> cone = AZStd::make_shared<ManipulatorBoundCone>(id);
cone->SetShapeData(*this);
return cone;
}
AZ::Vector3 m_axis;
AZ::Vector3 m_base;
float m_height;
float m_radius;
};
/**
* The quad shape consists of 4 points in 3D space. Please set them from \ref m_corner1 to \ref m_corner4
* in either clock-wise winding or counter clock-wise winding. In another word, \ref m_corner1 and
* \ref corner_2 cannot be diagonal corners.
*/
class BoundShapeQuad : public BoundRequestShapeBase
{
public:
AZ_RTTI(BoundShapeQuad, "{D1F73C4B-3B42-4493-B1D1-38EE59F2C7F3}", BoundRequestShapeBase)
AZ_CLASS_ALLOCATOR(BoundShapeQuad, AZ::SystemAllocator, 0)
AZStd::shared_ptr<BoundShapeInterface> MakeShapeInterface(RegisteredBoundId id) const override
{
AZStd::shared_ptr<BoundShapeInterface> quad = AZStd::make_shared<ManipulatorBoundQuad>(id);
quad->SetShapeData(*this);
return quad;
}
AZ::Vector3 m_corner1;
AZ::Vector3 m_corner2;
AZ::Vector3 m_corner3;
AZ::Vector3 m_corner4;
};
/**
* The line segment consists of two points in 3D space defining a line the user can interact with.
*/
class BoundShapeLineSegment : public BoundRequestShapeBase
{
public:
AZ_RTTI(BoundShapeLineSegment, "{BC5DCB8B-E9F7-41BB-AD93-00D3EAB108D3}", BoundRequestShapeBase)
AZ_CLASS_ALLOCATOR(BoundShapeLineSegment, AZ::SystemAllocator, 0)
AZStd::shared_ptr<BoundShapeInterface> MakeShapeInterface(RegisteredBoundId id) const override
{
AZStd::shared_ptr<BoundShapeInterface> lineSegment = AZStd::make_shared<ManipulatorBoundLineSegment>(id);
lineSegment->SetShapeData(*this);
return lineSegment;
}
AZ::Vector3 m_start;
AZ::Vector3 m_end;
float m_width;
};
/**
* The torus shape is approximated by a cylinder whose radius is the sum of the torus's major radius
* and minor radius and height is twice the torus's minor radius.
*/
class BoundShapeTorus : public BoundRequestShapeBase
{
public:
AZ_RTTI(BoundShapeTorus, "{2EF456F8-87D4-44CD-9929-FC45981289D4}", BoundRequestShapeBase)
AZ_CLASS_ALLOCATOR(BoundShapeTorus, AZ::SystemAllocator, 0)
AZStd::shared_ptr<BoundShapeInterface> MakeShapeInterface(RegisteredBoundId id) const override
{
AZStd::shared_ptr<BoundShapeInterface> torus = AZStd::make_shared<ManipulatorBoundTorus>(id);
torus->SetShapeData(*this);
return torus;
}
AZ::Vector3 m_axis;
AZ::Vector3 m_center;
float m_majorRadius;
float m_minorRadius;
};
/**
* The spline is specified by a number of vertices. A piecewise approximation of the curve
* is computed by using a number of linear steps (defined by the granularity of the curve).
*/
class BoundShapeSpline : public BoundRequestShapeBase
{
public:
AZ_RTTI(BoundShapeSpline, "{65CBF85A-5126-4F2A-AA2E-047367435DEC}", BoundRequestShapeBase)
AZ_CLASS_ALLOCATOR(BoundShapeSpline, AZ::SystemAllocator, 0)
AZStd::shared_ptr<BoundShapeInterface> MakeShapeInterface(RegisteredBoundId id) const override
{
AZStd::shared_ptr<BoundShapeInterface> spline = AZStd::make_shared<ManipulatorBoundSpline>(id);
spline->SetShapeData(*this);
return spline;
}
AZStd::weak_ptr<const AZ::Spline> m_spline;
AZ::Transform m_transform;
float m_width;
};
/**
* Ray query for intersection against bounds.
*/
struct RaySelectInfo
{
AZ::Vector3 m_origin; ///< Start of ray.
AZ::Vector3 m_direction; ///< Direction of ray - make sure m_direction is unit length.
AZStd::vector<AZStd::pair<RegisteredBoundId, float>> m_boundIdsHit; ///< Store the id of the intersected bound
///< and the parameter of the corresponding
///< intersecting point.
};
} // namespace Picking
} // namespace AzToolsFramework
@@ -0,0 +1,120 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "ManipulatorBoundManager.h"
namespace AzToolsFramework
{
namespace Picking
{
RegisteredBoundId ManipulatorBoundManager::UpdateOrRegisterBound(
const BoundRequestShapeBase& shapeData, RegisteredBoundId boundId)
{
if (boundId == InvalidBoundId)
{
// make a new bound
boundId = m_nextBoundId++;
}
if (auto result = m_boundIdToShapeMap.find(boundId);
result == m_boundIdToShapeMap.end())
{
if (AZStd::shared_ptr<BoundShapeInterface> createdShape = CreateShape(shapeData, boundId))
{
m_boundIdToShapeMap[boundId] = createdShape;
createdShape->SetValidity(true);
}
else
{
boundId = InvalidBoundId;
}
}
else
{
result->second->SetShapeData(shapeData);
result->second->SetValidity(true);
}
return boundId;
}
void ManipulatorBoundManager::UnregisterBound(const RegisteredBoundId boundId)
{
if (const auto findIter = m_boundIdToShapeMap.find(boundId);
findIter != m_boundIdToShapeMap.end())
{
DeleteShape(findIter->second.get());
m_boundIdToShapeMap.erase(findIter);
}
}
void ManipulatorBoundManager::SetBoundValidity(
const RegisteredBoundId boundId, const bool valid)
{
if (auto found = m_boundIdToShapeMap.find(boundId);
found != m_boundIdToShapeMap.end())
{
found->second->SetValidity(valid);
}
}
AZStd::shared_ptr<BoundShapeInterface> ManipulatorBoundManager::CreateShape(
const BoundRequestShapeBase& shapeData, const RegisteredBoundId boundId)
{
AZ_Assert(boundId != InvalidBoundId, "Invalid Bound Id!");
AZStd::shared_ptr<BoundShapeInterface> shape = shapeData.MakeShapeInterface(boundId);
m_bounds.push_back(shape);
return shape;
}
void ManipulatorBoundManager::DeleteShape(const BoundShapeInterface* boundShape)
{
const auto boundShapeCompare = [boundShape](const auto& storedBoundShape)
{
return boundShape == storedBoundShape.get();
};
m_bounds.erase(AZStd::remove_if(m_bounds.begin(), m_bounds.end(), boundShapeCompare), m_bounds.end());
}
void ManipulatorBoundManager::RaySelect(RaySelectInfo& rayInfo)
{
using BoundIdHitDistance = AZStd::pair<RegisteredBoundId, float>;
// create a sorted list of manipulators - sorted based on proximity to ray
AZStd::vector<BoundIdHitDistance> rayHits;
rayHits.reserve(m_bounds.size());
for (const AZStd::shared_ptr<BoundShapeInterface>& bound : m_bounds)
{
if (bound->IsValid())
{
float t = 0.0f;
if (bound->IntersectRay(rayInfo.m_origin, rayInfo.m_direction, t))
{
const auto hitItr = AZStd::lower_bound(
rayHits.begin(), rayHits.end(), BoundIdHitDistance(0, t),
[](const BoundIdHitDistance& lhs, const BoundIdHitDistance& rhs)
{
return lhs.second < rhs.second;
});
rayHits.insert(hitItr, AZStd::make_pair(bound->GetBoundId(), t));
}
}
}
rayInfo.m_boundIdsHit.reserve(rayHits.size());
AZStd::copy(rayHits.begin(), rayHits.end(), AZStd::back_inserter(rayInfo.m_boundIdsHit));
}
} // namespace Picking
} // namespace AzToolsFramework
@@ -0,0 +1,55 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
#include <AzToolsFramework/Picking/ContextBoundAPI.h>
namespace AzToolsFramework
{
namespace Picking
{
class BoundShapeInterface;
/**
* Handle creating, destroying and storing all active manipulator
* bounds for performing raycasts/picking against.
*/
class ManipulatorBoundManager
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorBoundManager, AZ::SystemAllocator, 0);
ManipulatorBoundManager() = default;
ManipulatorBoundManager(const ManipulatorBoundManager&) = delete;
ManipulatorBoundManager& operator=(const ManipulatorBoundManager&) = delete;
~ManipulatorBoundManager() = default;
RegisteredBoundId UpdateOrRegisterBound(
const BoundRequestShapeBase& shapeData, RegisteredBoundId id);
void UnregisterBound(RegisteredBoundId boundId);
void SetBoundValidity(RegisteredBoundId boundId, bool valid);
void RaySelect(RaySelectInfo &rayInfo);
private:
AZStd::shared_ptr<BoundShapeInterface> CreateShape(
const BoundRequestShapeBase& ptrShape, RegisteredBoundId id);
void DeleteShape(const BoundShapeInterface* boundShape);
AZStd::unordered_map<RegisteredBoundId, AZStd::shared_ptr<BoundShapeInterface>> m_boundIdToShapeMap;
AZStd::vector<AZStd::shared_ptr<BoundShapeInterface>> m_bounds; ///< All current manipulator bounds.
RegisteredBoundId m_nextBoundId = RegisteredBoundId(1); ///< Next bound id to use when a bound is registered.
};
} // namespace Picking
} // namespace AzToolsFramework
@@ -0,0 +1,257 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Math/IntersectSegment.h>
#include <AzCore/Math/Spline.h>
#include <AzToolsFramework/Picking/ContextBoundAPI.h>
#include <AzToolsFramework/Picking/Manipulators/ManipulatorBounds.h>
namespace AzToolsFramework
{
namespace Picking
{
bool ManipulatorBoundSphere::IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance)
{
float vecRayIntersectionDistance;
if (AZ::Intersect::IntersectRaySphere(
rayOrigin, rayDirection, m_center, m_radius, vecRayIntersectionDistance) > 0)
{
rayIntersectionDistance = vecRayIntersectionDistance;
return true;
}
return false;
}
void ManipulatorBoundSphere::SetShapeData(const BoundRequestShapeBase& shapeData)
{
if (const auto* sphereData = azrtti_cast<const BoundShapeSphere*>(&shapeData))
{
m_center = sphereData->m_center;
m_radius = sphereData->m_radius;
}
}
bool ManipulatorBoundBox::IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance)
{
return AZ::Intersect::IntersectRayBox(rayOrigin, rayDirection, m_center, m_axis1, m_axis2, m_axis3,
m_halfExtents.GetX(), m_halfExtents.GetY(), m_halfExtents.GetZ(), rayIntersectionDistance) > 0;
}
void ManipulatorBoundBox::SetShapeData(const BoundRequestShapeBase& shapeData)
{
if (const auto* boxData = azrtti_cast<const BoundShapeBox*>(&shapeData))
{
m_center = boxData->m_center;
m_axis1 = boxData->m_orientation.TransformVector(AZ::Vector3::CreateAxisX());
m_axis2 = boxData->m_orientation.TransformVector(AZ::Vector3::CreateAxisY());
m_axis3 = boxData->m_orientation.TransformVector(AZ::Vector3::CreateAxisZ());
m_halfExtents = boxData->m_halfExtents;
}
}
bool ManipulatorBoundCylinder::IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance)
{
float t1 = std::numeric_limits<float>::max();
float t2 = std::numeric_limits<float>::max();
if (AZ::Intersect::IntersectRayCappedCylinder(
rayOrigin, rayDirection, m_base, m_axis, m_height, m_radius, t1, t2) > 0)
{
rayIntersectionDistance = AZStd::GetMin(t1, t2);
return true;
}
return false;
}
void ManipulatorBoundCylinder::SetShapeData(const BoundRequestShapeBase& shapeData)
{
if (const auto* cylinderData = azrtti_cast<const BoundShapeCylinder*>(&shapeData))
{
m_base = cylinderData->m_base;
m_axis = cylinderData->m_axis;
m_height = cylinderData->m_height;
m_radius = cylinderData->m_radius;
}
}
bool ManipulatorBoundCone::IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance)
{
float t1 = std::numeric_limits<float>::max();
float t2 = std::numeric_limits<float>::max();
if (AZ::Intersect::IntersectRayCone(
rayOrigin, rayDirection, m_apexPosition, m_dir, m_height, m_radius, t1, t2) > 0)
{
rayIntersectionDistance = AZStd::GetMin(t1, t2);
return true;
}
return false;
}
void ManipulatorBoundCone::SetShapeData(const BoundRequestShapeBase& shapeData)
{
if (const auto* coneData = azrtti_cast<const BoundShapeCone*>(&shapeData))
{
m_apexPosition = coneData->m_base + coneData->m_axis * coneData->m_height;
m_dir = -coneData->m_axis;
m_height = coneData->m_height;
m_radius = coneData->m_radius;
}
}
bool ManipulatorBoundQuad::IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance)
{
return AZ::Intersect::IntersectRayQuad(
rayOrigin, rayDirection, m_corner1, m_corner2, m_corner3, m_corner4, rayIntersectionDistance) > 0;
}
void ManipulatorBoundQuad::SetShapeData(const BoundRequestShapeBase& shapeData)
{
if (const auto* quadData = azrtti_cast<const BoundShapeQuad*>(&shapeData))
{
m_corner1 = quadData->m_corner1;
m_corner2 = quadData->m_corner2;
m_corner3 = quadData->m_corner3;
m_corner4 = quadData->m_corner4;
}
}
bool ManipulatorBoundTorus::IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance)
{
return IntersectHollowCylinder(
rayOrigin, rayDirection, m_center, m_axis, m_minorRadius, m_majorRadius, rayIntersectionDistance);
}
void ManipulatorBoundTorus::SetShapeData(const BoundRequestShapeBase& shapeData)
{
if (const auto* torusData = azrtti_cast<const BoundShapeTorus*>(&shapeData))
{
m_center = torusData->m_center;
m_axis = torusData->m_axis;
m_minorRadius = torusData->m_minorRadius;
m_majorRadius = torusData->m_majorRadius;
}
}
bool ManipulatorBoundLineSegment::IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance)
{
const float rayLength = 1000.0f;
AZ::Vector3 closestPosRay, closestPosLineSegment;
float rayProportion, lineSegmentProportion;
// note: here out param is proportion/percentage of line
AZ::Intersect::ClosestSegmentSegment(
rayOrigin, rayOrigin + rayDirection * rayLength,
m_worldStart, m_worldEnd, rayProportion, lineSegmentProportion,
closestPosRay, closestPosLineSegment);
float distanceFromLine = (closestPosRay - closestPosLineSegment).GetLength();
if (distanceFromLine <= m_width)
{
// rayIntersectionDistance is expected to be distance so we must scale rayProportion by its length.
// add distance from line to give more accurate rayIntersectionDistance value.
rayIntersectionDistance = rayProportion * rayLength + distanceFromLine;
return true;
}
return false;
}
void ManipulatorBoundLineSegment::SetShapeData(const BoundRequestShapeBase& shapeData)
{
if (const auto* lineSegmentData = azrtti_cast<const BoundShapeLineSegment*>(&shapeData))
{
m_worldStart = lineSegmentData->m_start;
m_worldEnd = lineSegmentData->m_end;
m_width = lineSegmentData->m_width;
}
}
bool ManipulatorBoundSpline::IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance)
{
if (const AZStd::shared_ptr<const AZ::Spline> spline = m_spline.lock())
{
AZ::RaySplineQueryResult splineQueryResult =
AZ::IntersectSpline(m_transform, rayOrigin, rayDirection, *spline);
if (splineQueryResult.m_distanceSq <= m_width * m_width)
{
rayIntersectionDistance = splineQueryResult.m_rayDistance;
return true;
}
return false;
}
return false;
}
void ManipulatorBoundSpline::SetShapeData(const BoundRequestShapeBase& shapeData)
{
if (const auto* splineData = azrtti_cast<const BoundShapeSpline*>(&shapeData))
{
m_spline = splineData->m_spline;
m_transform = splineData->m_transform;
m_width = splineData->m_width;
}
}
bool IntersectHollowCylinder(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
const AZ::Vector3& center, const AZ::Vector3& axis,
const float minorRadius, const float majorRadius,
float& rayIntersectionDistance)
{
float t1 = std::numeric_limits<float>::max();
float t2 = std::numeric_limits<float>::max();
const AZ::Vector3 base = center - axis * minorRadius;
if (AZ::Intersect::IntersectRayCappedCylinder(
rayOrigin, rayDirection, base, axis, minorRadius * 2.0f, majorRadius + minorRadius, t1, t2) > 0)
{
const float thresholdSq = powf(majorRadius - minorRadius, 2.0f);
// util lambda used for distance checks at both 't' values
const auto validHolowCylinderHit =
[&rayOrigin, &rayDirection, &center, thresholdSq](const float t)
{
// only return a valid intersection if the hit was
// not in the 'hollow' part of the cylinder
const AZ::Vector3 intersection = rayOrigin + rayDirection * t;
const float distanceSq = (intersection - center).GetLengthSq();
return distanceSq > thresholdSq;
};
if (validHolowCylinderHit(t1))
{
rayIntersectionDistance = t1;
return true;
}
if (validHolowCylinderHit(t2))
{
rayIntersectionDistance = t2;
return true;
}
}
return false;
}
} // namespace Picking
} // namespace AzToolsFramework
@@ -0,0 +1,203 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Math/Transform.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzToolsFramework/Picking/BoundInterface.h>
namespace AZ
{
class Spline;
}
namespace AzToolsFramework
{
namespace Picking
{
class ManipulatorBoundSphere
: public BoundShapeInterface
{
public:
AZ_RTTI(ManipulatorBoundSphere, "{64D1B863-F574-4B31-A4F2-C9744D8567B3}", BoundShapeInterface);
AZ_CLASS_ALLOCATOR(ManipulatorBoundSphere, AZ::SystemAllocator, 0);
explicit ManipulatorBoundSphere(RegisteredBoundId boundId)
: BoundShapeInterface(boundId) {}
bool IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override;
void SetShapeData(const BoundRequestShapeBase& shapeData) override;
AZ::Vector3 m_center = AZ::Vector3::CreateZero();
float m_radius = 0.0f;
};
class ManipulatorBoundBox
: public BoundShapeInterface
{
public:
AZ_RTTI(ManipulatorBoundBox, "{3AD46067-933F-49B4-82E1-DBF12C7BC02E}", BoundShapeInterface);
AZ_CLASS_ALLOCATOR(ManipulatorBoundBox, AZ::SystemAllocator, 0);
explicit ManipulatorBoundBox(RegisteredBoundId boundId)
: BoundShapeInterface(boundId) {}
bool IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override;
void SetShapeData(const BoundRequestShapeBase& shapeData) override;
AZ::Vector3 m_center = AZ::Vector3::CreateZero();
AZ::Vector3 m_axis1 = AZ::Vector3::CreateZero();
AZ::Vector3 m_axis2 = AZ::Vector3::CreateZero();
AZ::Vector3 m_axis3 = AZ::Vector3::CreateZero();
AZ::Vector3 m_halfExtents = AZ::Vector3::CreateZero();
};
class ManipulatorBoundCylinder
: public BoundShapeInterface
{
public:
AZ_RTTI(ManipulatorBoundCylinder, "{D248F9E4-22E6-41A8-898D-704DF307B533}", BoundShapeInterface);
AZ_CLASS_ALLOCATOR(ManipulatorBoundCylinder, AZ::SystemAllocator, 0);
explicit ManipulatorBoundCylinder(RegisteredBoundId boundId)
: BoundShapeInterface(boundId) {}
bool IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override;
void SetShapeData(const BoundRequestShapeBase& shapeData) override;
AZ::Vector3 m_base = AZ::Vector3::CreateZero(); ///< The center of the circle at the base of the cylinder.
AZ::Vector3 m_axis = AZ::Vector3::CreateZero();
float m_height = 0.0f;
float m_radius = 0.0f;
};
class ManipulatorBoundCone
: public BoundShapeInterface
{
public:
AZ_RTTI(ManipulatorBoundCone, "{9430440D-DFF2-4A60-9073-507C4E9DD65D}", BoundShapeInterface);
AZ_CLASS_ALLOCATOR(ManipulatorBoundCone, AZ::SystemAllocator, 0);
explicit ManipulatorBoundCone(RegisteredBoundId boundId)
: BoundShapeInterface(boundId) {}
bool IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override;
void SetShapeData(const BoundRequestShapeBase& shapeData) override;
AZ::Vector3 m_apexPosition = AZ::Vector3::CreateZero();
AZ::Vector3 m_dir = AZ::Vector3::CreateZero();
float m_radius = 0.0f;
float m_height = 0.0f;
};
/**
* The quad shape consists of 4 points in 3D space. Please set them from \ref m_corner1 to \ref m_corner4
* in either clock-wise winding or counter clock-wise winding. In another word, \ref m_corner1 and
* \ref corner_2 cannot be diagonal corners.
*/
class ManipulatorBoundQuad
: public BoundShapeInterface
{
public:
AZ_RTTI(ManipulatorBoundQuad, "{3CDED61C-5786-4299-B5F2-5970DE4457AD}", BoundShapeInterface);
AZ_CLASS_ALLOCATOR(ManipulatorBoundQuad, AZ::SystemAllocator, 0);
explicit ManipulatorBoundQuad(RegisteredBoundId boundId)
: BoundShapeInterface(boundId) {}
bool IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override;
void SetShapeData(const BoundRequestShapeBase& shapeData) override;
AZ::Vector3 m_corner1 = AZ::Vector3::CreateZero();
AZ::Vector3 m_corner2 = AZ::Vector3::CreateZero();
AZ::Vector3 m_corner3 = AZ::Vector3::CreateZero();
AZ::Vector3 m_corner4 = AZ::Vector3::CreateZero();
};
class ManipulatorBoundTorus
: public BoundShapeInterface
{
public:
AZ_RTTI(ManipulatorBoundTorus, "{46E4711C-178A-4F97-BC14-A048D096E7A1}", BoundShapeInterface);
AZ_CLASS_ALLOCATOR(ManipulatorBoundTorus, AZ::SystemAllocator, 0);
explicit ManipulatorBoundTorus(RegisteredBoundId boundId)
: BoundShapeInterface(boundId) {}
bool IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override;
void SetShapeData(const BoundRequestShapeBase& shapeData) override;
// Approximate a torus as a thin cylinder. A ray intersects a torus when the ray and the torus'
// approximating cylinder have an intersecting point that is at certain distance away from the
// center of the torus.
AZ::Vector3 m_center = AZ::Vector3::CreateZero();
AZ::Vector3 m_axis = AZ::Vector3::CreateZero();
float m_majorRadius = 0.0f; ///< Usually denoted as "R", the distance from the center of the tube to the center of the torus.
float m_minorRadius = 0.0f; ///< Usually denoted as "r", the radius of the tube.
};
class ManipulatorBoundLineSegment
: public BoundShapeInterface
{
public:
AZ_RTTI(ManipulatorBoundLineSegment, "{66801554-1C1A-4E79-B1E7-342DFA779D53}", BoundShapeInterface);
AZ_CLASS_ALLOCATOR(ManipulatorBoundLineSegment, AZ::SystemAllocator, 0);
explicit ManipulatorBoundLineSegment(RegisteredBoundId boundId)
: BoundShapeInterface(boundId) {}
bool IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override;
void SetShapeData(const BoundRequestShapeBase& shapeData) override;
AZ::Vector3 m_worldStart = AZ::Vector3::CreateZero();
AZ::Vector3 m_worldEnd = AZ::Vector3::CreateZero();
float m_width = 0.0f;
};
class ManipulatorBoundSpline
: public BoundShapeInterface
{
public:
AZ_RTTI(ManipulatorBoundSpline, "{777760FF-8547-45AD-876F-16BA4D9D0584}", BoundShapeInterface);
AZ_CLASS_ALLOCATOR(ManipulatorBoundSpline, AZ::SystemAllocator, 0);
explicit ManipulatorBoundSpline(RegisteredBoundId boundId)
: BoundShapeInterface(boundId) {}
bool IntersectRay(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override;
void SetShapeData(const BoundRequestShapeBase& shapeData) override;
AZStd::weak_ptr<const AZ::Spline> m_spline;
AZ::Transform m_transform;
float m_width = 0.0f;
};
/// Approximate intersection with a torus-like shape.
bool IntersectHollowCylinder(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
const AZ::Vector3& center, const AZ::Vector3& axis,
float minorRadius, float majorRadius,
float& rayIntersectionDistance);
} // namespace Picking
} // namespace AzToolsFramework