void UDestructibleComponent::SetChunkVisible( int32 ChunkIndex, bool bVisible ) { #if WITH_APEX // Bone 0 is a dummy root bone const int32 BoneIndex = ChunkIdxToBoneIdx(ChunkIndex); if( bVisible ) { UnHideBone(BoneIndex); if (NULL != ApexDestructibleActor) { physx::PxShape** PShapes; const physx::PxU32 PShapeCount = ApexDestructibleActor->getChunkPhysXShapes(PShapes, ChunkIndex); if (PShapeCount > 0) { const physx::PxMat44 ChunkPoseRT = ApexDestructibleActor->getChunkPose(ChunkIndex); // Unscaled const physx::PxTransform Transform(ChunkPoseRT); SetChunkWorldRT(ChunkIndex, P2UQuat(Transform.q), P2UVector(Transform.p)); } } } else { HideBone(BoneIndex, PBO_None); } // Mark the transform as dirty, so the bounds are updated and sent to the render thread MarkRenderTransformDirty(); // New bone positions need to be sent to render thread MarkRenderDynamicDataDirty(); #endif }
void UDestructibleComponent::SetChunksWorldTM(const TArray<FUpdateChunksInfo>& UpdateInfos) { const FQuat InvRotation = ComponentToWorld.GetRotation().Inverse(); for (const FUpdateChunksInfo& UpdateInfo : UpdateInfos) { // Bone 0 is a dummy root bone const int32 BoneIndex = ChunkIdxToBoneIdx(UpdateInfo.ChunkIndex); const FVector WorldTranslation = UpdateInfo.WorldTM.GetLocation(); const FQuat WorldRotation = UpdateInfo.WorldTM.GetRotation(); const FQuat BoneRotation = InvRotation*WorldRotation; const FVector BoneTranslation = InvRotation.RotateVector(WorldTranslation - ComponentToWorld.GetTranslation()) / ComponentToWorld.GetScale3D(); GetEditableSpaceBases()[BoneIndex] = FTransform(BoneRotation, BoneTranslation); } // Mark the transform as dirty, so the bounds are updated and sent to the render thread MarkRenderTransformDirty(); // New bone positions need to be sent to render thread MarkRenderDynamicDataDirty(); //Update bone visibilty and flip the editable space base buffer FlipEditableSpaceBases(); }
void UDestructibleComponent::SetCollisionResponseForActor(PxRigidDynamic* Actor, int32 ChunkIdx, const FCollisionResponseContainer* ResponseOverride /*= NULL*/) { #if WITH_APEX if (ApexDestructibleActor == NULL) { return; } // Get collision channel and response PxFilterData PQueryFilterData, PSimFilterData; uint8 MoveChannel = GetCollisionObjectType(); if(IsCollisionEnabled()) { UDestructibleMesh* TheDestructibleMesh = GetDestructibleMesh(); AActor* Owner = GetOwner(); bool bLargeChunk = IsChunkLarge(ChunkIdx); const FCollisionResponseContainer& UseResponse = ResponseOverride == NULL ? (bLargeChunk ? LargeChunkCollisionResponse.GetResponseContainer() : SmallChunkCollisionResponse.GetResponseContainer()) : *ResponseOverride; physx::PxU32 SupportDepth = TheDestructibleMesh->ApexDestructibleAsset->getChunkDepth(ChunkIdx); const bool bEnableImpactDamage = IsImpactDamageEnabled(TheDestructibleMesh, SupportDepth); CreateShapeFilterData(MoveChannel, GetUniqueID(), UseResponse, 0, ChunkIdxToBoneIdx(ChunkIdx), PQueryFilterData, PSimFilterData, BodyInstance.bUseCCD, bEnableImpactDamage, false); PQueryFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision; SCOPED_SCENE_WRITE_LOCK(Actor->getScene()); TArray<PxShape*> Shapes; Shapes.AddUninitialized(Actor->getNbShapes()); int ShapeCount = Actor->getShapes(Shapes.GetData(), Shapes.Num()); for (int32 i=0; i < ShapeCount; ++i) { PxShape* Shape = Shapes[i]; Shape->setQueryFilterData(PQueryFilterData); Shape->setSimulationFilterData(PSimFilterData); Shape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, true); Shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); Shape->setFlag(PxShapeFlag::eVISUALIZATION, true); } } #endif }
void UDestructibleComponent::SetChunkWorldRT( int32 ChunkIndex, const FQuat& WorldRotation, const FVector& WorldTranslation ) { // Bone 0 is a dummy root bone const int32 BoneIndex = ChunkIdxToBoneIdx(ChunkIndex); // Mark the transform as dirty, so the bounds are updated and sent to the render thread MarkRenderTransformDirty(); #if 0 // Scale is already applied to the ComponentToWorld transform, and is carried into the bones _locally_. // So there is no need to set scale in the bone local transforms const FTransform WorldRT(WorldRotation, WorldTranslation, ComponentToWorld.GetScale3D()); SpaceBases(BoneIndex) = WorldRT*ComponentToWorld.Inverse(); #elif 1 // More optimal form of the above const FQuat BoneRotation = ComponentToWorld.GetRotation().Inverse()*WorldRotation; const FVector BoneTranslation = ComponentToWorld.GetRotation().Inverse().RotateVector(WorldTranslation - ComponentToWorld.GetTranslation())/ComponentToWorld.GetScale3D(); SpaceBases[BoneIndex] = FTransform(BoneRotation, BoneTranslation); #endif }
void UDestructibleComponent::SetCollisionResponseForShape(PxShape* Shape, int32 ChunkIdx) { // Get collision channel and response PxFilterData PQueryFilterData, PSimFilterData; uint8 MoveChannel = GetCollisionObjectType(); if (IsCollisionEnabled()) { AActor* Owner = GetOwner(); bool bLargeChunk = IsChunkLarge(ChunkIdx); const FCollisionResponse& ColResponse = bLargeChunk ? LargeChunkCollisionResponse : SmallChunkCollisionResponse; //TODO: we currently assume chunks will not have impact damage as it's very expensive. Should look into exposing this a bit more CreateShapeFilterData(MoveChannel, (Owner ? Owner->GetUniqueID() : 0), ColResponse.GetResponseContainer(), 0, ChunkIdxToBoneIdx(ChunkIdx), PQueryFilterData, PSimFilterData, BodyInstance.bUseCCD, false, false); PQueryFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision; SCOPED_SCENE_WRITE_LOCK(Shape->getActor()->getScene()); Shape->setQueryFilterData(PQueryFilterData); Shape->setSimulationFilterData(PSimFilterData); Shape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, true); Shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); Shape->setFlag(PxShapeFlag::eVISUALIZATION, true); } }
void UDestructibleComponent::SetChunkVisible( int32 ChunkIndex, bool bVisible ) { // Bone 0 is a dummy root bone const int32 BoneIndex = ChunkIdxToBoneIdx(ChunkIndex); bool bClearActorFromChunkInfo = false; if( bVisible ) { UnHideBone(BoneIndex); #if WITH_APEX PxRigidDynamic* PActor = ApexDestructibleActor != NULL ? ApexDestructibleActor->getChunkPhysXActor(ChunkIndex) : NULL; UDestructibleMesh* DMesh = GetDestructibleMesh(); if (PActor != NULL) { // If actor has already a chunk info and userdata, we just make sure it is valid and update the // physx actor if needed. We do NOT do this for FormExtended structures, as in this case, the shapes/actors // are moved to the 1st structure object internally by APEX. if(PActor->userData != NULL && !DMesh->DefaultDestructibleParameters.Flags.bFormExtendedStructures) { FDestructibleChunkInfo* CI = FPhysxUserData::Get<FDestructibleChunkInfo>(PActor->userData); checkf(CI, TEXT("If a chunk actor has user data and it is not a DestructibleChunkInfo, something is messed up.")); //check(CI->OwningComponent == this); if (CI->ChunkIndex != ChunkIndex) { // grab the old actor and clear its user data, as we steal the ChunkInfo here if (CI->Actor && CI->Actor != PActor) { CI->Actor->userData = NULL; } CI->ChunkIndex = ChunkIndex; } CI->OwningComponent = this; CI->Actor = PActor; } else if (PActor->userData == NULL) { // Setup the user data to have a proper chunk - actor mapping int32 InfoIndex = ChunkInfos.AddUninitialized(); FDestructibleChunkInfo* CI = &ChunkInfos[InfoIndex]; CI->Index = InfoIndex; CI->ChunkIndex = ChunkIndex; CI->OwningComponent = this; CI->Actor = PActor; int32 UserDataIdx = PhysxChunkUserData.Add(FPhysxUserData(CI)); check(InfoIndex == UserDataIdx); PActor->userData = &PhysxChunkUserData[UserDataIdx]; // Set collision response to non-root chunks if (GetDestructibleMesh()->ApexDestructibleAsset->getChunkParentIndex(ChunkIndex) >= 0) { SetCollisionResponseForActor(ChunkCollisionResponse, PActor, ChunkIndex); } } } else { bClearActorFromChunkInfo = true; } #endif // WITH_APEX } else { HideBone(BoneIndex, PBO_None); bClearActorFromChunkInfo = true; } #if WITH_APEX if (bClearActorFromChunkInfo) { // Make sure we clear the physx actor pointer of the chunk info as it might (and probably will) be // invalid from now on for (int32 i=0; i < ChunkInfos.Num(); ++i) { if (ChunkInfos[i].ChunkIndex == ChunkIndex) { ChunkInfos[i].Actor = NULL; break; } } } #endif // WITH_APEX // Mark the transform as dirty, so the bounds are updated and sent to the render thread MarkRenderTransformDirty(); // New bone positions need to be sent to render thread MarkRenderDynamicDataDirty(); }
void UDestructibleComponent::SetCollisionResponseForActor(const FCollisionResponse& ColResponse, PxRigidDynamic* Actor, int32 ChunkIdx) { // Get collision channel and response PxFilterData PQueryFilterData, PSimFilterData; uint8 MoveChannel = GetCollisionObjectType(); if(IsCollisionEnabled()) { AActor* Owner = GetOwner(); CreateShapeFilterData(MoveChannel, (Owner ? Owner->GetUniqueID() : 0), ColResponse.GetResponseContainer(), 0, ChunkIdxToBoneIdx(ChunkIdx), PQueryFilterData, PSimFilterData, BodyInstance.bUseCCD, BodyInstance.bNotifyRigidBodyCollision, false); PQueryFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision; SCOPED_SCENE_WRITE_LOCK(Actor->getScene()); TArray<PxShape*> Shapes; Shapes.AddUninitialized(Actor->getNbShapes()); int ShapeCount = Actor->getShapes(Shapes.GetTypedData(), Shapes.Num()); for (int32 i=0; i < ShapeCount; ++i) { PxShape* Shape = Shapes[i]; Shape->setQueryFilterData(PQueryFilterData); Shape->setSimulationFilterData(PSimFilterData); Shape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, true); Shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); Shape->setFlag(PxShapeFlag::eVISUALIZATION, true); } } }