Browse Source

Added LargeMeshScene test to the PerformanceTest

Jorrit Rouwe 8 months ago
parent
commit
094bbda1a9

+ 118 - 0
PerformanceTest/LargeMeshScene.h

@@ -0,0 +1,118 @@
+// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
+// SPDX-FileCopyrightText: 2024 Jorrit Rouwe
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+// Jolt includes
+#include <Jolt/Physics/Collision/Shape/BoxShape.h>
+#include <Jolt/Physics/Collision/Shape/SphereShape.h>
+#include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
+#include <Jolt/Physics/Collision/Shape/MeshShape.h>
+#include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
+#include <Jolt/Physics/Body/BodyCreationSettings.h>
+
+// Local includes
+#include "PerformanceTestScene.h"
+#include "Layers.h"
+
+// A scene that first finds the largest possible mesh and then simulates some objects on it
+class LargeMeshScene : public PerformanceTestScene
+{
+public:
+	virtual const char *	GetName() const override
+	{
+		return "LargeMeshScene";
+	}
+
+	virtual bool			Load() override
+	{
+		// Create mesh shape creation settings
+		mMeshCreationSettings.mMotionType = EMotionType::Static;
+		mMeshCreationSettings.mObjectLayer = Layers::NON_MOVING;
+		mMeshCreationSettings.mPosition = RVec3::sZero();
+		mMeshCreationSettings.mFriction = 0.5f;
+		mMeshCreationSettings.mRestitution = 0.6f;
+
+		Trace("Finding the largest possible mesh, this will take some time!");
+		Trace("N, Num Triangles, Mesh Size, Size / Triangle, SubShapeID Bits, Time");
+		for (int i = 1; ; ++i)
+		{
+			const int n = 500 * i;
+			const float cell_size = 1.0f;
+			const float max_height = 50.0f;
+
+			// Create heights
+			MeshShapeSettings settings;
+			float center = n * cell_size / 2;
+			settings.mTriangleVertices.reserve((n + 1)*(n + 1));
+			for (int x = 0; x <= n; ++x)
+				for (int z = 0; z <= n; ++z)
+					settings.mTriangleVertices.push_back(Float3(cell_size * x - center, max_height * Sin(float(x) * 50.0f / n) * Cos(float(z) * 50.0f / n), cell_size * z - center));
+
+			// Create regular grid of triangles
+			settings.mIndexedTriangles.reserve(2 * n * n);
+			for (int x = 0; x < n; ++x)
+				for (int z = 0; z < n; ++z)
+				{
+					settings.mIndexedTriangles.push_back(IndexedTriangle(x + z * (n + 1), x + 1 + z * (n + 1), x + (z + 1)*(n + 1)));
+					settings.mIndexedTriangles.push_back(IndexedTriangle(x + 1 + z * (n + 1), x + 1 + (z + 1)*(n + 1), x + (z + 1)*(n + 1)));
+				}
+
+			// Start measuring
+			chrono::high_resolution_clock::time_point clock_start = chrono::high_resolution_clock::now();
+
+			// Create the mesh shape
+			Shape::ShapeResult result = settings.Create();
+
+			// Stop measuring
+			chrono::high_resolution_clock::time_point clock_end = chrono::high_resolution_clock::now();
+			chrono::nanoseconds duration = chrono::duration_cast<chrono::nanoseconds>(clock_end - clock_start);
+
+			if (result.HasError())
+			{
+				// Break when we get an error
+				Trace("Mesh creation failed with error: %s", result.GetError().c_str());
+				break;
+			}
+			else
+			{
+				// Trace stats
+				RefConst<Shape> shape = result.Get();
+				Shape::Stats stats = shape->GetStats();
+				Trace("%u, %u, %llu, %.1f, %d, %.3f", n, stats.mNumTriangles, (uint64)stats.mSizeBytes, double(stats.mSizeBytes) / double(stats.mNumTriangles), shape->GetSubShapeIDBitsRecursive(), 1.0e-9 * double(duration.count()));
+
+				// Set this shape as the best shape so far
+				mMeshCreationSettings.SetShape(shape);
+			}
+		}
+
+		return true;
+	}
+
+	virtual void			StartTest(PhysicsSystem &inPhysicsSystem, EMotionQuality inMotionQuality) override
+	{
+		// Create background
+		BodyInterface &bi = inPhysicsSystem.GetBodyInterface();
+		bi.CreateAndAddBody(mMeshCreationSettings, EActivation::DontActivate);
+
+		// Construct bodies
+		BodyCreationSettings creation_settings;
+		creation_settings.mMotionType = EMotionType::Dynamic;
+		creation_settings.mMotionQuality = inMotionQuality;
+		creation_settings.mObjectLayer = Layers::MOVING;
+		creation_settings.mFriction = 0.5f;
+		creation_settings.mRestitution = 0.6f;
+		creation_settings.SetShape(new BoxShape(Vec3(0.5f, 0.75f, 1.0f)));
+		for (int x = -10; x <= 10; ++x)
+			for (int y = 0; y < 10; ++y)
+				for (int z = -10; z <= 10; ++z)
+				{
+					creation_settings.mPosition = RVec3(7.5_r * x, 55.0_r + 2.0_r * y, 7.5_r * z);
+					bi.CreateAndAddBody(creation_settings, EActivation::Activate);
+				}
+	}
+
+private:
+	BodyCreationSettings	mMeshCreationSettings;
+};

+ 1 - 0
PerformanceTest/PerformanceTest.cmake

@@ -9,6 +9,7 @@ set(PERFORMANCE_TEST_SRC_FILES
 	${PERFORMANCE_TEST_ROOT}/PerformanceTestScene.h
 	${PERFORMANCE_TEST_ROOT}/RagdollScene.h
 	${PERFORMANCE_TEST_ROOT}/ConvexVsMeshScene.h
+	${PERFORMANCE_TEST_ROOT}/LargeMeshScene.h
 	${PERFORMANCE_TEST_ROOT}/Layers.h
 )
 

+ 9 - 6
PerformanceTest/PerformanceTest.cpp

@@ -43,6 +43,7 @@ JPH_SUPPRESS_WARNINGS
 #include "RagdollScene.h"
 #include "ConvexVsMeshScene.h"
 #include "PyramidScene.h"
+#include "LargeMeshScene.h"
 
 // Time step for physics
 constexpr float cDeltaTime = 1.0f / 60.0f;
@@ -112,6 +113,8 @@ int main(int argc, char** argv)
 				scene = unique_ptr<PerformanceTestScene>(new ConvexVsMeshScene);
 			else if (strcmp(arg + 3, "Pyramid") == 0)
 				scene = unique_ptr<PerformanceTestScene>(new PyramidScene);
+			else if (strcmp(arg + 3, "LargeMesh") == 0)
+				scene = unique_ptr<PerformanceTestScene>(new LargeMeshScene);
 			else
 			{
 				Trace("Invalid scene");
@@ -211,18 +214,18 @@ int main(int argc, char** argv)
 	// Create temp allocator
 	TempAllocatorImpl temp_allocator(32 * 1024 * 1024);
 
-	// Load the scene
-	if (scene == nullptr)
-		scene = create_ragdoll_scene();
-	if (!scene->Load())
-		return 1;
-
 	// Show used instruction sets
 	Trace(GetConfigurationString());
 
 	// Output scene we're running
 	Trace("Running scene: %s", scene->GetName());
 
+	// Load the scene
+	if (scene == nullptr)
+		scene = create_ragdoll_scene();
+	if (!scene->Load())
+		return 1;
+
 	// Create mapping table from object layer to broadphase layer
 	BPLayerInterfaceImpl broad_phase_layer_interface;