Pārlūkot izejas kodu

use PrimitiveAssets Gem to visualize primitives (#485)

Use PrimitiveAssets Gem to visualize primitives

---------

Signed-off-by: Jan Hanca <[email protected]>
Jan Hanca 2 gadi atpakaļ
vecāks
revīzija
d5726250fd

+ 96 - 85
Gems/ROS2/Code/Source/RobotImporter/URDF/VisualsMaker.cpp

@@ -18,16 +18,11 @@
 #include <AzCore/Component/TransformBus.h>
 #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
 #include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
-#include <LmbrCentral/Shape/BoxShapeComponentBus.h>
-#include <LmbrCentral/Shape/CylinderShapeComponentBus.h>
-#include <LmbrCentral/Shape/EditorShapeComponentBus.h>
-#include <LmbrCentral/Shape/SphereShapeComponentBus.h>
 
 namespace ROS2
 {
     VisualsMaker::VisualsMaker() = default;
-    VisualsMaker::VisualsMaker(
-        MaterialNameMap materials, const AZStd::shared_ptr<Utils::UrdfAssetMap>& urdfAssetsMapping)
+    VisualsMaker::VisualsMaker(MaterialNameMap materials, const AZStd::shared_ptr<Utils::UrdfAssetMap>& urdfAssetsMapping)
         : m_materials(AZStd::move(materials))
         , m_urdfAssetsMapping(urdfAssetsMapping)
     {
@@ -54,7 +49,10 @@ namespace ROS2
 
             for (uint64_t index = 0; index < link->VisualCount(); index++)
             {
-                auto createdEntity = AddVisual(link->VisualByIndex(index), entityId, PrefabMakerUtils::MakeEntityName(link->Name().c_str(), typeString, nameSuffixIndex));
+                auto createdEntity = AddVisual(
+                    link->VisualByIndex(index),
+                    entityId,
+                    PrefabMakerUtils::MakeEntityName(link->Name().c_str(), typeString, nameSuffixIndex));
                 if (createdEntity.IsValid())
                 {
                     createdEntities.emplace_back(createdEntity);
@@ -100,7 +98,6 @@ namespace ROS2
         // Apply transform as per origin
         PrefabMakerUtils::SetEntityTransformLocal(visual->RawPose(), entityId);
 
-        AZ::Entity* entity = AzToolsFramework::GetEntityById(entityId);
         auto geometry = visual->Geom();
         switch (geometry->Type())
         {
@@ -108,91 +105,76 @@ namespace ROS2
             {
                 auto sphereGeometry = geometry->SphereShape();
                 AZ_Assert(sphereGeometry, "geometry is not Sphere");
-                entity->CreateComponent(LmbrCentral::EditorSphereShapeComponentTypeId);
-                entity->Activate();
-                LmbrCentral::SphereShapeComponentRequestsBus::Event(
-                    entityId, &LmbrCentral::SphereShapeComponentRequests::SetRadius, sphereGeometry->Radius());
-                LmbrCentral::EditorShapeComponentRequestsBus::Event(
-                    entityId, &LmbrCentral::EditorShapeComponentRequests::SetVisibleInGame, true);
-                entity->Deactivate();
+                // Convert radius to diameter: the `_sphere_1x1.fbx.azmodel` model has a diameter of 1
+                const AZ::Vector3 sphereDimensions(sphereGeometry->Radius() * 2.0f);
+
+                // The `_sphere_1x1.fbx.azmodel` is created by Asset Processor based on O3DE `PrimitiveAssets` Gem source.
+                AZ::Data::AssetId assetId;
+                const char* sphereAssetRelPath = "objects/_primitives/_sphere_1x1.fbx.azmodel"; // relative path to cache folder.
+                AZ::Data::AssetCatalogRequestBus::BroadcastResult(
+                    assetId,
+                    &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
+                    sphereAssetRelPath,
+                    AZ::Data::s_invalidAssetType,
+                    false);
+                AZ_Warning("AddVisual", assetId.IsValid(), "There is no product asset for %s.", sphereAssetRelPath);
+
+                AddVisualAssetToEntity(entityId, assetId, sphereDimensions);
             }
             break;
         case sdf::GeometryType::CYLINDER:
             {
                 auto cylinderGeometry = geometry->CylinderShape();
                 AZ_Assert(cylinderGeometry, "geometry is not Cylinder");
-                entity->CreateComponent(LmbrCentral::EditorCylinderShapeComponentTypeId);
-                entity->Activate();
-                LmbrCentral::CylinderShapeComponentRequestsBus::Event(
-                    entityId, &LmbrCentral::CylinderShapeComponentRequests::SetRadius, cylinderGeometry->Radius());
-                LmbrCentral::CylinderShapeComponentRequestsBus::Event(
-                    entityId, &LmbrCentral::CylinderShapeComponentRequests::SetHeight, cylinderGeometry->Length());
-                LmbrCentral::EditorShapeComponentRequestsBus::Event(
-                    entityId, &LmbrCentral::EditorShapeComponentRequests::SetVisibleInGame, true);
-                entity->Deactivate();
+                // Convert radius to diameter: the `_cylinder_1x1.fbx.azmodel` model has a diameter of 1
+                const AZ::Vector3 cylinderDimensions(
+                    cylinderGeometry->Radius() * 2.0f, cylinderGeometry->Radius() * 2.0f, cylinderGeometry->Length());
+
+                // The `_cylinder_1x1.fbx.azmodel` is created by Asset Processor based on O3DE `PrimitiveAssets` Gem source.
+                AZ::Data::AssetId assetId;
+                const char* cylinderAssetRelPath = "objects/_primitives/_cylinder_1x1.fbx.azmodel"; // relative path to cache folder.
+                AZ::Data::AssetCatalogRequestBus::BroadcastResult(
+                    assetId,
+                    &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
+                    cylinderAssetRelPath,
+                    AZ::Data::s_invalidAssetType,
+                    false);
+                AZ_Warning("AddVisual", assetId.IsValid(), "There is no product asset for %s.", cylinderAssetRelPath);
+
+                AddVisualAssetToEntity(entityId, assetId, cylinderDimensions);
             }
             break;
         case sdf::GeometryType::BOX:
             {
                 auto boxGeometry = geometry->BoxShape();
                 AZ_Assert(boxGeometry, "geometry is not Box");
-                entity->CreateComponent(LmbrCentral::EditorBoxShapeComponentTypeId);
-                AZ::Vector3 boxDimensions = URDF::TypeConversions::ConvertVector3(boxGeometry->Size());
-                entity->Activate();
-                LmbrCentral::BoxShapeComponentRequestsBus::Event(
-                    entityId, &LmbrCentral::BoxShapeComponentRequests::SetBoxDimensions, boxDimensions);
-                LmbrCentral::EditorShapeComponentRequestsBus::Event(
-                    entityId, &LmbrCentral::EditorShapeComponentRequests::SetVisibleInGame, true);
-                entity->Deactivate();
+                const AZ::Vector3 boxDimensions = URDF::TypeConversions::ConvertVector3(boxGeometry->Size());
+
+                // The `_box_1x1.fbx.azmodel` is created by Asset Processor based on O3DE `PrimitiveAssets` Gem source.
+                AZ::Data::AssetId assetId;
+                const char* boxAssetRelPath = "objects/_primitives/_box_1x1.fbx.azmodel"; // relative path to cache folder.
+                AZ::Data::AssetCatalogRequestBus::BroadcastResult(
+                    assetId,
+                    &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
+                    boxAssetRelPath,
+                    AZ::Data::s_invalidAssetType,
+                    false);
+                AZ_Warning("AddVisual", assetId.IsValid(), "There is no product asset for %s.", boxAssetRelPath);
+
+                AddVisualAssetToEntity(entityId, assetId, boxDimensions);
             }
             break;
         case sdf::GeometryType::MESH:
             {
                 auto meshGeometry = geometry->MeshShape();
                 AZ_Assert(meshGeometry, "geometry is not Mesh");
+                const AZ::Vector3 scaleVector = URDF::TypeConversions::ConvertVector3(meshGeometry->Scale());
 
                 const auto asset = PrefabMakerUtils::GetAssetFromPath(*m_urdfAssetsMapping, AZStd::string(meshGeometry->Uri().c_str()));
+                AZ::Data::AssetId assetId = Utils::GetModelProductAssetId(asset->m_sourceGuid);
+                AZ_Warning("AddVisual", assetId.IsValid(), "There is no product asset for %s.", asset->m_sourceAssetRelativePath.c_str());
 
-                if (asset)
-                {
-                    auto editorMeshComponent = entity->CreateComponent(AZ::Render::EditorMeshComponentTypeId);
-
-                    // Prepare scale
-                    AZ::Vector3 scaleVector = URDF::TypeConversions::ConvertVector3(meshGeometry->Scale());
-                    bool isUniformScale =
-                        AZ::IsClose(scaleVector.GetMaxElement(), scaleVector.GetMinElement(), AZ::Constants::FloatEpsilon);
-                    if (!isUniformScale)
-                    {
-                        entity->CreateComponent<AzToolsFramework::Components::EditorNonUniformScaleComponent>();
-                    }
-
-                    if (editorMeshComponent)
-                    {
-                        auto editorBaseComponent = azrtti_cast<AzToolsFramework::Components::EditorComponentBase*>(editorMeshComponent);
-                        AZ_Assert(editorBaseComponent, "EditorMeshComponent didn't derive from EditorComponentBase.");
-
-                        AZ::Data::AssetId modelId = Utils::GetModelProductAssetId(asset->m_sourceGuid);
-                        AZ_Warning(
-                            "AddVisual",
-                            modelId.IsValid(),
-                            "There is no product asset for %s.",
-                            asset->m_sourceAssetRelativePath.c_str());
-                        editorBaseComponent->SetPrimaryAsset(modelId);
-                    }
-
-                    entity->Activate();
-
-                    // Set scale, uniform or non-uniform
-                    if (isUniformScale)
-                    {
-                        AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalUniformScale, scaleVector.GetX());
-                    }
-                    else
-                    {
-                        AZ::NonUniformScaleRequestBus::Event(entityId, &AZ::NonUniformScaleRequests::SetScale, scaleVector);
-                    }
-                    entity->Deactivate();
-                }
+                AddVisualAssetToEntity(entityId, assetId, scaleVector);
             }
             break;
         default:
@@ -201,10 +183,48 @@ namespace ROS2
         }
     }
 
+    void VisualsMaker::AddVisualAssetToEntity(AZ::EntityId entityId, const AZ::Data::AssetId& assetId, const AZ::Vector3& scale) const
+    {
+        if (!assetId.IsValid())
+        {
+            return;
+        }
+
+        AZ::Entity* entity = AzToolsFramework::GetEntityById(entityId);
+        auto editorMeshComponent = entity->CreateComponent(AZ::Render::EditorMeshComponentTypeId);
+
+        // Prepare scale
+        bool isUniformScale = AZ::IsClose(scale.GetMaxElement(), scale.GetMinElement(), AZ::Constants::FloatEpsilon);
+        if (!isUniformScale)
+        {
+            entity->CreateComponent<AzToolsFramework::Components::EditorNonUniformScaleComponent>();
+        }
+
+        if (editorMeshComponent)
+        {
+            auto editorBaseComponent = azrtti_cast<AzToolsFramework::Components::EditorComponentBase*>(editorMeshComponent);
+            AZ_Assert(editorBaseComponent, "EditorMeshComponent didn't derive from EditorComponentBase.");
+            editorBaseComponent->SetPrimaryAsset(assetId);
+        }
+
+        entity->Activate();
+
+        // Set scale, uniform or non-uniform
+        if (isUniformScale)
+        {
+            AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalUniformScale, scale.GetX());
+        }
+        else
+        {
+            AZ::NonUniformScaleRequestBus::Event(entityId, &AZ::NonUniformScaleRequests::SetScale, scale);
+        }
+        entity->Deactivate();
+    }
+
     void VisualsMaker::AddMaterialForVisual(const sdf::Visual* visual, AZ::EntityId entityId) const
     {
         // URDF does not include information from <gazebo> tags with specific materials, diffuse, specular and emissive params
-        if (!visual->Material() || !visual->Geom())
+        if (!visual->Material())
         {
             // Material is optional, and it requires geometry
             return;
@@ -218,21 +238,12 @@ namespace ROS2
         const AZStd::string azMaterialName{ materialName.c_str(), materialName.size() };
 
         // If present in map, take map color definition as priority, otherwise apply local node definition
-        const auto materialColorUrdf = m_materials.contains(azMaterialName) ? m_materials.at(azMaterialName)->Diffuse() : visual->Material()->Diffuse();
-
+        const auto materialColorUrdf =
+            m_materials.contains(azMaterialName) ? m_materials.at(azMaterialName)->Diffuse() : visual->Material()->Diffuse();
         const AZ::Color materialColor = URDF::TypeConversions::ConvertColor(materialColorUrdf);
-        bool isPrimitive = visual->Geom()->Type() != sdf::GeometryType::MESH;
-        if (isPrimitive)
-        { // For primitives, set the color in the shape component
-            entity->Activate();
-            LmbrCentral::EditorShapeComponentRequestsBus::Event(
-                entityId, &LmbrCentral::EditorShapeComponentRequests::SetShapeColor, materialColor);
-            entity->Deactivate();
-            return;
-        }
 
         entity->CreateComponent(AZ::Render::EditorMaterialComponentTypeId);
-        AZ_Printf("AddVisual", "Setting color for material %s\n", azMaterialName.c_str());
+        AZ_Trace("AddVisual", "Setting color for material %s\n", azMaterialName.c_str());
         entity->Activate();
         AZ::Render::MaterialComponentRequestBus::Event(
             entityId,

+ 3 - 3
Gems/ROS2/Code/Source/RobotImporter/URDF/VisualsMaker.h

@@ -11,6 +11,7 @@
 #include "UrdfParser.h"
 #include <AzCore/Component/EntityId.h>
 #include <AzCore/IO/Path/Path.h>
+#include <AzCore/Math/Vector3.h>
 #include <AzCore/std/containers/unordered_map.h>
 #include <AzCore/std/smart_ptr/shared_ptr.h>
 #include <RobotImporter/Utils/SourceAssetsStorage.h>
@@ -24,9 +25,7 @@ namespace ROS2
         using MaterialNameMap = AZStd::unordered_map<AZStd::string, const sdf::Material*>;
 
         VisualsMaker();
-        VisualsMaker(
-            MaterialNameMap materials,
-            const AZStd::shared_ptr<Utils::UrdfAssetMap>& urdfAssetsMapping);
+        VisualsMaker(MaterialNameMap materials, const AZStd::shared_ptr<Utils::UrdfAssetMap>& urdfAssetsMapping);
 
         //! Add zero, one or many visual elements to a given entity (depending on link content).
         //! Note that a sub-entity will be added to hold each visual (since they can have different transforms).
@@ -38,6 +37,7 @@ namespace ROS2
     private:
         AZ::EntityId AddVisual(const sdf::Visual* visual, AZ::EntityId entityId, const AZStd::string& generatedName) const;
         void AddVisualToEntity(const sdf::Visual* visual, AZ::EntityId entityId) const;
+        void AddVisualAssetToEntity(AZ::EntityId entityId, const AZ::Data::AssetId& assetId, const AZ::Vector3& scale) const;
         void AddMaterialForVisual(const sdf::Visual* visual, AZ::EntityId entityId) const;
 
         MaterialNameMap m_materials;

+ 2 - 0
Gems/ROS2/gem.json

@@ -30,7 +30,9 @@
         "Atom_Component_DebugCamera",
         "CommonFeaturesAtom",
         "PhysX",
+        "PrimitiveAssets",
         "StartingPointInput"
+
     ],
     "restricted": "ROS2",
     "repo_uri": "https://raw.githubusercontent.com/o3de/o3de-extras/development",