Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wc/snap to terrain - CsvSpawner: Make "snap to terrain" based on collision layer. #74

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.vscode/**
.idea/**

80 changes: 71 additions & 9 deletions Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
*
* This source code is protected under international copyright law. All rights
* reserved and protected by the copyright holders.
* This file is confidential and only available to authorized individuals with the
* permission of the copyright holders. If you encounter this file and do not have
* permission, please contact the copyright holders and delete this file.
* This file is confidential and only available to authorized individuals with
* the permission of the copyright holders. If you encounter this file and do
* not have permission, please contact the copyright holders and delete this
* file.
*/

#include "CsvSpawnerUtils.h"
Expand Down Expand Up @@ -49,7 +50,8 @@ namespace CsvSpawner::CsvSpawnerUtils
->Field("PositionStdDev", &CsvSpawnableAssetConfiguration::m_positionStdDev)
->Field("RotationStdDev", &CsvSpawnableAssetConfiguration::m_rotationStdDev)
->Field("ScaleStdDev", &CsvSpawnableAssetConfiguration::m_scaleStdDev)
->Field("PlaceOnTerrain", &CsvSpawnableAssetConfiguration::m_placeOnTerrain);
->Field("PlaceOnTerrain", &CsvSpawnableAssetConfiguration::m_placeOnTerrain)
->Field("CollisionLayer", &CsvSpawnableAssetConfiguration::m_selectedCollisionLayer);

if (auto* editContext = serializeContext->GetEditContext())
{
Expand Down Expand Up @@ -78,15 +80,32 @@ namespace CsvSpawner::CsvSpawnerUtils
&CsvSpawnableAssetConfiguration::m_placeOnTerrain,
"Place on Terrain",
"Perform scene query raytrace to place on terrain")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &CsvSpawnableAssetConfiguration::OnPlaceOnTerrainChanged)
->DataElement(
AZ::Edit::UIHandlers::Default,
&CsvSpawnableAssetConfiguration::m_scaleStdDev,
"Scale Std. Dev.",
"Scale standard deviation, in meters");
"Scale standard deviation, in meters")
->DataElement(
AZ::Edit::UIHandlers::Default,
&CsvSpawnableAssetConfiguration::m_selectedCollisionLayer,
"Collision Layer",
"To which collision layer this target will be attached")
->Attribute(AZ::Edit::Attributes::ReadOnly, &CsvSpawnableAssetConfiguration::IsCollisionLayerEnabled);
}
}
}

bool CsvSpawnableAssetConfiguration::IsCollisionLayerEnabled() const
{
return !m_placeOnTerrain;
}

AZ::Crc32 CsvSpawnableAssetConfiguration::OnPlaceOnTerrainChanged()
{
return AZ::Edit::PropertyRefreshLevels::EntireTree;
}

AZStd::unordered_map<AZStd::string, CsvSpawnableAssetConfiguration> GetSpawnableAssetFromVector(
AZStd::vector<CsvSpawnableAssetConfiguration> spawnableAssetConfigurations)
{
Expand Down Expand Up @@ -161,6 +180,47 @@ namespace CsvSpawner::CsvSpawnerUtils
return hitPosition;
}

AZStd::optional<AZ::Vector3> RaytraceTerrain(
const AZ::Vector3& location,
const AzPhysics::SceneHandle sceneHandle,
const AZ::Vector3& gravityDirection,
float maxDistance,
const AzPhysics::CollisionLayer& collisionLayer)
{
AZStd::optional<AZ::Vector3> hitPosition = AZStd::nullopt;

AZ_Assert(sceneHandle == AzPhysics::InvalidSceneHandle, "Unable to get scene handle");
if (sceneHandle == AzPhysics::InvalidSceneHandle)
michalpelka marked this conversation as resolved.
Show resolved Hide resolved
{
return hitPosition;
}

auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get();
auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
AZ_Assert(physicsSystem, "Unable to get physics system interface");
AZ_Assert(sceneInterface, "Unable to get physics scene interface");

if (!sceneInterface || !physicsSystem)
{
return hitPosition;
}

AzPhysics::RayCastRequest request;
request.m_start = location;
request.m_direction = gravityDirection;
request.m_distance = maxDistance;
request.m_collisionGroup.SetLayer(collisionLayer, true);

AzPhysics::SceneQueryHits result = sceneInterface->QueryScene(sceneHandle, &request);

if (!result.m_hits.empty())
{
hitPosition = result.m_hits.front().m_position;
}

return hitPosition;
}

AZStd::unordered_map<int, AzFramework::EntitySpawnTicket> SpawnEntities(
const AZStd::vector<CsvSpawnableEntityInfo>& entitiesToSpawn,
const AZStd::unordered_map<AZStd::string, CsvSpawnableAssetConfiguration>& spawnableAssetConfiguration,
Expand Down Expand Up @@ -211,21 +271,23 @@ namespace CsvSpawner::CsvSpawnerUtils

if (spawnConfig.m_placeOnTerrain)
{
const AZStd::optional<AZ::Vector3> hitPosition =
RaytraceTerrain(transform.GetTranslation(), sceneHandle, -AZ::Vector3::CreateAxisZ(), 1000.0f);
const AZStd::optional<AZ::Vector3> hitPosition = RaytraceTerrain(
transform.GetTranslation(), sceneHandle, -AZ::Vector3::CreateAxisZ(), 1000.0f, spawnConfig.m_selectedCollisionLayer);
if (hitPosition.has_value())
{
transform.SetTranslation(hitPosition.value());
}
else
{
continue; // Skip this entity if we can't find a valid position and place on terrain is enabled.
continue; // Skip this entity if we can't find a valid position and
// place on terrain is enabled.
}
}
AZ_Assert(spawner, "Unable to get spawnable entities definition");
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
AzFramework::EntitySpawnTicket ticket(spawnable);
// Set the pre-spawn callback to set the name of the root entity to the name of the spawnable
// Set the pre-spawn callback to set the name of the root entity to the name
// of the spawnable
optionalArgs.m_preInsertionCallback = [transform](auto id, auto view)
{
if (view.empty())
Expand Down
47 changes: 31 additions & 16 deletions Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
*
* This source code is protected under international copyright law. All rights
* reserved and protected by the copyright holders.
* This file is confidential and only available to authorized individuals with the
* permission of the copyright holders. If you encounter this file and do not have
* permission, please contact the copyright holders and delete this file.
* This file is confidential and only available to authorized individuals with
* the permission of the copyright holders. If you encounter this file and do
* not have permission, please contact the copyright holders and delete this
* file.
*/

#pragma once

#include "AzFramework/Physics/Collision/CollisionLayers.h"
#include "CsvSpawner/CsvSpawnerTypeIds.h"

#include <AzCore/Asset/AssetCommon.h>
Expand All @@ -24,8 +26,8 @@ namespace CsvSpawner::CsvSpawnerUtils

//! Information about a locations to spawn an entity.
//! This information is generated from CSV file and is used to spawn the entity.
//! @param m_name is the name of the spawnable entity configuration and should be identical to name in @class
//! SpawnableAssetConfiguration.
//! @param m_name is the name of the spawnable entity configuration and should
//! be identical to name in @class SpawnableAssetConfiguration.
class CsvSpawnableEntityInfo
{
public:
Expand All @@ -37,15 +39,18 @@ namespace CsvSpawner::CsvSpawnerUtils
unsigned int m_id; //!< Optional ID for the entity
AZ::Transform m_transform; //!< Transform of the entity, mandatory
AZStd::string m_name; //!< Name of the spawnable entity configuration, mandatory
uint64_t m_seed{ 0 }; //!< Optional seed value for randomization, in the context of one spawnable entity configuration, optional
uint64_t m_seed{ 0 }; //!< Optional seed value for randomization, in the context
//!< of one spawnable entity configuration, optional
};

//! Configuration for a spawnable asset
//! This configuration is used to configure the spawnable asset before spawning it.
//! The @param m_name is used to identify the spawnable asset configuration and should be identical to name given in CSV file.
//! The class allows user to specify multiple spawnable assets for a given name and randomization parameters for position, rotation and
//! scale. If more then one spawnable asset is specified for a given name, then one of the spawnable assets is randomly selected for
//! spawning.
//! This configuration is used to configure the spawnable asset before spawning
//! it. The @param m_name is used to identify the spawnable asset configuration
//! and should be identical to name given in CSV file. The class allows user to
//! specify multiple spawnable assets for a given name and randomization
//! parameters for position, rotation and scale. If more then one spawnable
//! asset is specified for a given name, then one of the spawnable assets is
//! randomly selected for spawning.
class CsvSpawnableAssetConfiguration
{
public:
Expand All @@ -59,12 +64,21 @@ namespace CsvSpawner::CsvSpawnerUtils
AZ::Vector3 m_positionStdDev{ 0.f }; //!< Standard deviation for position
AZ::Vector3 m_rotationStdDev{ 0.f }; //!< Standard deviation for rotation
float m_scaleStdDev{ 0.1f }; //!< Standard deviation for scale
bool m_placeOnTerrain{ false }; //!< Whether to raytrace to terrain and place the entity on the terrain
bool m_placeOnTerrain{ false }; //!< Whether to raytrace to terrain and place
//!< the entity on the terrain
AzPhysics::CollisionLayer m_selectedCollisionLayer; //!< To which collision layer this target will
//!< be attached

private:
[[nodiscard]] bool IsCollisionLayerEnabled() const;
static AZ::Crc32 OnPlaceOnTerrainChanged();
};

//! This function create map of spawnable asset configuration from vector of spawnable asset configuration, where
//! the key is the name of the spawnable asset configuration
//! @param spawnableAssetConfigurations - vector of spawnable asset configuration
//! This function create map of spawnable asset configuration from vector of
//! spawnable asset configuration, where the key is the name of the spawnable
//! asset configuration
//! @param spawnableAssetConfigurations - vector of spawnable asset
//! configuration
//! @return map of spawnable asset configuration
AZStd::unordered_map<AZStd::string, CsvSpawnableAssetConfiguration> GetSpawnableAssetFromVector(
AZStd::vector<CsvSpawnableAssetConfiguration> spawnableAssetConfigurations);
Expand All @@ -74,7 +88,8 @@ namespace CsvSpawner::CsvSpawnerUtils
//! @param spawnableAssetConfiguration - map of spawnable asset configuration
//! @param defaultSeed - default seed value
//! @param parentId - parent entity id to set for new entities
//! @param physicsSceneName - physics scene name (AzPhysics::DefaultPhysicsSceneName or AzPhysics::EditorPhysicsSceneName)
//! @param physicsSceneName - physics scene name
//! (AzPhysics::DefaultPhysicsSceneName or AzPhysics::EditorPhysicsSceneName)
//! @return map of spawn created tickets
AZStd::unordered_map<int, AzFramework::EntitySpawnTicket> SpawnEntities(
const AZStd::vector<CsvSpawnableEntityInfo>& entitiesToSpawn,
Expand Down