A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
VREPhysicalAnimationComponent.cpp
Go to the documentation of this file.
2#include "SceneManagement.h"
3#include "Components/SkeletalMeshComponent.h"
4#include "PhysicsEngine/PhysicsAsset.h"
5#if PHYSICS_INTERFACE_PHYSX
6#include "PhysXPublic.h"
7#endif
8#include "ReferenceSkeleton.h"
9#include "DrawDebugHelpers.h"
10#include "Physics/PhysicsInterfaceCore.h"
11#include "Physics/PhysicsInterfaceTypes.h"
12
13UVREPhysicalAnimationComponent::UVREPhysicalAnimationComponent(const FObjectInitializer& ObjectInitializer)
14 : Super(ObjectInitializer)
15{
18}
19
20/*void UVREPhysicalAnimationComponent::CustomPhysics(float DeltaTime, FBodyInstance* BodyInstance)
21{
22 //UpdateWeldedBoneDriver(DeltaTime);
23}*/
24
25/*void UVREPhysicalAnimationComponent::OnWeldedMassUpdated(FBodyInstance* BodyInstance)
26{
27 // If our mass changed then our body was altered, lets re-init
28 SetupWeldedBoneDriver(true);
29}*/
30
35
40
45
47{
48 if (BaseBoneNames.Num())
49 BaseWeldedBoneDriverNames = BaseBoneNames;
50
52}
53
54FTransform UVREPhysicalAnimationComponent::GetWorldSpaceRefBoneTransform(FReferenceSkeleton& RefSkel, int32 BoneIndex, int32 ParentBoneIndex)
55{
56 FTransform BoneTransform;
57
58 if (BoneIndex > 0 && BoneIndex != ParentBoneIndex)
59 {
60 BoneTransform = RefSkel.GetRefBonePose()[BoneIndex];
61
62 FMeshBoneInfo BoneInfo = RefSkel.GetRefBoneInfo()[BoneIndex];
63 if (BoneInfo.ParentIndex != 0 && BoneInfo.ParentIndex != ParentBoneIndex)
64 {
65 BoneTransform *= GetWorldSpaceRefBoneTransform(RefSkel, BoneInfo.ParentIndex, ParentBoneIndex);
66 }
67 }
68
69 return BoneTransform;
70}
71
72// #TODO: support off scaling
73FTransform UVREPhysicalAnimationComponent::GetRefPoseBoneRelativeTransform(USkeletalMeshComponent* SkeleMesh, FName BoneName, FName ParentBoneName)
74{
75 FTransform BoneTransform;
76
77 if (SkeleMesh && !BoneName.IsNone() && !ParentBoneName.IsNone())
78 {
79 //SkelMesh->ClearRefPoseOverride();
80 FReferenceSkeleton RefSkel;
81 RefSkel = SkeleMesh->SkeletalMesh->GetRefSkeleton();
82
83 BoneTransform = GetWorldSpaceRefBoneTransform(RefSkel, RefSkel.FindBoneIndex(BoneName), RefSkel.FindBoneIndex(ParentBoneName));
84 }
85
86 return BoneTransform;
87}
88
90{
91 TArray<FWeldedBoneDriverData> OriginalData;
92 if (bReInit)
93 {
94 OriginalData = BoneDriverMap;
95 }
96
97 BoneDriverMap.Empty();
98
99 USkeletalMeshComponent* SkeleMesh = GetSkeletalMesh();
100
101 if (!SkeleMesh || !SkeleMesh->Bodies.Num())
102 return;
103
104 // Get ref pose position and walk up the tree to the welded root to get our relative base pose.
105 //SkeleMesh->GetRefPosePosition()
106
107 UPhysicsAsset* PhysAsset = SkeleMesh ? SkeleMesh->GetPhysicsAsset() : nullptr;
108 if (PhysAsset && SkeleMesh->SkeletalMesh)
109 {
110
111//#if PHYSICS_INTERFACE_PHYSX
112 for (FName BaseWeldedBoneDriverName : BaseWeldedBoneDriverNames)
113 {
114 int32 ParentBodyIdx = PhysAsset->FindBodyIndex(BaseWeldedBoneDriverName);
115
116 if (FBodyInstance* ParentBody = (ParentBodyIdx == INDEX_NONE ? nullptr : SkeleMesh->Bodies[ParentBodyIdx]))
117 {
118 // Build map of bodies that we want to control.
119 FPhysicsActorHandle& ActorHandle = ParentBody->WeldParent ? ParentBody->WeldParent->GetPhysicsActorHandle() : ParentBody->GetPhysicsActorHandle();
120
121 if (FPhysicsInterface::IsValid(ActorHandle) /*&& FPhysicsInterface::IsRigidBody(ActorHandle)*/)
122 {
123 FPhysicsCommand::ExecuteWrite(ActorHandle, [&](FPhysicsActorHandle& Actor)
124 {
125 //TArray<FPhysicsShapeHandle> Shapes;
126 PhysicsInterfaceTypes::FInlineShapeArray Shapes;
127 FPhysicsInterface::GetAllShapes_AssumedLocked(Actor, Shapes);
128
129 for (FPhysicsShapeHandle& Shape : Shapes)
130 {
131 if (ParentBody->WeldParent)
132 {
133 const FBodyInstance* OriginalBI = ParentBody->WeldParent->GetOriginalBodyInstance(Shape);
134
135 if (OriginalBI != ParentBody)
136 {
137 // Not originally our shape
138 continue;
139 }
140 }
141#if WITH_CHAOS
142 FKShapeElem* ShapeElem = FChaosUserData::Get<FKShapeElem>(FPhysicsInterface::GetUserData(Shape));
143#elif PHYSICS_INTERFACE_PHYSX
144 FKShapeElem* ShapeElem = FPhysxUserData::Get<FKShapeElem>(FPhysicsInterface::GetUserData(Shape));
145#endif
146 if (ShapeElem)
147 {
148 FName TargetBoneName = ShapeElem->GetName();
149 int32 BoneIdx = SkeleMesh->GetBoneIndex(TargetBoneName);
150
151 if (BoneIdx != INDEX_NONE)
152 {
153 FWeldedBoneDriverData DriverData;
154 DriverData.BoneName = TargetBoneName;
155 DriverData.ShapeHandle = Shape;
156
157 if (bReInit && OriginalData.Num() - 1 >= BoneDriverMap.Num())
158 {
159 DriverData.RelativeTransform = OriginalData[BoneDriverMap.Num()].RelativeTransform;
160 }
161 else
162 {
163 FTransform BoneTransform = FTransform::Identity;
164 if (SkeleMesh->GetBoneIndex(TargetBoneName) != INDEX_NONE)
165 BoneTransform = GetRefPoseBoneRelativeTransform(SkeleMesh, TargetBoneName, BaseWeldedBoneDriverName).Inverse();
166
167 //FTransform BoneTransform = SkeleMesh->GetSocketTransform(TargetBoneName, ERelativeTransformSpace::RTS_World);
168
169 // Calc shape global pose
170 //FTransform RelativeTM = FPhysicsInterface::GetLocalTransform(Shape) * FPhysicsInterface::GetGlobalPose_AssumesLocked(ActorHandle);
171
172 //RelativeTM = RelativeTM * BoneTransform.Inverse();
173
174 DriverData.RelativeTransform = FPhysicsInterface::GetLocalTransform(Shape) * BoneTransform;
175 }
176
177 BoneDriverMap.Add(DriverData);
178 }
179 }
180 }
181
182 if (bAutoSetPhysicsSleepSensitivity && !ParentBody->WeldParent && BoneDriverMap.Num() > 0)
183 {
184 ParentBody->SleepFamily = ESleepFamily::Custom;
185 ParentBody->CustomSleepThresholdMultiplier = SleepThresholdMultiplier;
186 float SleepEnergyThresh = FPhysicsInterface::GetSleepEnergyThreshold_AssumesLocked(Actor);
187 SleepEnergyThresh *= ParentBody->GetSleepThresholdMultiplier();
188 FPhysicsInterface::SetSleepEnergyThreshold_AssumesLocked(Actor, SleepEnergyThresh);
189 }
190 });
191 }
192 }
193 }
194//#endif
195 }
196}
197
198void UVREPhysicalAnimationComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
199{
200 // Make sure base physical animation component runs its logic
201 Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
202 UpdateWeldedBoneDriver(DeltaTime);
203}
204
206{
207
208 if (!BoneDriverMap.Num())
209 return;
210
211 /*
212 #if WITH_CHAOS || WITH_IMMEDIATE_PHYSX
213 //ensure(false);
214#else
215#endif
216 */
217 USkeletalMeshComponent* SkeleMesh = GetSkeletalMesh();
218
219 if (!SkeleMesh || !SkeleMesh->Bodies.Num())// || (!SkeleMesh->IsSimulatingPhysics(BaseWeldedBoneDriverNames) && !SkeleMesh->IsWelded()))
220 return;
221
222 UPhysicsAsset* PhysAsset = SkeleMesh ? SkeleMesh->GetPhysicsAsset() : nullptr;
223 if(PhysAsset && SkeleMesh->SkeletalMesh)
224 {
225 for (FName BaseWeldedBoneDriverName : BaseWeldedBoneDriverNames)
226 {
227 int32 ParentBodyIdx = PhysAsset->FindBodyIndex(BaseWeldedBoneDriverName);
228
229 if (FBodyInstance* ParentBody = (ParentBodyIdx == INDEX_NONE ? nullptr : SkeleMesh->Bodies[ParentBodyIdx]))
230 {
231 // Allow it to run even when not simulating physics, if we have a welded root then it needs to animate anyway
232 //if (!ParentBody->IsInstanceSimulatingPhysics() && !ParentBody->WeldParent)
233 // return;
234
235 FPhysicsActorHandle& ActorHandle = ParentBody->WeldParent ? ParentBody->WeldParent->GetPhysicsActorHandle() : ParentBody->GetPhysicsActorHandle();
236
237 if (FPhysicsInterface::IsValid(ActorHandle) /*&& FPhysicsInterface::IsRigidBody(ActorHandle)*/)
238 {
239
240 bool bModifiedBody = false;
241 FPhysicsCommand::ExecuteWrite(ActorHandle, [&](FPhysicsActorHandle& Actor)
242 {
243 PhysicsInterfaceTypes::FInlineShapeArray Shapes;
244 FPhysicsInterface::GetAllShapes_AssumedLocked(Actor, Shapes);
245
246 FTransform GlobalPose = FPhysicsInterface::GetGlobalPose_AssumesLocked(ActorHandle).Inverse();
247
248 for (FPhysicsShapeHandle& Shape : Shapes)
249 {
250
251 if (ParentBody->WeldParent)
252 {
253 const FBodyInstance* OriginalBI = ParentBody->WeldParent->GetOriginalBodyInstance(Shape);
254
255 if (OriginalBI != ParentBody)
256 {
257 // Not originally our shape
258 continue;
259 }
260 }
261
262 if (FWeldedBoneDriverData* WeldedData = BoneDriverMap.FindByKey(Shape))
263 {
264 bModifiedBody = true;
265
266 FTransform Trans = SkeleMesh->GetSocketTransform(WeldedData->BoneName, ERelativeTransformSpace::RTS_World);
267
268 // This fixes a bug with simulating inverse scaled meshes
269 //Trans.SetScale3D(FVector(1.f) * Trans.GetScale3D().GetSignVector());
270 FTransform GlobalTransform = WeldedData->RelativeTransform * Trans;
271 FTransform RelativeTM = GlobalTransform * GlobalPose;
272
273 if (!WeldedData->LastLocal.Equals(RelativeTM))
274 {
275 FPhysicsInterface::SetLocalTransform(Shape, RelativeTM);
276 WeldedData->LastLocal = RelativeTM;
277 }
278 }
279 }
280 });
281 }
282
283 }
284 }
285 }
286}
void RefreshWeldedBoneDriver()
UFUNCTION(BlueprintCallable, Category = PhysicalAnimation)
bool bIsPaused
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = WeldedBoneDriver)
FTransform GetWorldSpaceRefBoneTransform(FReferenceSkeleton &RefSkel, int32 BoneIndex, int32 ParentBoneIndex)
void SetupWeldedBoneDriver_Implementation(bool bReInit=false)
void SetupWeldedBoneDriver(TArray< FName > BaseBoneNames)
UFUNCTION(BlueprintCallable, Category = PhysicalAnimation)
TArray< FName > BaseWeldedBoneDriverNames
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = WeldedBoneDriver)
TArray< FWeldedBoneDriverData > BoneDriverMap
UPROPERTY()
FTransform GetRefPoseBoneRelativeTransform(USkeletalMeshComponent *SkeleMesh, FName BoneName, FName ParentBoneName)
void SetWeldedBoneDriverPaused(bool bPaused)
UFUNCTION(BlueprintCallable, Category = PhysicalAnimation)
float SleepThresholdMultiplier
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = WeldedBoneDriver)
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override
bool bAutoSetPhysicsSleepSensitivity
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = WeldedBoneDriver)
bool IsWeldedBoneDriverPaused()
UFUNCTION(BlueprintPure, Category = PhysicalAnimation)