Forráskód Böngészése

Implemented test that shows how to implement friction and restitution per triangle or shape (#51)

Fixes #49
Jorrit Rouwe 3 éve
szülő
commit
aecf914a89

+ 2 - 0
Samples/Samples.cmake

@@ -77,6 +77,8 @@ set(SAMPLES_SRC_FILES
 	${SAMPLES_ROOT}/Tests/General/DampingTest.h
 	${SAMPLES_ROOT}/Tests/General/FrictionTest.cpp
 	${SAMPLES_ROOT}/Tests/General/FrictionTest.h
+	${SAMPLES_ROOT}/Tests/General/FrictionPerTriangleTest.cpp
+	${SAMPLES_ROOT}/Tests/General/FrictionPerTriangleTest.h
 	${SAMPLES_ROOT}/Tests/General/FunnelTest.cpp
 	${SAMPLES_ROOT}/Tests/General/FunnelTest.h
 	${SAMPLES_ROOT}/Tests/General/GravityFactorTest.cpp

+ 2 - 0
Samples/SamplesApp.cpp

@@ -58,6 +58,7 @@ JPH_DECLARE_RTTI_FOR_FACTORY(WallTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(IslandTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(FunnelTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(FrictionTest)
+JPH_DECLARE_RTTI_FOR_FACTORY(FrictionPerTriangleTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(GravityFactorTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(RestitutionTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(DampingTest)
@@ -86,6 +87,7 @@ static TestNameAndRTTI sGeneralTests[] =
 	{ "Island",								JPH_RTTI(IslandTest) },
 	{ "Funnel",								JPH_RTTI(FunnelTest) },
 	{ "Friction",							JPH_RTTI(FrictionTest) },
+	{ "Friction (Per Triangle)",			JPH_RTTI(FrictionPerTriangleTest) },
 	{ "Gravity Factor",						JPH_RTTI(GravityFactorTest) },
 	{ "Restitution",						JPH_RTTI(RestitutionTest) },
 	{ "Damping",							JPH_RTTI(DampingTest) },

+ 94 - 0
Samples/Tests/General/FrictionPerTriangleTest.cpp

@@ -0,0 +1,94 @@
+// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
+// SPDX-License-Identifier: MIT
+
+#include <TestFramework.h>
+
+#include <Tests/General/FrictionPerTriangleTest.h>
+#include <Physics/Collision/Shape/BoxShape.h>
+#include <Physics/Collision/Shape/MeshShape.h>
+#include <Geometry/Triangle.h>
+#include <Physics/Body/BodyCreationSettings.h>
+#include <Layers.h>
+
+JPH_IMPLEMENT_RTTI_VIRTUAL(FrictionPerTriangleTest) 
+{ 
+	JPH_ADD_BASE_CLASS(FrictionPerTriangleTest, Test) 
+}
+
+void FrictionPerTriangleTest::Initialize() 
+{
+	const int num_sections = 5;
+	const float section_size = 50.0f;
+
+	// Create a strip of triangles
+	TriangleList triangles;
+	for (int z = 0; z <= num_sections; ++z)
+	{
+		float z1 = section_size * (z - 0.5f * num_sections);
+		float z2 = z1 + section_size;
+
+		Float3 v1 = Float3(-100.0f, 0, z1);
+		Float3 v2 = Float3(100.0f, 0, z1);
+		Float3 v3 = Float3(-100.0f, 0, z2);
+		Float3 v4 = Float3(100.0f, 0, z2);
+
+		triangles.push_back(Triangle(v1, v3, v4, z));
+		triangles.push_back(Triangle(v1, v4, v2, z));
+	}
+
+	// Create materials with increasing friction
+	PhysicsMaterialList materials;
+	for (uint i = 0; i <= num_sections; ++i)
+	{
+		float friction = float(i) / float(num_sections);
+		materials.push_back(new MyMaterial("Friction " + ConvertToString(friction), Color::sGetDistinctColor(i), friction, 0.0f));
+	}
+
+	// A ramp
+	mBodyInterface->CreateAndAddBody(BodyCreationSettings(new MeshShapeSettings(triangles, materials), Vec3::sZero(), Quat::sRotation(Vec3::sAxisX(), 0.2f * JPH_PI), EMotionType::Static, Layers::NON_MOVING), EActivation::DontActivate);
+
+	// A box with friction 1 that slides down the ramp
+	Ref<BoxShape> box_shape = new BoxShape(Vec3(2.0f, 2.0f, 2.0f), cDefaultConvexRadius, new MyMaterial("Box Friction 1", Color::sYellow, 1.0f, 0.0f));
+	mBodyInterface->CreateAndAddBody(BodyCreationSettings(box_shape, Vec3(0, 60.0f, -75.0f), Quat::sRotation(Vec3::sAxisX(), 0.2f * JPH_PI), EMotionType::Dynamic, Layers::MOVING), EActivation::Activate);
+}
+
+void FrictionPerTriangleTest::sGetFrictionAndRestitution(const Body &inBody, const SubShapeID &inSubShapeID, float &outFriction, float &outRestitution)
+{
+	// Get the material that corresponds to the sub shape ID
+	const PhysicsMaterial *material = inBody.GetShape()->GetMaterial(inSubShapeID);
+	if (material == PhysicsMaterial::sDefault)
+	{
+		// This is the default material, use the settings from the body (note all bodies in our test have a material so this should not happen)
+		outFriction = inBody.GetFriction();
+		outRestitution = inBody.GetRestitution();
+	}
+	else
+	{
+		// If it's not the default material we know its a material that we created so we can cast it and get the values
+		const MyMaterial *my_material = static_cast<const MyMaterial *>(material);
+		outFriction = my_material->mFriction;
+		outRestitution = my_material->mRestitution;
+	}
+}
+
+void FrictionPerTriangleTest::sOverrideContactSettings(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings)
+{
+	// Get the custom friction and restitution for both bodies
+	float friction1, friction2, restitution1, restitution2;
+	sGetFrictionAndRestitution(inBody1, inManifold.mSubShapeID1, friction1, restitution1);
+	sGetFrictionAndRestitution(inBody2, inManifold.mSubShapeID2, friction2, restitution2);
+
+	// Use the default formulas for combining friction and restitution
+	ioSettings.mCombinedFriction = sqrt(friction1 * friction2);
+	ioSettings.mCombinedRestitution = max(restitution1, restitution2);
+}
+
+void FrictionPerTriangleTest::OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings)
+{
+	sOverrideContactSettings(inBody1, inBody2, inManifold, ioSettings);
+}
+
+void FrictionPerTriangleTest::OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings)
+{
+	sOverrideContactSettings(inBody1, inBody2, inManifold, ioSettings);
+}

+ 45 - 0
Samples/Tests/General/FrictionPerTriangleTest.h

@@ -0,0 +1,45 @@
+// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <Tests/Test.h>
+#include <Physics/Collision/ContactListener.h>
+#include <Physics/Collision/PhysicsMaterialSimple.h>
+
+/// This test demonstrates how you can use a contact listener and your own material definition to get friction and restitution per triangle or sub shape of a compound shape
+class FrictionPerTriangleTest : public Test, public ContactListener
+{
+public:
+	JPH_DECLARE_RTTI_VIRTUAL(FrictionPerTriangleTest)
+
+	// See: Test
+	virtual void	Initialize() override;
+
+	/// A custom material implementation that stores its own friction and restitution
+	/// Note: Make sure you set PhysicsMaterial::sDefault to something your application understands (explicitly check PhysicsMaterial::sDefault to prevent casting to the wrong type in sGetFrictionAndRestitution)
+	class MyMaterial : public PhysicsMaterialSimple
+	{
+	public:
+		// Note: Not implementing serialization because we don't serialize this material in this example!
+
+		/// Constructor
+					MyMaterial(const string &inName, ColorArg inColor, float inFriction, float inRestitution) : PhysicsMaterialSimple(inName, inColor), mFriction(inFriction), mRestitution(inRestitution) { }
+
+		float		mFriction;
+		float		mRestitution;
+	};
+
+	/// Extract custom friction and restitution from a body and sub shape ID
+	static void		sGetFrictionAndRestitution(const Body &inBody, const SubShapeID &inSubShapeID, float &outFriction, float &outRestitution);
+
+	/// Calculates and overrides friction and restitution settings for a contact between two bodies
+	static void		sOverrideContactSettings(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings);
+
+	// If this test implements a contact listener, it should be returned here
+	virtual ContactListener *GetContactListener() override		{ return this; }
+
+	// See: ContactListener
+	virtual void	OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override;
+	virtual void	OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override;
+};