/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Blast { BlastActorImpl::BlastActorImpl(const BlastActorDesc& desc) : m_family(*desc.m_family) , m_tkActor(*desc.m_tkActor) , m_entity(desc.m_entity) , m_chunkIndices(desc.m_chunkIndices) , m_isLeafChunk(desc.m_isLeafChunk) , m_isStatic(desc.m_isStatic) , m_physicsMaterialId(desc.m_physicsMaterialId) , m_parentLinearVelocity(desc.m_parentLinearVelocity) , m_parentCenterOfMass(desc.m_parentCenterOfMass) , m_bodyConfiguration(desc.m_bodyConfiguration) , m_scale(desc.m_scale) { // Store pointer to ourselves in the blast toolkit actor's userData m_tkActor.userData = this; m_shapesProvider = AZStd::make_unique(m_entity->GetId(), desc.m_bodyConfiguration); } BlastActorImpl::~BlastActorImpl() { m_tkActor.userData = nullptr; } void BlastActorImpl::Spawn() { // Add shapes for each of the visible chunks AddShapes(m_chunkIndices, m_family.GetPxAsset(), m_physicsMaterialId); m_entity->Init(); m_entity->Activate(); auto transform = AZ::Transform::CreateFromQuaternionAndTranslation( m_bodyConfiguration.m_orientation, m_bodyConfiguration.m_position); transform.MultiplyByUniformScale(m_scale); AZ::TransformBus::Event(m_entity->GetId(), &AZ::TransformInterface::SetWorldTM, transform); // Set initial velocities if we're not static if (!m_isStatic) { AzPhysics::RigidBody* rigidBody = nullptr; Physics::RigidBodyRequestBus::EventResult( rigidBody, m_entity->GetId(), &Physics::RigidBodyRequests::GetRigidBody); rigidBody->SetTransform(transform); const AZ::Vector3 com = rigidBody->GetTransform().TransformPoint(rigidBody->GetCenterOfMassLocal()); const AZ::Vector3 linearVelocity = m_parentLinearVelocity + m_bodyConfiguration.m_initialAngularVelocity.Cross(com - m_parentCenterOfMass); Physics::RigidBodyRequestBus::Event( m_entity->GetId(), &Physics::RigidBodyRequests::SetLinearVelocity, linearVelocity); Physics::RigidBodyRequestBus::Event( m_entity->GetId(), &Physics::RigidBodyRequests::SetAngularVelocity, m_bodyConfiguration.m_initialAngularVelocity); } } void BlastActorImpl::AddShapes( const AZStd::vector& chunkIndices, const Nv::Blast::ExtPxAsset& asset, const Physics::MaterialId& material) { const Nv::Blast::ExtPxChunk* pxChunks = asset.getChunks(); const Nv::Blast::ExtPxSubchunk* pxSubchunks = asset.getSubchunks(); const uint32_t chunkCount = asset.getChunkCount(); const uint32_t subchunkCount = asset.getSubchunkCount(); AZ_Assert(pxChunks, "Received asset with a null chunk array."); AZ_Assert(pxSubchunks, "Received asset with a null subchunk array."); if (!pxChunks || !pxSubchunks) { return; } for (uint32_t chunkId : chunkIndices) { AZ_Assert(chunkId < chunkCount, "Out of bounds access to the BlastPxActor's PxChunks."); if (chunkId >= chunkCount) { continue; } const Nv::Blast::ExtPxChunk& chunk = pxChunks[chunkId]; for (uint32_t i = 0; i < chunk.subchunkCount; i++) { const uint32_t subchunkIndex = chunk.firstSubchunkIndex + i; AZ_Assert(subchunkIndex < subchunkCount, "Out of bounds access to the BlastPxActor's PxSubchunks."); if (subchunkIndex >= subchunkCount) { continue; } auto& subchunk = pxSubchunks[subchunkIndex]; AZ::Transform transform = PxMathConvert(subchunk.transform); auto colliderConfiguration = CalculateColliderConfiguration(transform, material); Physics::NativeShapeConfiguration shapeConfiguration; shapeConfiguration.m_nativeShapePtr = reinterpret_cast(const_cast(&subchunk.geometry)->convexMesh); shapeConfiguration.m_nativeShapeScale = AZ::Vector3(m_scale); AZStd::shared_ptr shape = AZ::Interface::Get()->CreateShape( colliderConfiguration, shapeConfiguration); AZ_Assert(shape, "Failed to create Shape for BlastActor"); m_shapesProvider->AddShape(shape); } } } Physics::ColliderConfiguration BlastActorImpl::CalculateColliderConfiguration( const AZ::Transform& transform, Physics::MaterialId material) { auto& actorConfiguration = m_family.GetActorConfiguration(); Physics::ColliderConfiguration colliderConfiguration; colliderConfiguration.m_position = transform.GetTranslation(); colliderConfiguration.m_rotation = transform.GetRotation(); colliderConfiguration.m_isExclusive = true; colliderConfiguration.m_materialSelection.SetMaterialId(material); colliderConfiguration.m_collisionGroupId = actorConfiguration.m_collisionGroupId; colliderConfiguration.m_collisionLayer = actorConfiguration.m_collisionLayer; colliderConfiguration.m_isInSceneQueries = actorConfiguration.m_isInSceneQueries; colliderConfiguration.m_isSimulated = actorConfiguration.m_isSimulated; colliderConfiguration.m_tag = actorConfiguration.m_tag; return colliderConfiguration; } AZ::Transform BlastActorImpl::GetTransform() const { return GetSimulatedBody()->GetTransform(); } const BlastFamily& BlastActorImpl::GetFamily() const { return m_family; } Nv::Blast::TkActor& BlastActorImpl::GetTkActor() const { return m_tkActor; } AzPhysics::SimulatedBody* BlastActorImpl::GetSimulatedBody() { AzPhysics::SimulatedBody* worldBody = nullptr; AzPhysics::SimulatedBodyComponentRequestsBus::EventResult( worldBody, m_entity->GetId(), &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody); return worldBody; } const AzPhysics::SimulatedBody* BlastActorImpl::GetSimulatedBody() const { AzPhysics::SimulatedBody* worldBody = nullptr; AzPhysics::SimulatedBodyComponentRequestsBus::EventResult( worldBody, m_entity->GetId(), &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody); return worldBody; } const AZStd::vector& BlastActorImpl::GetChunkIndices() const { return m_chunkIndices; } bool BlastActorImpl::IsStatic() const { return m_isStatic; } const AZ::Entity* BlastActorImpl::GetEntity() const { return m_entity.get(); } void BlastActorImpl::Damage(const NvBlastDamageProgram& program, NvBlastExtProgramParams* programParams) { m_tkActor.damage(program, programParams); } } // namespace Blast