UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SQVerifier.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "PhysicsCore.h"
7
10#include "PhysTestSerializer.h"
11#include "SQAccelerator.h"
12
13#ifndef SQ_REPLAY_TEST
14#define SQ_REPLAY_TEST(cond) bEnsureOnMismatch ? ensure(cond) : (cond)
15#endif
16
17template <bool bHasPhysX = false>
18void SQPerfComparisonHelper(const FString& TestName, FPhysTestSerializer& Serializer, bool bEnsureOnMismatch = false)
19{
20 using namespace Chaos;
21 uint32 PhysXSum = 0;
22 uint32 ChaosSum = 0;
23 double NumIterations = bHasPhysX ? 100 : 10000;
25 //double NumIterations = 1000000;
26
27 const FSQCapture& CapturedSQ = *Serializer.GetSQCapture();
28 switch (CapturedSQ.SQType)
29 {
31 {
35 for (double i = 0; i < NumIterations; ++i)
36 {
38 uint32 StartTime = FPlatformTime::Cycles();
39 SQAccelerator.Raycast(CapturedSQ.StartPoint, CapturedSQ.Dir, CapturedSQ.DeltaMag, *ChaosHitBuffer, CapturedSQ.OutputFlags.HitFlags, CapturedSQ.QueryFilterData, *CapturedSQ.FilterCallback);
40 ChaosSum += FPlatformTime::Cycles() - StartTime;
41 }
42 break;
43 }
45 {
49 for (double i = 0; i < NumIterations; ++i)
50 {
52 uint32 StartTime = FPlatformTime::Cycles();
53 SQAccelerator.Sweep(*CapturedSQ.ChaosImplicitGeometry, CapturedSQ.StartTM, CapturedSQ.Dir, CapturedSQ.DeltaMag, *ChaosHitBuffer, CapturedSQ.OutputFlags.HitFlags, CapturedSQ.QueryFilterData, *CapturedSQ.FilterCallback);
54 ChaosSum += FPlatformTime::Cycles() - StartTime;
55 }
56 break;
57 }
59 {
63 for (double i = 0; i < NumIterations; ++i)
64 {
66 uint32 StartTime = FPlatformTime::Cycles();
67 SQAccelerator.Overlap(*CapturedSQ.ChaosImplicitGeometry, CapturedSQ.StartTM, *ChaosHitBuffer, CapturedSQ.QueryFilterData, *CapturedSQ.FilterCallback);
68 ChaosSum += FPlatformTime::Cycles() - StartTime;
69 }
70 break;
71 }
72 }
73
75 float ChaosAvgUs = (ChaosMs * 1000) / NumIterations;
76
78 float PhysXAvgUs = (PhysXMs * 1000) / NumIterations;
79
80
81 if (bHasPhysX)
82 {
83 UE_LOG(LogPhysicsCore, Warning, TEXT("Perf Test:%s\nPhysX:%f(us), Chaos:%f(us)"), *TestName, PhysXAvgUs, ChaosAvgUs);
84 }
85 else
86 {
87 UE_LOG(LogPhysicsCore, Warning, TEXT("Perf Test:%s\nChaos:%f(us), Total:%f(ms)"), *TestName, ChaosAvgUs, ChaosMs);
88 //UE_LOG(LogPhysicsCore, Warning, TEXT("Perf Test:%s\nChaos:%f(us)"), *TestName, AvgChaos);
89 }
90}
91
92
93#if 0
94bool SQComparisonHelper(FPhysTestSerializer& Serializer, bool bEnsureOnMismatch = false)
95{
96 using namespace Chaos;
97
98 bool bTestPassed = true;
99 const float DistanceTolerance = 1e-1f;
100 const float NormalTolerance = 1e-2f;
102
103 const FSQCapture& CapturedSQ = *Serializer.GetSQCapture();
104 switch (CapturedSQ.SQType)
105 {
107 {
109 Serializer.GetPhysXData()->raycast(U2PVector(CapturedSQ.StartPoint), U2PVector(CapturedSQ.Dir), CapturedSQ.DeltaMag, *PxHitBuffer, U2PHitFlags(CapturedSQ.OutputFlags.HitFlags), CapturedSQ.QueryFilterData, CapturedSQ.FilterCallback.Get());
110
111 bTestPassed &= SQ_REPLAY_TEST(PxHitBuffer->hasBlock == CapturedSQ.PhysXRaycastBuffer.hasBlock);
112 bTestPassed &= SQ_REPLAY_TEST(PxHitBuffer->GetNumHits() == CapturedSQ.PhysXRaycastBuffer.GetNumHits());
113 for (int32 Idx = 0; Idx < PxHitBuffer->GetNumHits(); ++Idx)
114 {
115 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(PxHitBuffer.GetHits()[Idx].normal.x, CapturedSQ.PhysXRaycastBuffer.GetHits()[Idx].normal.x));
116 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(PxHitBuffer.GetHits()[Idx].normal.y, CapturedSQ.PhysXRaycastBuffer.GetHits()[Idx].normal.y));
117 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(PxHitBuffer.GetHits()[Idx].normal.z, CapturedSQ.PhysXRaycastBuffer.GetHits()[Idx].normal.z));
118 }
119
120 if (PxHitBuffer->hasBlock)
121 {
122 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(PxHitBuffer->block.position.x, CapturedSQ.PhysXRaycastBuffer.block.position.x, DistanceTolerance));
123 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(PxHitBuffer->block.position.y, CapturedSQ.PhysXRaycastBuffer.block.position.y, DistanceTolerance));
124 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(PxHitBuffer->block.position.z, CapturedSQ.PhysXRaycastBuffer.block.position.z, DistanceTolerance));
125 }
126
130 FChaosSQAccelerator SQAccelerator(*Accelerator); SQAccelerator.Raycast(CapturedSQ.StartPoint, CapturedSQ.Dir, CapturedSQ.DeltaMag, *ChaosHitBuffer, CapturedSQ.OutputFlags.HitFlags, CapturedSQ.QueryFilterData, *CapturedSQ.FilterCallback);
131
132 bTestPassed &= SQ_REPLAY_TEST(ChaosHitBuffer->HasBlockingHit() == CapturedSQ.PhysXRaycastBuffer.hasBlock);
133 bTestPassed &= SQ_REPLAY_TEST(ChaosHitBuffer->GetNumHits() == CapturedSQ.PhysXRaycastBuffer.GetNumHits());
134 for (int32 Idx = 0; Idx < ChaosHitBuffer->GetNumHits(); ++Idx)
135 {
136 //not sorted
137 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer.GetHits()[Idx].WorldNormal.X, CapturedSQ.PhysXRaycastBuffer.GetHits()[Idx].normal.x));
138 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer.GetHits()[Idx].WorldNormal.Y, CapturedSQ.PhysXRaycastBuffer.GetHits()[Idx].normal.y));
139 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer.GetHits()[Idx].WorldNormal.Z, CapturedSQ.PhysXRaycastBuffer.GetHits()[Idx].normal.z));
140 }
141
142 if (ChaosHitBuffer->HasBlockingHit())
143 {
144 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldPosition.X, CapturedSQ.PhysXRaycastBuffer.block.position.x, DistanceTolerance));
145 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldPosition.Y, CapturedSQ.PhysXRaycastBuffer.block.position.y, DistanceTolerance));
146 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldPosition.Z, CapturedSQ.PhysXRaycastBuffer.block.position.z, DistanceTolerance));
147
148 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldNormal.X, CapturedSQ.PhysXRaycastBuffer.block.normal.x, NormalTolerance));
149 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldNormal.Y, CapturedSQ.PhysXRaycastBuffer.block.normal.y, NormalTolerance));
150 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldNormal.Z, CapturedSQ.PhysXRaycastBuffer.block.normal.z, NormalTolerance));
151 }
152 break;
153 }
155 {
156 //For sweep there are many solutions (many contacts possible) so we only bother testing for Distance
158 Serializer.GetPhysXData()->sweep(CapturedSQ.PhysXGeometry.any(), U2PTransform(CapturedSQ.StartTM), U2PVector(CapturedSQ.Dir), CapturedSQ.DeltaMag, *PxHitBuffer, U2PHitFlags(CapturedSQ.OutputFlags.HitFlags), CapturedSQ.QueryFilterData, CapturedSQ.FilterCallback.Get());
159
160 bTestPassed &= SQ_REPLAY_TEST(PxHitBuffer->hasBlock == CapturedSQ.PhysXSweepBuffer.hasBlock);
161 bTestPassed &= SQ_REPLAY_TEST(PxHitBuffer->GetNumHits() == CapturedSQ.PhysXSweepBuffer.GetNumHits());
162 for (int32 Idx = 0; Idx < PxHitBuffer->GetNumHits(); ++Idx)
163 {
164 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(PxHitBuffer.GetHits()[Idx].normal.x, CapturedSQ.PhysXSweepBuffer.GetHits()[Idx].normal.x, DistanceTolerance));
165 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(PxHitBuffer.GetHits()[Idx].normal.y, CapturedSQ.PhysXSweepBuffer.GetHits()[Idx].normal.y, DistanceTolerance));
166 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(PxHitBuffer.GetHits()[Idx].normal.z, CapturedSQ.PhysXSweepBuffer.GetHits()[Idx].normal.z, DistanceTolerance));
167 }
168
172 FChaosSQAccelerator SQAccelerator(*Accelerator); SQAccelerator.Sweep(*CapturedSQ.ChaosGeometry, CapturedSQ.StartTM, CapturedSQ.Dir, CapturedSQ.DeltaMag, *ChaosHitBuffer, CapturedSQ.OutputFlags.HitFlags, CapturedSQ.QueryFilterData, *CapturedSQ.FilterCallback);
173
174 bTestPassed &= SQ_REPLAY_TEST(ChaosHitBuffer->HasBlockingHit() == CapturedSQ.PhysXSweepBuffer.hasBlock);
175 bTestPassed &= SQ_REPLAY_TEST(ChaosHitBuffer->GetNumHits() == CapturedSQ.PhysXSweepBuffer.GetNumHits());
176 for (int32 Idx = 0; Idx < ChaosHitBuffer->GetNumHits(); ++Idx)
177 {
178 //not sorted
179 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer.GetHits()[Idx].WorldNormal.X, CapturedSQ.PhysXSweepBuffer.GetHits()[Idx].normal.x));
180 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer.GetHits()[Idx].WorldNormal.Y, CapturedSQ.PhysXSweepBuffer.GetHits()[Idx].normal.y));
181 //bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer.GetHits()[Idx].WorldNormal.Z, CapturedSQ.PhysXSweepBuffer.GetHits()[Idx].normal.z));
182 }
183
184 if (ChaosHitBuffer->HasBlockingHit())
185 {
186 bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->Distance, CapturedSQ.PhysXSweepBuffer.block.distance, DistanceTolerance));
187 }
188 break;
189 }
191 {
193 Serializer.GetPhysXData()->overlap(CapturedSQ.PhysXGeometry.any(), U2PTransform(CapturedSQ.StartTM), *PxHitBuffer, CapturedSQ.QueryFilterData, CapturedSQ.FilterCallback.Get());
194
195 bTestPassed &= SQ_REPLAY_TEST(PxHitBuffer->GetNumHits() == CapturedSQ.PhysXOverlapBuffer.GetNumHits());
196
201 SQAccelerator.Overlap(*CapturedSQ.ChaosGeometry, CapturedSQ.StartTM, *ChaosHitBuffer, CapturedSQ.QueryFilterData, *CapturedSQ.FilterCallback);
202
203 bTestPassed &= SQ_REPLAY_TEST(ChaosHitBuffer->GetNumHits() == CapturedSQ.PhysXOverlapBuffer.GetNumHits());
204 break;
205 }
206 }
207
208 return bTestPassed;
209}
210
211#endif
212
214{
215 using namespace Chaos;
216
217 bool bTestPassed = true;
218 const float DistanceTolerance = 1e-1f;
219 const float NormalTolerance = 1e-2f;
221
222 const FSQCapture& CapturedSQ = *Serializer.GetSQCapture();
223 switch (CapturedSQ.SQType)
224 {
226 {
229
232 SQAccelerator.Raycast(CapturedSQ.StartPoint, CapturedSQ.Dir, CapturedSQ.DeltaMag, ChaosHitBuffer, CapturedSQ.OutputFlags.HitFlags, CapturedSQ.QueryFilterData, *CapturedSQ.FilterCallback);
233
234 const bool bHasBlockingHit = ChaosHitBuffer.HasBlockingHit();
235 const int32 NumHits = ChaosHitBuffer.GetNumHits();
236 for (int32 Idx = 0; Idx < NumHits; ++Idx)
237 {
238 // TODO: DO tests
239 }
240 break;
241 }
243 {
248 SQAccelerator.Sweep(*CapturedSQ.ChaosImplicitGeometry, CapturedSQ.StartTM, CapturedSQ.Dir, CapturedSQ.DeltaMag, ChaosHitBuffer, CapturedSQ.OutputFlags.HitFlags, CapturedSQ.QueryFilterData, *CapturedSQ.FilterCallback);
249
250 const bool bHasBlockingHit = ChaosHitBuffer.HasBlockingHit();
251 const int32 NumHits = ChaosHitBuffer.GetNumHits();
252 for (int32 Idx = 0; Idx < NumHits; ++Idx)
253 {
254 ChaosInterface::FSweepHit& Hit = ChaosHitBuffer.GetHits()[Idx];
255
256 if (!HadInitialOverlap(Hit))
257 {
258 const int32 FaceIdx = FindFaceIndex(Hit, CapturedSQ.Dir);
259 bTestPassed |= (FaceIdx != INDEX_NONE);
260 }
261 }
262
263 break;
264 }
266 {
271 SQAccelerator.Overlap(*CapturedSQ.ChaosImplicitGeometry, CapturedSQ.StartTM, ChaosHitBuffer, CapturedSQ.QueryFilterData, *CapturedSQ.FilterCallback);
272 break;
273 }
274 }
275
276 return bTestPassed;
277}
278
279
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
uint32 FindFaceIndex(const FHitLocation &Hit, const FVector &UnitDir)
Definition PhysicsInterfaceUtilsCore.cpp:38
bool SQValidityHelper(FPhysTestSerializer &Serializer)
Definition SQVerifier.h:213
void SQPerfComparisonHelper(const FString &TestName, FPhysTestSerializer &Serializer, bool bEnsureOnMismatch=false)
Definition SQVerifier.h:18
#define SQ_REPLAY_TEST(cond)
Definition SQVerifier.h:14
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition SQTypes.h:220
CHAOS_API void UpdateExternalAccelerationStructure_External(ISpatialAccelerationCollection< FAccelerationStructureHandle, FReal, 3 > *&ExternalStructure, FPendingSpatialDataQueue &PendingExternal)
Definition PBDRigidsEvolution.cpp:972
Definition ISpatialAccelerationCollection.h:23
Definition SQAccelerator.h:38
Definition PhysTestSerializer.h:37
const FSQCapture * GetSQCapture()
Definition PhysTestSerializer.h:63
Chaos::FPBDRigidsEvolution * GetChaosData()
Definition PhysTestSerializer.h:76
Definition SkeletalMeshComponent.h:307
Definition SQTypes.h:106
Definition PendingSpatialData.h:184
static uint32 Cycles()
Definition AndroidPlatformTime.h:27
static float ToMilliseconds(const uint32 Cycles)
Definition GenericPlatformTime.h:183
static UE_FORCEINLINE_HINT bool IsNearlyEqual(float A, float B, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:388
Definition SQCapture.h:41