3
0

MaterialPropertyUtil.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Atom/RPI.Edit/Common/AssetUtils.h>
  9. #include <Atom/RPI.Reflect/Image/AttachmentImageAsset.h>
  10. #include <Atom/RPI.Reflect/Image/ImageAsset.h>
  11. #include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
  12. #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
  13. #include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
  14. #include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
  15. #include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
  16. #include <AtomToolsFramework/Util/Util.h>
  17. #include <AzCore/Math/Color.h>
  18. #include <AzCore/Math/Matrix3x3.h>
  19. #include <AzCore/Math/Matrix3x4.h>
  20. #include <AzCore/Math/Matrix4x4.h>
  21. #include <AzCore/Math/Vector2.h>
  22. #include <AzCore/Math/Vector3.h>
  23. #include <AzCore/Math/Vector4.h>
  24. namespace AtomToolsFramework
  25. {
  26. AZ::RPI::MaterialPropertyValue ConvertToRuntimeType(const AZStd::any& value)
  27. {
  28. return AZ::RPI::MaterialPropertyValue::FromAny(value);
  29. }
  30. AZStd::any ConvertToEditableType(const AZ::RPI::MaterialPropertyValue& value)
  31. {
  32. return AZ::RPI::MaterialPropertyValue::ToAny(value);
  33. }
  34. void ConvertToPropertyConfig(AtomToolsFramework::DynamicPropertyConfig& propertyConfig, const AZ::RPI::MaterialPropertySourceData& propertyDefinition)
  35. {
  36. propertyConfig.m_name = propertyDefinition.GetName();
  37. propertyConfig.m_displayName = propertyDefinition.m_displayName;
  38. propertyConfig.m_description = propertyDefinition.m_description;
  39. propertyConfig.m_defaultValue = ConvertToEditableType(propertyDefinition.m_value);
  40. propertyConfig.m_min = ConvertToEditableType(propertyDefinition.m_min);
  41. propertyConfig.m_max = ConvertToEditableType(propertyDefinition.m_max);
  42. propertyConfig.m_softMin = ConvertToEditableType(propertyDefinition.m_softMin);
  43. propertyConfig.m_softMax = ConvertToEditableType(propertyDefinition.m_softMax);
  44. propertyConfig.m_step = ConvertToEditableType(propertyDefinition.m_step);
  45. propertyConfig.m_enumValues = propertyDefinition.m_enumValues;
  46. propertyConfig.m_vectorLabels = propertyDefinition.m_vectorLabels;
  47. propertyConfig.m_visible = propertyDefinition.m_visibility != AZ::RPI::MaterialPropertyVisibility::Hidden;
  48. propertyConfig.m_readOnly = propertyDefinition.m_visibility == AZ::RPI::MaterialPropertyVisibility::Disabled;
  49. // Use customized property handler (ImageAssetPropertyHandler) for image asset
  50. if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image)
  51. {
  52. propertyConfig.m_supportedAssetTypes.push_back(azrtti_typeid<AZ::RPI::AttachmentImageAsset>());
  53. propertyConfig.m_supportedAssetTypes.push_back(azrtti_typeid<AZ::RPI::StreamingImageAsset>());
  54. }
  55. // Update the description for material properties to include script name assuming id is set beforehand
  56. propertyConfig.m_description = AZStd::string::format(
  57. "%s%s(Script Name = '%s')",
  58. propertyConfig.m_description.c_str(),
  59. propertyConfig.m_description.empty() ? "" : "\n",
  60. propertyConfig.m_id.GetCStr());
  61. }
  62. void ConvertToPropertyConfig(AtomToolsFramework::DynamicPropertyConfig& propertyConfig, const AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData)
  63. {
  64. propertyConfig.m_description = propertyMetaData.m_description;
  65. propertyConfig.m_min = ConvertToEditableType(propertyMetaData.m_propertyRange.m_min);
  66. propertyConfig.m_max = ConvertToEditableType(propertyMetaData.m_propertyRange.m_max);
  67. propertyConfig.m_softMin = ConvertToEditableType(propertyMetaData.m_propertyRange.m_softMin);
  68. propertyConfig.m_softMax = ConvertToEditableType(propertyMetaData.m_propertyRange.m_softMax);
  69. propertyConfig.m_visible = propertyMetaData.m_visibility != AZ::RPI::MaterialPropertyVisibility::Hidden;
  70. propertyConfig.m_readOnly = propertyMetaData.m_visibility == AZ::RPI::MaterialPropertyVisibility::Disabled;
  71. }
  72. void ConvertToPropertyMetaData(AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData, const AtomToolsFramework::DynamicPropertyConfig& propertyConfig)
  73. {
  74. propertyMetaData.m_description = propertyConfig.m_description;
  75. propertyMetaData.m_propertyRange.m_min = ConvertToRuntimeType(propertyConfig.m_min);
  76. propertyMetaData.m_propertyRange.m_max = ConvertToRuntimeType(propertyConfig.m_max);
  77. propertyMetaData.m_propertyRange.m_softMin = ConvertToRuntimeType(propertyConfig.m_softMin);
  78. propertyMetaData.m_propertyRange.m_softMax = ConvertToRuntimeType(propertyConfig.m_softMax);
  79. if (!propertyConfig.m_visible)
  80. {
  81. propertyMetaData.m_visibility = AZ::RPI::MaterialPropertyVisibility::Hidden;
  82. }
  83. else if (propertyConfig.m_readOnly)
  84. {
  85. propertyMetaData.m_visibility = AZ::RPI::MaterialPropertyVisibility::Disabled;
  86. }
  87. else
  88. {
  89. propertyMetaData.m_visibility = AZ::RPI::MaterialPropertyVisibility::Enabled;
  90. }
  91. }
  92. template<typename T>
  93. bool ComparePropertyValues(const AZStd::any& valueA, const AZStd::any& valueB)
  94. {
  95. return valueA.is<T>() && valueB.is<T>() && *AZStd::any_cast<T>(&valueA) == *AZStd::any_cast<T>(&valueB);
  96. }
  97. bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB)
  98. {
  99. if (valueA.type() != valueB.type())
  100. {
  101. return false;
  102. }
  103. if (ComparePropertyValues<bool>(valueA, valueB) ||
  104. ComparePropertyValues<int32_t>(valueA, valueB) ||
  105. ComparePropertyValues<uint32_t>(valueA, valueB) ||
  106. ComparePropertyValues<float>(valueA, valueB) ||
  107. ComparePropertyValues<double>(valueA, valueB) ||
  108. ComparePropertyValues<AZ::Vector2>(valueA, valueB) ||
  109. ComparePropertyValues<AZ::Vector3>(valueA, valueB) ||
  110. ComparePropertyValues<AZ::Vector4>(valueA, valueB) ||
  111. ComparePropertyValues<AZ::Matrix3x3>(valueA, valueB) ||
  112. ComparePropertyValues<AZ::Matrix3x4>(valueA, valueB) ||
  113. ComparePropertyValues<AZ::Matrix4x4>(valueA, valueB) ||
  114. ComparePropertyValues<AZ::Color>(valueA, valueB) ||
  115. ComparePropertyValues<AZ::Data::AssetId>(valueA, valueB) ||
  116. ComparePropertyValues<AZ::Data::Asset<AZ::Data::AssetData>>(valueA, valueB) ||
  117. ComparePropertyValues<AZ::Data::Asset<AZ::RPI::ImageAsset>>(valueA, valueB) ||
  118. ComparePropertyValues<AZ::Data::Asset<AZ::RPI::AttachmentImageAsset>>(valueA, valueB) ||
  119. ComparePropertyValues<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(valueA, valueB) ||
  120. ComparePropertyValues<AZ::Data::Asset<AZ::RPI::MaterialAsset>>(valueA, valueB) ||
  121. ComparePropertyValues<AZ::Data::Asset<AZ::RPI::MaterialTypeAsset>>(valueA, valueB) ||
  122. ComparePropertyValues<AZStd::string>(valueA, valueB))
  123. {
  124. return true;
  125. }
  126. return false;
  127. }
  128. bool ConvertToExportFormat(
  129. const AZStd::string& exportPath,
  130. [[maybe_unused]] const AZ::Name& propertyId,
  131. const AZ::RPI::MaterialPropertySourceData& propertyDefinition,
  132. AZ::RPI::MaterialPropertyValue& propertyValue)
  133. {
  134. if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum)
  135. {
  136. if (propertyDefinition.m_enumValues.empty())
  137. {
  138. AZ_Error("AtomToolsFramework", false, "No enum values are specified for property: '%s'.", propertyId.GetCStr());
  139. return false;
  140. }
  141. if (propertyValue.Is<uint32_t>())
  142. {
  143. const uint32_t index = propertyValue.GetValue<uint32_t>();
  144. if (index >= propertyDefinition.m_enumValues.size())
  145. {
  146. AZ_Warning(
  147. "AtomToolsFramework",
  148. false,
  149. "Invalid value for material enough property, using default: '%s'.",
  150. propertyId.GetCStr());
  151. propertyValue = propertyDefinition.m_enumValues[0];
  152. return true;
  153. }
  154. propertyValue = propertyDefinition.m_enumValues[index];
  155. return true;
  156. }
  157. if (propertyValue.Is<AZStd::string>())
  158. {
  159. const AZStd::string value = propertyValue.GetValue<AZStd::string>();
  160. if (AZStd::find(propertyDefinition.m_enumValues.begin(), propertyDefinition.m_enumValues.end(), value) ==
  161. propertyDefinition.m_enumValues.end())
  162. {
  163. AZ_Warning(
  164. "AtomToolsFramework",
  165. false,
  166. "Invalid value for material enough property, using default: '%s'.",
  167. propertyId.GetCStr());
  168. propertyValue = propertyDefinition.m_enumValues[0];
  169. return true;
  170. }
  171. propertyValue = value;
  172. return true;
  173. }
  174. AZ_Error(
  175. "AtomToolsFramework", false, "Property is of data type enum but value data type is not supported: '%s'.", propertyId.GetCStr());
  176. return false;
  177. }
  178. // Image asset references must be converted from asset IDs to a relative source file path
  179. if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image)
  180. {
  181. AZStd::string imagePath;
  182. AZ::Data::AssetId imageAssetId;
  183. if (propertyValue.Is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
  184. {
  185. const auto& imageAsset = propertyValue.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
  186. imageAssetId = imageAsset.GetId();
  187. }
  188. if (propertyValue.Is<AZ::Data::Instance<AZ::RPI::Image>>())
  189. {
  190. const auto& image = propertyValue.GetValue<AZ::Data::Instance<AZ::RPI::Image>>();
  191. if (image)
  192. {
  193. imageAssetId = image->GetAssetId();
  194. }
  195. }
  196. imagePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAssetId);
  197. if (imageAssetId.IsValid() && imagePath.empty())
  198. {
  199. AZ_Error("AtomToolsFramework", false, "Image asset could not be found for property: '%s'.", propertyId.GetCStr());
  200. return false;
  201. }
  202. propertyValue = GetPathToExteralReference(exportPath, imagePath);
  203. return true;
  204. }
  205. return true;
  206. }
  207. AZ::RPI::MaterialPropertyDataType GetMaterialPropertyDataTypeFromValue(
  208. AZ::RPI::MaterialPropertyValue& propertyValue, bool hasEnumValues)
  209. {
  210. if (propertyValue.Is<bool>())
  211. {
  212. return AZ::RPI::MaterialPropertyDataType::Bool;
  213. }
  214. if (propertyValue.Is<AZ::s32>())
  215. {
  216. return AZ::RPI::MaterialPropertyDataType::Int;
  217. }
  218. if (propertyValue.Is<AZ::u32>())
  219. {
  220. return AZ::RPI::MaterialPropertyDataType::UInt;
  221. }
  222. if (propertyValue.Is<float>())
  223. {
  224. return AZ::RPI::MaterialPropertyDataType::Float;
  225. }
  226. if (propertyValue.Is<AZ::Vector2>())
  227. {
  228. return AZ::RPI::MaterialPropertyDataType::Vector2;
  229. }
  230. if (propertyValue.Is<AZ::Vector3>())
  231. {
  232. return AZ::RPI::MaterialPropertyDataType::Vector3;
  233. }
  234. if (propertyValue.Is<AZ::Vector4>())
  235. {
  236. return AZ::RPI::MaterialPropertyDataType::Vector4;
  237. }
  238. if (propertyValue.Is<AZ::Color>())
  239. {
  240. return AZ::RPI::MaterialPropertyDataType::Color;
  241. }
  242. if (propertyValue.Is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
  243. {
  244. return AZ::RPI::MaterialPropertyDataType::Image;
  245. }
  246. if (propertyValue.Is<AZ::Data::Instance<AZ::RPI::Image>>())
  247. {
  248. return AZ::RPI::MaterialPropertyDataType::Image;
  249. }
  250. if (propertyValue.Is<AZStd::string>())
  251. {
  252. return hasEnumValues ? AZ::RPI::MaterialPropertyDataType::Enum : AZ::RPI::MaterialPropertyDataType::Image;
  253. }
  254. return AZ::RPI::MaterialPropertyDataType::Invalid;
  255. }
  256. } // namespace AtomToolsFramework