Browse Source

Added a sample that shows how to dynamically scale a shape

Jorrit Rouwe 1 year ago
parent
commit
7ef0fbc50d

+ 2 - 0
Samples/Samples.cmake

@@ -187,6 +187,8 @@ set(SAMPLES_SRC_FILES
 	${SAMPLES_ROOT}/Tests/Test.h
 	${SAMPLES_ROOT}/Tests/Test.h
 	${SAMPLES_ROOT}/Tests/Tools/LoadSnapshotTest.cpp
 	${SAMPLES_ROOT}/Tests/Tools/LoadSnapshotTest.cpp
 	${SAMPLES_ROOT}/Tests/Tools/LoadSnapshotTest.h
 	${SAMPLES_ROOT}/Tests/Tools/LoadSnapshotTest.h
+	${SAMPLES_ROOT}/Tests/ScaledShapes/DynamicScaledShape.cpp
+	${SAMPLES_ROOT}/Tests/ScaledShapes/DynamicScaledShape.h
 	${SAMPLES_ROOT}/Tests/ScaledShapes/ScaledBoxShapeTest.cpp
 	${SAMPLES_ROOT}/Tests/ScaledShapes/ScaledBoxShapeTest.cpp
 	${SAMPLES_ROOT}/Tests/ScaledShapes/ScaledBoxShapeTest.h
 	${SAMPLES_ROOT}/Tests/ScaledShapes/ScaledBoxShapeTest.h
 	${SAMPLES_ROOT}/Tests/ScaledShapes/ScaledCapsuleShapeTest.cpp
 	${SAMPLES_ROOT}/Tests/ScaledShapes/ScaledCapsuleShapeTest.cpp

+ 3 - 1
Samples/SamplesApp.cpp

@@ -241,6 +241,7 @@ JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, ScaledStaticCompoundShapeTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, ScaledMutableCompoundShapeTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, ScaledMutableCompoundShapeTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, ScaledTriangleShapeTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, ScaledTriangleShapeTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, ScaledOffsetCenterOfMassShapeTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, ScaledOffsetCenterOfMassShapeTest)
+JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, DynamicScaledShape)
 
 
 static TestNameAndRTTI sScaledShapeTests[] =
 static TestNameAndRTTI sScaledShapeTests[] =
 {
 {
@@ -255,7 +256,8 @@ static TestNameAndRTTI sScaledShapeTests[] =
 	{ "Static Compound Shape",				JPH_RTTI(ScaledStaticCompoundShapeTest) },
 	{ "Static Compound Shape",				JPH_RTTI(ScaledStaticCompoundShapeTest) },
 	{ "Mutable Compound Shape",				JPH_RTTI(ScaledMutableCompoundShapeTest) },
 	{ "Mutable Compound Shape",				JPH_RTTI(ScaledMutableCompoundShapeTest) },
 	{ "Triangle Shape",						JPH_RTTI(ScaledTriangleShapeTest) },
 	{ "Triangle Shape",						JPH_RTTI(ScaledTriangleShapeTest) },
-	{ "Offset Center Of Mass Shape",		JPH_RTTI(ScaledOffsetCenterOfMassShapeTest) }
+	{ "Offset Center Of Mass Shape",		JPH_RTTI(ScaledOffsetCenterOfMassShapeTest) },
+	{ "Dynamic Scaled Shape",				JPH_RTTI(DynamicScaledShape) }
 };
 };
 
 
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, CreateRigTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, CreateRigTest)

+ 65 - 0
Samples/Tests/ScaledShapes/DynamicScaledShape.cpp

@@ -0,0 +1,65 @@
+// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
+// SPDX-FileCopyrightText: 2024 Jorrit Rouwe
+// SPDX-License-Identifier: MIT
+
+#include <TestFramework.h>
+
+#include <Tests/ScaledShapes/DynamicScaledShape.h>
+#include <Jolt/Physics/Collision/Shape/SphereShape.h>
+#include <Jolt/Physics/Collision/Shape/ScaledShape.h>
+#include <Jolt/Physics/Body/BodyCreationSettings.h>
+#include <Layers.h>
+
+JPH_IMPLEMENT_RTTI_VIRTUAL(DynamicScaledShape)
+{
+	JPH_ADD_BASE_CLASS(DynamicScaledShape, Test)
+}
+
+void DynamicScaledShape::Initialize()
+{
+	// Floor
+	CreateHeightFieldTerrain();
+
+	// Create scaled sphere
+	RefConst<Shape> scaled_sphere_shape = new ScaledShape(new SphereShape(2.0f), Vec3::sReplicate(1.0f));
+	mBodyID = mBodyInterface->CreateAndAddBody(BodyCreationSettings(scaled_sphere_shape, RVec3(0, 10, 0), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING), EActivation::Activate);
+}
+
+void DynamicScaledShape::PrePhysicsUpdate(const PreUpdateParams &inParams)
+{
+	// Update time
+	mTime += inParams.mDeltaTime;
+
+	BodyLockWrite lock(mPhysicsSystem->GetBodyLockInterface(), mBodyID);
+	if (lock.Succeeded())
+	{
+		Body &body = lock.GetBody();
+
+		// Fetch the inner shape
+		// Note that we know here that the inner shape is the original shape, but if you're scaling a CompoundShape non-uniformly the inner shape
+		// may be a new compound shape with the scale baked into the children. In this case you need to keep track of your original shape yourself.
+		JPH_ASSERT(body.GetShape()->GetSubType() == EShapeSubType::Scaled);
+		const ScaledShape *scaled_shape = static_cast<const ScaledShape *>(body.GetShape());
+		const Shape *non_scaled_shape = scaled_shape->GetInnerShape();
+
+		// Rescale the sphere
+		float new_scale = 1.0f + 0.5f * Sin(mTime);
+		Shape::ShapeResult new_shape = non_scaled_shape->ScaleShape(Vec3::sReplicate(new_scale));
+		JPH_ASSERT(new_shape.IsValid()); // We're uniformly scaling a sphere, this should always succeed
+
+		// Note: Using non-locking interface here because we already have the lock
+		// Also note that scaling shapes may cause simulation issues as the bodies can get stuck when they get bigger.
+		// Recalculating mass every frame can also be an expensive operation.
+		mPhysicsSystem->GetBodyInterfaceNoLock().SetShape(body.GetID(), new_shape.Get(), true, EActivation::Activate);
+	}
+}
+
+void DynamicScaledShape::SaveState(StateRecorder &inStream) const
+{
+	inStream.Write(mTime);
+}
+
+void DynamicScaledShape::RestoreState(StateRecorder &inStream)
+{
+	inStream.Read(mTime);
+}

+ 26 - 0
Samples/Tests/ScaledShapes/DynamicScaledShape.h

@@ -0,0 +1,26 @@
+// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
+// SPDX-FileCopyrightText: 2024 Jorrit Rouwe
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <Tests/Test.h>
+
+// Demonstrates how you can scale a shape dynamically while a body is being simulated
+class DynamicScaledShape : public Test
+{
+public:
+	JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, DynamicScaledShape)
+
+	// See: Test
+	virtual void	Initialize() override;
+	virtual void	PrePhysicsUpdate(const PreUpdateParams &inParams) override;
+
+	// Saving / restoring state for replay
+	virtual void	SaveState(StateRecorder &inStream) const override;
+	virtual void	RestoreState(StateRecorder &inStream) override;
+
+private:
+	BodyID			mBodyID;
+	float			mTime = 0.0f;
+};

+ 1 - 1
Samples/Tests/ScaledShapes/ScaledSphereShapeTest.cpp

@@ -20,7 +20,7 @@ void ScaledSphereShapeTest::Initialize()
 	// Floor
 	// Floor
 	CreateFloor();
 	CreateFloor();
 
 
-	// Create box
+	// Create sphere
 	RefConst<SphereShape> sphere_shape = new SphereShape(2.0f);
 	RefConst<SphereShape> sphere_shape = new SphereShape(2.0f);
 
 
 	// Original shape
 	// Original shape