Merge remote-tracking branch 'upstream/development' into thin-transmission
commit
fe163bc930
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 <AzCore/std/containers/span.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
|
||||
//! This file holds useful material related utility functions.
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
enum class TransformType
|
||||
{
|
||||
Invalid,
|
||||
Scale,
|
||||
Rotate,
|
||||
Translate
|
||||
};
|
||||
|
||||
struct UvTransformDescriptor
|
||||
{
|
||||
Vector2 m_center{ Vector2::CreateZero() };
|
||||
float m_scale{ 1.0f };
|
||||
float m_scaleX{ 1.0f };
|
||||
float m_scaleY{ 1.0f };
|
||||
float m_translateX{ 0.0f };
|
||||
float m_translateY{ 0.0f };
|
||||
float m_rotateDegrees{ 0.0f };
|
||||
};
|
||||
|
||||
// Create a 3x3 uv transform matrix from a set of input properties.
|
||||
Matrix3x3 CreateUvTransformMatrix(const UvTransformDescriptor& desc, const AZStd::span<const TransformType> transformOrder);
|
||||
}
|
||||
|
||||
AZ_TYPE_INFO_SPECIALIZE(Render::TransformType, "{D8C15D33-CE3D-4297-A646-030B0625BF84}");
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 <Atom/Utils/MaterialUtils.h>
|
||||
|
||||
namespace AZ::Render
|
||||
{
|
||||
|
||||
Matrix3x3 CreateUvTransformMatrix(const UvTransformDescriptor& desc, AZStd::span<const TransformType> transformOrder)
|
||||
{
|
||||
float translateX = desc.m_translateX;
|
||||
float translateY = desc.m_translateY;
|
||||
|
||||
if (desc.m_scaleX != 0.0f)
|
||||
{
|
||||
translateX *= (1.0f / desc.m_scaleX);
|
||||
}
|
||||
|
||||
if (desc.m_scaleY != 0.0f)
|
||||
{
|
||||
translateY *= (1.0f / desc.m_scaleY);
|
||||
}
|
||||
|
||||
Matrix3x3 translateCenter2D = Matrix3x3::CreateIdentity();
|
||||
translateCenter2D.SetBasisZ(-desc.m_center.GetX(), -desc.m_center.GetY(), 1.0f);
|
||||
|
||||
Matrix3x3 translateCenterInv2D = Matrix3x3::CreateIdentity();
|
||||
translateCenterInv2D.SetBasisZ(desc.m_center.GetX(), desc.m_center.GetY(), 1.0f);
|
||||
|
||||
Matrix3x3 scale2D = Matrix3x3::CreateDiagonal(AZ::Vector3(desc.m_scaleX * desc.m_scale, desc.m_scaleY * desc.m_scale, 1.0f));
|
||||
|
||||
Matrix3x3 translate2D = Matrix3x3::CreateIdentity();
|
||||
translate2D.SetBasisZ(translateX, translateY, 1.0f);
|
||||
|
||||
Matrix3x3 rotate2D = Matrix3x3::CreateRotationZ(AZ::DegToRad(desc.m_rotateDegrees));
|
||||
|
||||
Matrix3x3 transform = translateCenter2D;
|
||||
for (auto transformType : transformOrder)
|
||||
{
|
||||
switch (transformType)
|
||||
{
|
||||
case TransformType::Scale:
|
||||
transform = scale2D * transform;
|
||||
break;
|
||||
case TransformType::Rotate:
|
||||
transform = rotate2D * transform;
|
||||
break;
|
||||
case TransformType::Translate:
|
||||
transform = translate2D * transform;
|
||||
break;
|
||||
}
|
||||
}
|
||||
transform = translateCenterInv2D * transform;
|
||||
return transform;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* 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 <SurfaceData/Utility/SurfaceDataUtility.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAssetCreator.h>
|
||||
|
||||
namespace SurfaceData
|
||||
{
|
||||
void SurfaceTagWeights::AssignSurfaceTagWeights(const AzFramework::SurfaceData::SurfaceTagWeightList& weights)
|
||||
{
|
||||
m_weights.clear();
|
||||
m_weights.reserve(weights.size());
|
||||
for (auto& weight : weights)
|
||||
{
|
||||
m_weights.emplace(weight.m_surfaceType, weight.m_weight);
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceTagWeights::AssignSurfaceTagWeights(const SurfaceTagVector& tags, float weight)
|
||||
{
|
||||
m_weights.clear();
|
||||
m_weights.reserve(tags.size());
|
||||
for (auto& tag : tags)
|
||||
{
|
||||
m_weights[tag] = weight;
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceTagWeights::AddSurfaceTagWeight(const AZ::Crc32 tag, const float value)
|
||||
{
|
||||
m_weights[tag] = value;
|
||||
}
|
||||
|
||||
void SurfaceTagWeights::Clear()
|
||||
{
|
||||
m_weights.clear();
|
||||
}
|
||||
|
||||
size_t SurfaceTagWeights::GetSize() const
|
||||
{
|
||||
return m_weights.size();
|
||||
}
|
||||
|
||||
AzFramework::SurfaceData::SurfaceTagWeightList SurfaceTagWeights::GetSurfaceTagWeightList() const
|
||||
{
|
||||
AzFramework::SurfaceData::SurfaceTagWeightList weights;
|
||||
weights.reserve(m_weights.size());
|
||||
for (auto& weight : m_weights)
|
||||
{
|
||||
weights.emplace_back(weight.first, weight.second);
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
bool SurfaceTagWeights::operator==(const SurfaceTagWeights& rhs) const
|
||||
{
|
||||
// If the lists are different sizes, they're not equal.
|
||||
if (m_weights.size() != rhs.m_weights.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& weight : m_weights)
|
||||
{
|
||||
auto rhsWeight = rhs.m_weights.find(weight.first);
|
||||
if ((rhsWeight == rhs.m_weights.end()) || (rhsWeight->second != weight.second))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All the entries matched, and the lists are the same size, so they're equal.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SurfaceTagWeights::SurfaceWeightsAreEqual(const AzFramework::SurfaceData::SurfaceTagWeightList& compareWeights) const
|
||||
{
|
||||
// If the lists are different sizes, they're not equal.
|
||||
if (m_weights.size() != compareWeights.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& weight : m_weights)
|
||||
{
|
||||
auto maskEntry = AZStd::find_if(
|
||||
compareWeights.begin(), compareWeights.end(),
|
||||
[weight](const AzFramework::SurfaceData::SurfaceTagWeight& compareWeight) -> bool
|
||||
{
|
||||
return (weight.first == compareWeight.m_surfaceType) && (weight.second == compareWeight.m_weight);
|
||||
});
|
||||
|
||||
// If we didn't find a match, they're not equal.
|
||||
if (maskEntry == compareWeights.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All the entries matched, and the lists are the same size, so they're equal.
|
||||
return true;
|
||||
}
|
||||
|
||||
void SurfaceTagWeights::EnumerateWeights(AZStd::function<bool(AZ::Crc32 tag, float weight)> weightCallback) const
|
||||
{
|
||||
for (auto& [tag, weight] : m_weights)
|
||||
{
|
||||
if (!weightCallback(tag, weight))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SurfaceTagWeights::HasValidTags() const
|
||||
{
|
||||
for (const auto& sourceTag : m_weights)
|
||||
{
|
||||
if (sourceTag.first != Constants::s_unassignedTagCrc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SurfaceTagWeights::HasMatchingTag(const AZ::Crc32& sampleTag) const
|
||||
{
|
||||
return m_weights.find(sampleTag) != m_weights.end();
|
||||
}
|
||||
|
||||
bool SurfaceTagWeights::HasAnyMatchingTags(const SurfaceTagVector& sampleTags) const
|
||||
{
|
||||
for (const auto& sampleTag : sampleTags)
|
||||
{
|
||||
if (HasMatchingTag(sampleTag))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SurfaceTagWeights::HasMatchingTag(const AZ::Crc32& sampleTag, float weightMin, float weightMax) const
|
||||
{
|
||||
auto maskItr = m_weights.find(sampleTag);
|
||||
return maskItr != m_weights.end() && weightMin <= maskItr->second && weightMax >= maskItr->second;
|
||||
}
|
||||
|
||||
bool SurfaceTagWeights::HasAnyMatchingTags(const SurfaceTagVector& sampleTags, float weightMin, float weightMax) const
|
||||
{
|
||||
for (const auto& sampleTag : sampleTags)
|
||||
{
|
||||
if (HasMatchingTag(sampleTag, weightMin, weightMax))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
SurfacePointList::SurfacePointList(AZStd::initializer_list<const AzFramework::SurfaceData::SurfacePoint> surfacePoints)
|
||||
{
|
||||
ReserveSpace(surfacePoints.size());
|
||||
|
||||
for (auto& point : surfacePoints)
|
||||
{
|
||||
SurfaceTagWeights weights(point.m_surfaceTags);
|
||||
AddSurfacePoint(AZ::EntityId(), point.m_position, point.m_normal, weights);
|
||||
}
|
||||
}
|
||||
|
||||
void SurfacePointList::AddSurfacePoint(const AZ::EntityId& entityId,
|
||||
const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceTagWeights& masks)
|
||||
{
|
||||
// When adding a surface point, we'll either merge it with a similar existing point, or else add it in order of
|
||||
// decreasing Z, so that our final results are sorted.
|
||||
|
||||
for (size_t index = 0; index < m_surfacePositionList.size(); ++index)
|
||||
{
|
||||
// (Someday we should add a configurable tolerance for comparison)
|
||||
if (m_surfacePositionList[index].IsClose(position) && m_surfaceNormalList[index].IsClose(normal))
|
||||
{
|
||||
// consolidate points with similar attributes by adding masks/weights to the similar point instead of adding a new one.
|
||||
m_surfaceWeightsList[index].AddSurfaceWeightsIfGreater(masks);
|
||||
return;
|
||||
}
|
||||
else if (m_surfacePositionList[index].GetZ() < position.GetZ())
|
||||
{
|
||||
m_pointBounds.AddPoint(position);
|
||||
m_surfacePositionList.insert(m_surfacePositionList.begin() + index, position);
|
||||
m_surfaceNormalList.insert(m_surfaceNormalList.begin() + index, normal);
|
||||
m_surfaceWeightsList.insert(m_surfaceWeightsList.begin() + index, masks);
|
||||
m_surfaceCreatorIdList.insert(m_surfaceCreatorIdList.begin() + index, entityId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The point wasn't merged and the sort puts it at the end, so just add the point to the end of the list.
|
||||
m_pointBounds.AddPoint(position);
|
||||
m_surfacePositionList.emplace_back(position);
|
||||
m_surfaceNormalList.emplace_back(normal);
|
||||
m_surfaceWeightsList.emplace_back(masks);
|
||||
m_surfaceCreatorIdList.emplace_back(entityId);
|
||||
}
|
||||
|
||||
void SurfacePointList::Clear()
|
||||
{
|
||||
m_surfacePositionList.clear();
|
||||
m_surfaceNormalList.clear();
|
||||
m_surfaceWeightsList.clear();
|
||||
m_surfaceCreatorIdList.clear();
|
||||
}
|
||||
|
||||
void SurfacePointList::ReserveSpace(size_t maxPointsPerInput)
|
||||
{
|
||||
AZ_Assert(
|
||||
m_surfacePositionList.size() < maxPointsPerInput,
|
||||
"Trying to reserve space on a list that is already using more points than requested.");
|
||||
|
||||
m_surfaceCreatorIdList.reserve(maxPointsPerInput);
|
||||
m_surfacePositionList.reserve(maxPointsPerInput);
|
||||
m_surfaceNormalList.reserve(maxPointsPerInput);
|
||||
m_surfaceWeightsList.reserve(maxPointsPerInput);
|
||||
}
|
||||
|
||||
bool SurfacePointList::IsEmpty() const
|
||||
{
|
||||
return m_surfacePositionList.empty();
|
||||
}
|
||||
|
||||
size_t SurfacePointList::GetSize() const
|
||||
{
|
||||
return m_surfacePositionList.size();
|
||||
}
|
||||
|
||||
void SurfacePointList::EnumeratePoints(
|
||||
AZStd::function<bool(const AZ::Vector3&, const AZ::Vector3&, const SurfaceData::SurfaceTagWeights&)>
|
||||
pointCallback) const
|
||||
{
|
||||
for (size_t index = 0; index < m_surfacePositionList.size(); index++)
|
||||
{
|
||||
if (!pointCallback(m_surfacePositionList[index], m_surfaceNormalList[index], m_surfaceWeightsList[index]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SurfacePointList::ModifySurfaceWeights(
|
||||
const AZ::EntityId& currentEntityId,
|
||||
AZStd::function<void(const AZ::Vector3& position, SurfaceData::SurfaceTagWeights& surfaceWeights)> modificationWeightCallback)
|
||||
{
|
||||
for (size_t index = 0; index < m_surfacePositionList.size(); index++)
|
||||
{
|
||||
if (m_surfaceCreatorIdList[index] != currentEntityId)
|
||||
{
|
||||
modificationWeightCallback(m_surfacePositionList[index], m_surfaceWeightsList[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AzFramework::SurfaceData::SurfacePoint SurfacePointList::GetHighestSurfacePoint() const
|
||||
{
|
||||
AzFramework::SurfaceData::SurfacePoint point;
|
||||
point.m_position = m_surfacePositionList.front();
|
||||
point.m_normal = m_surfaceNormalList.front();
|
||||
point.m_surfaceTags = m_surfaceWeightsList.front().GetSurfaceTagWeightList();
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
void SurfacePointList::FilterPoints(const SurfaceTagVector& desiredTags)
|
||||
{
|
||||
// Filter out any points that don't match our search tags.
|
||||
// This has to be done after the Surface Modifiers have processed the points, not at point insertion time, because
|
||||
// Surface Modifiers add tags to existing points.
|
||||
size_t listSize = m_surfacePositionList.size();
|
||||
size_t index = 0;
|
||||
for (; index < listSize; index++)
|
||||
{
|
||||
if (!m_surfaceWeightsList[index].HasAnyMatchingTags(desiredTags))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index != listSize)
|
||||
{
|
||||
size_t next = index + 1;
|
||||
for (; next < listSize; ++next)
|
||||
{
|
||||
if (m_surfaceWeightsList[index].HasAnyMatchingTags(desiredTags))
|
||||
{
|
||||
m_surfaceCreatorIdList[index] = m_surfaceCreatorIdList[next];
|
||||
m_surfacePositionList[index] = m_surfacePositionList[next];
|
||||
m_surfaceNormalList[index] = m_surfaceNormalList[next];
|
||||
m_surfaceWeightsList[index] = m_surfaceWeightsList[next];
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
m_surfaceCreatorIdList.resize(index);
|
||||
m_surfacePositionList.resize(index);
|
||||
m_surfaceNormalList.resize(index);
|
||||
m_surfaceWeightsList.resize(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue