Merge pull request #69 from aws-lumberyard-dev/non-uniform-scale-mesh

support for non-uniform scale component with atom mesh component
This commit is contained in:
greerdv
2021-04-22 18:49:36 +01:00
committed by GitHub
27 changed files with 263 additions and 42 deletions
@@ -145,8 +145,10 @@ namespace AZ
const MaterialAssignmentMap& GetMaterialAssignmentMap(const MeshHandle& meshHandle) const override;
void ConnectModelChangeEventHandler(const MeshHandle& meshHandle, ModelChangedEvent::Handler& handler) override;
void SetTransform(const MeshHandle& meshHandle, const AZ::Transform& transform) override;
void SetTransform(const MeshHandle& meshHandle, const AZ::Transform& transform,
const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne()) override;
Transform GetTransform(const MeshHandle& meshHandle) override;
Vector3 GetNonUniformScale(const MeshHandle& meshHandle) override;
void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) override;
RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) override;
@@ -62,9 +62,12 @@ namespace AZ
//! Connects a handler to any changes to an RPI::Model. Changes include loading and reloading.
virtual void ConnectModelChangeEventHandler(const MeshHandle& meshHandle, ModelChangedEvent::Handler& handler) = 0;
//! Sets the transform for a given mesh handle.
virtual void SetTransform(const MeshHandle& meshHandle, const AZ::Transform& transform) = 0;
virtual void SetTransform(const MeshHandle& meshHandle, const Transform& transform,
const Vector3& nonUniformScale = Vector3::CreateOne()) = 0;
//! Gets the transform for a given mesh handle.
virtual Transform GetTransform(const MeshHandle& meshHandle) = 0;
//! Gets the non-uniform scale for a given mesh handle.
virtual Vector3 GetNonUniformScale(const MeshHandle& meshHandle) = 0;
//! Sets the sort key for a given mesh handle.
virtual void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) = 0;
//! Gets the sort key for a given mesh handle.
@@ -50,8 +50,10 @@ namespace AZ
// TransformServiceFeatureProcessorInterface overrides ...
ObjectId ReserveObjectId() override;
void ReleaseObjectId(ObjectId& id) override;
void SetTransformForId(ObjectId id, const AZ::Transform& transform) override;
void SetTransformForId(ObjectId id, const AZ::Transform& transform,
const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne()) override;
AZ::Transform GetTransformForId(ObjectId id) const override;
AZ::Vector3 GetNonUniformScaleForId(ObjectId id) const override;
private:
@@ -13,6 +13,7 @@
#pragma once
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Vector3.h>
#include <Atom/RPI.Public/FeatureProcessor.h>
namespace AZ
@@ -34,11 +35,13 @@ namespace AZ
//! Releases an object ID to be used by others. The passed in handle is invalidated.
virtual void ReleaseObjectId(ObjectId& id) = 0;
//! Sets the transform for a given id. Id must be one reserved earlier.
virtual void SetTransformForId(ObjectId id, const AZ::Transform& transform) = 0;
//! Sets the transform (and optionally non-uniform scale) for a given id. Id must be one reserved earlier.
virtual void SetTransformForId(ObjectId id, const AZ::Transform& transform,
const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne()) = 0;
//! Gets the transform for a given id. Id must be one reserved earlier.
virtual AZ::Transform GetTransformForId(ObjectId) const = 0;
//! Gets the non-uniform scale for a given id. Id must be one reserved earlier.
virtual AZ::Vector3 GetNonUniformScaleForId(ObjectId id) const = 0;
};
}
}
@@ -31,11 +31,12 @@ namespace UnitTest
MOCK_CONST_METHOD1(GetModel, AZStd::intrusive_ptr<AZ::RPI::Model>(const MeshHandle&));
MOCK_CONST_METHOD1(GetMaterialAssignmentMap, const AZ::Render::MaterialAssignmentMap&(const MeshHandle&));
MOCK_METHOD2(ConnectModelChangeEventHandler, void(const MeshHandle&, ModelChangedEvent::Handler&));
MOCK_METHOD2(SetTransform, void(const MeshHandle&, const AZ::Transform&));
MOCK_METHOD3(SetTransform, void(const MeshHandle&, const AZ::Transform&, const AZ::Vector3&));
MOCK_METHOD2(SetExcludeFromReflectionCubeMaps, void(const MeshHandle&, bool));
MOCK_METHOD2(SetMaterialAssignmentMap, void(const MeshHandle&, const AZ::Data::Instance<AZ::RPI::Material>&));
MOCK_METHOD2(SetMaterialAssignmentMap, void(const MeshHandle&, const AZ::Render::MaterialAssignmentMap&));
MOCK_METHOD1(GetTransform, AZ::Transform (const MeshHandle&));
MOCK_METHOD1(GetTransform, AZ::Transform(const MeshHandle&));
MOCK_METHOD1(GetNonUniformScale, AZ::Vector3(const MeshHandle&));
MOCK_METHOD2(SetSortKey, void (const MeshHandle&, AZ::RHI::DrawItemSortKey));
MOCK_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&));
MOCK_METHOD2(SetLodOverride, void(const MeshHandle&, AZ::RPI::Cullable::LodOverride));
@@ -504,7 +504,7 @@ namespace AZ
box.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
box.m_color = color;
box.m_scale = localMatrix3x4.ExtractScale() * extents;
box.m_position = localMatrix3x4.GetTranslation() + center;
box.m_position = matrix3x4 * center;
box.m_rotationMatrix = Matrix3x3::CreateFromMatrix3x4(localMatrix3x4);
box.m_pointSize = m_pointSize;
box.m_viewProjOverrideIndex = viewProjOverrideIndex;
@@ -256,7 +256,7 @@ namespace AZ
}
}
void MeshFeatureProcessor::SetTransform(const MeshHandle& meshHandle, const AZ::Transform& transform)
void MeshFeatureProcessor::SetTransform(const MeshHandle& meshHandle, const AZ::Transform& transform, const AZ::Vector3& nonUniformScale)
{
if (meshHandle.IsValid())
{
@@ -264,12 +264,12 @@ namespace AZ
meshData.m_cullBoundsNeedsUpdate = true;
meshData.m_objectSrgNeedsUpdate = true;
m_transformService->SetTransformForId(meshHandle->m_objectId, transform);
m_transformService->SetTransformForId(meshHandle->m_objectId, transform, nonUniformScale);
// ray tracing data needs to be updated with the new transform
if (m_rayTracingFeatureProcessor)
{
m_rayTracingFeatureProcessor->SetMeshTransform(meshHandle->m_objectId, transform);
m_rayTracingFeatureProcessor->SetMeshTransform(meshHandle->m_objectId, transform, nonUniformScale);
}
}
}
@@ -287,6 +287,19 @@ namespace AZ
}
}
Vector3 MeshFeatureProcessor::GetNonUniformScale(const MeshHandle& meshHandle)
{
if (meshHandle.IsValid())
{
return m_transformService->GetNonUniformScaleForId(meshHandle->m_objectId);
}
else
{
AZ_Assert(false, "Invalid mesh handle");
return Vector3::CreateOne();
}
}
void MeshFeatureProcessor::SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey)
{
if (meshHandle.IsValid())
@@ -845,10 +858,13 @@ namespace AZ
AZ_Assert(m_model, "The model has not finished loading yet");
Transform localToWorld = transformService->GetTransformForId(m_objectId);
Vector3 nonUniformScale = transformService->GetNonUniformScaleForId(m_objectId);
Vector3 center;
float radius;
Aabb localAabb = m_model->GetAabb();
localAabb.MultiplyByScale(nonUniformScale);
localAabb.GetTransformedAabb(localToWorld).GetAsSphere(center, radius);
m_cullable.m_cullData.m_boundingSphere = Sphere(center, radius);
@@ -81,6 +81,7 @@ namespace AZ
->HitGroupIndex(blasIndex)
->Blas(rayTracingSubMesh.m_blas)
->Transform(rayTracingMesh.second.m_transform)
->NonUniformScale(rayTracingMesh.second.m_nonUniformScale)
;
}
@@ -143,7 +143,7 @@ namespace AZ
m_meshInfoBufferNeedsUpdate = true;
}
void RayTracingFeatureProcessor::SetMeshTransform(const ObjectId objectId, AZ::Transform transform)
void RayTracingFeatureProcessor::SetMeshTransform(const ObjectId objectId, const AZ::Transform transform, const AZ::Vector3 nonUniformScale)
{
if (!m_rayTracingEnabled)
{
@@ -154,6 +154,7 @@ namespace AZ
if (itMesh != m_meshes.end())
{
itMesh->second.m_transform = transform;
itMesh->second.m_nonUniformScale = nonUniformScale;
m_revision++;
}
@@ -68,6 +68,9 @@ namespace AZ
// mesh transform
AZ::Transform m_transform = AZ::Transform::CreateIdentity();
// mesh non-uniform scale
AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne();
// flag indicating if the Blas objects in the sub-meshes are built
bool m_blasBuilt = false;
};
@@ -85,7 +88,8 @@ namespace AZ
//! Sets the ray tracing mesh transform
//! This will cause an update to the RayTracing acceleration structure on the next frame
void SetMeshTransform(const ObjectId objectId, const AZ::Transform transform);
void SetMeshTransform(const ObjectId objectId, const AZ::Transform transform,
const AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne());
//! Retrieves ray tracing data for all meshes in the scene
const MeshMap& GetMeshes() const { return m_meshes; }
@@ -210,14 +210,14 @@ namespace AZ
}
}
void TransformServiceFeatureProcessor::SetTransformForId(ObjectId id, const AZ::Transform& transform)
void TransformServiceFeatureProcessor::SetTransformForId(ObjectId id, const AZ::Transform& transform, const AZ::Vector3& nonUniformScale)
{
AZ_Error("TransformServiceFeatureProcessor", m_isWriteable, "Transform data cannot be written to during this phase");
AZ_Error("TransformServiceFeatureProcessor", id.IsValid(), "Attempting to set the transform for an invalid handle.");
if (id.IsValid())
{
AZ::Matrix3x4 matrix3x4 = AZ::Matrix3x4::CreateFromTransform(transform);
matrix3x4.MultiplyByScale(nonUniformScale);
matrix3x4.StoreToRowMajorFloat12(m_objectToWorldTransforms.at(id.GetIndex()).m_transform);
// Inverse transpose to take the non-uniform scale out of the transform for usage with normals.
@@ -228,8 +228,18 @@ namespace AZ
AZ::Transform TransformServiceFeatureProcessor::GetTransformForId(ObjectId id) const
{
AZ_Error("TransformServiceFeatureProcessor", id.IsValid(), "Attempting to set the transform for an invalid handle.");
return AZ::Transform::CreateFromMatrix3x4( Matrix3x4::CreateFromRowMajorFloat12(m_objectToWorldTransforms.at(id.GetIndex()).m_transform) );
AZ_Error("TransformServiceFeatureProcessor", id.IsValid(), "Attempting to get the transform for an invalid handle.");
AZ::Matrix3x4 matrix3x4 = AZ::Matrix3x4::CreateFromRowMajorFloat12(m_objectToWorldTransforms.at(id.GetIndex()).m_transform);
AZ::Transform transform = AZ::Transform::CreateFromMatrix3x4(matrix3x4);
transform.ExtractScale();
return transform;
}
AZ::Vector3 TransformServiceFeatureProcessor::GetNonUniformScaleForId(ObjectId id) const
{
AZ_Error("TransformServiceFeatureProcessor", id.IsValid(), "Attempting to get the non-uniform scale for an invalid handle.");
AZ::Matrix3x4 matrix3x4 = AZ::Matrix3x4::CreateFromRowMajorFloat12(m_objectToWorldTransforms.at(id.GetIndex()).m_transform);
return matrix3x4.RetrieveScale();
}
}
}
@@ -111,6 +111,7 @@ namespace AZ
uint32_t m_instanceID = 0;
uint32_t m_hitGroupIndex = 0;
AZ::Transform m_transform = AZ::Transform::CreateIdentity();
AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne();
RHI::Ptr<RHI::RayTracingBlas> m_blas;
};
using RayTracingTlasInstanceVector = AZStd::vector<RayTracingTlasInstance>;
@@ -154,6 +155,7 @@ namespace AZ
RayTracingTlasDescriptor* InstanceID(uint32_t instanceID);
RayTracingTlasDescriptor* HitGroupIndex(uint32_t hitGroupIndex);
RayTracingTlasDescriptor* Transform(const AZ::Transform& transform);
RayTracingTlasDescriptor* NonUniformScale(const AZ::Vector3& nonUniformScale);
RayTracingTlasDescriptor* Blas(RHI::Ptr<RHI::RayTracingBlas>& blas);
RayTracingTlasDescriptor* InstancesBuffer(RHI::Ptr<RHI::Buffer>& tlasInstances);
RayTracingTlasDescriptor* NumInstances(uint32_t numInstancesInBuffer);
@@ -85,6 +85,13 @@ namespace AZ
return this;
}
RayTracingTlasDescriptor* RayTracingTlasDescriptor::NonUniformScale(const AZ::Vector3& nonUniformScale)
{
AZ_Assert(m_buildContext, "NonUniformSCale property can only be added to an Instance entry");
m_buildContext->m_nonUniformScale = nonUniformScale;
return this;
}
RayTracingTlasDescriptor* RayTracingTlasDescriptor::Blas(RHI::Ptr<RHI::RayTracingBlas>& blas)
{
AZ_Assert(m_buildContext, "Blas property can only be added to an Instance entry");
@@ -89,8 +89,9 @@ namespace AZ
mappedData[i].InstanceID = instance.m_instanceID;
mappedData[i].InstanceContributionToHitGroupIndex = instance.m_hitGroupIndex;
// convert transform to row-major 3x4
AZ::Matrix3x4 matrix34 = AZ::Matrix3x4::CreateFromTransform(instance.m_transform);
matrix34.StoreToRowMajorFloat12(&mappedData[i].Transform[0][0]);
AZ::Matrix3x4 matrix3x4 = AZ::Matrix3x4::CreateFromTransform(instance.m_transform);
matrix3x4.MultiplyByScale(instance.m_nonUniformScale);
matrix3x4.StoreToRowMajorFloat12(&mappedData[i].Transform[0][0]);
mappedData[i].AccelerationStructure = static_cast<DX12::Buffer*>(blas->GetBuffers().m_blasBuffer.get())->GetMemoryView().GetGpuAddress();
// [GFX TODO][ATOM-5270] Add ray tracing TLAS instance mask support
mappedData[i].InstanceMask = 0x1;
@@ -92,9 +92,9 @@ namespace AZ
mappedData[i].instanceCustomIndex = instance.m_instanceID;
mappedData[i].instanceShaderBindingTableRecordOffset = instance.m_hitGroupIndex;
// convert transform to row-major 3x4
AZ::Matrix3x4 matrix34 = AZ::Matrix3x4::CreateFromTransform(instance.m_transform);
matrix34.StoreToRowMajorFloat12(&mappedData[i].transform.matrix[0][0]);
AZ::Matrix3x4 matrix3x4 = AZ::Matrix3x4::CreateFromTransform(instance.m_transform);
matrix3x4.MultiplyByScale(instance.m_nonUniformScale);
matrix3x4.StoreToRowMajorFloat12(&mappedData[i].transform.matrix[0][0]);
RayTracingBlas* blas = static_cast<RayTracingBlas*>(instance.m_blas.get());
VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {};
@@ -73,12 +73,14 @@ namespace AZ
//! [GFX TODO][ATOM-4343 Bake mesh spatial during AP processing]
//!
//! @param modelTransform a transform that puts the model into the ray's coordinate space
//! @param nonUniformScale Non-uniform scale applied in the model's local frame.
//! @param rayStart position where the ray starts
//! @param dir direction where the ray ends (does not have to be unit length)
//! @param distanceFactor if an intersection is detected, this will be set such that distanceFactor * dir.length == distance to intersection
//! @param normal if an intersection is detected, this will be set to the normal at the point of intersection
//! @return true if the ray intersects the mesh
bool RayIntersection(const AZ::Transform& modelTransform, const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distanceFactor, AZ::Vector3& normal) const;
bool RayIntersection(const AZ::Transform& modelTransform, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayStart,
const AZ::Vector3& dir, float& distanceFactor, AZ::Vector3& normal) const;
//! Get available UV names from the model and its lods.
const AZStd::unordered_set<AZ::Name>& GetUvNames() const;
@@ -164,18 +164,22 @@ namespace AZ
return false;
}
bool Model::RayIntersection(const AZ::Transform& modelTransform, const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distanceFactor, AZ::Vector3& normal) const
bool Model::RayIntersection(const AZ::Transform& modelTransform, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayStart, const AZ::Vector3& dir, float& distanceFactor, AZ::Vector3& normal) const
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
const AZ::Vector3 clampedScale = nonUniformScale.GetMax(AZ::Vector3(AZ::MinTransformScale));
const AZ::Transform inverseTM = modelTransform.GetInverse();
const AZ::Vector3 raySrcLocal = inverseTM.TransformPoint(rayStart);
const AZ::Vector3 raySrcLocal = inverseTM.TransformPoint(rayStart) / clampedScale;
// Instead of just rotating 'dir' we need it to be scaled too, so that 'distanceFactor' will be in the target units rather than object local units.
const AZ::Vector3 rayDest = rayStart + dir;
const AZ::Vector3 rayDestLocal = inverseTM.TransformPoint(rayDest);
const AZ::Vector3 rayDestLocal = inverseTM.TransformPoint(rayDest) / clampedScale;
const AZ::Vector3 rayDirLocal = rayDestLocal - raySrcLocal;
return LocalRayIntersection(raySrcLocal, rayDirLocal, distanceFactor, normal);
bool result = LocalRayIntersection(raySrcLocal, rayDirLocal, distanceFactor, normal);
normal = (normal * clampedScale).GetNormalized();
return result;
}
const AZStd::unordered_set<AZ::Name>& Model::GetUvNames() const