Skip to content

Commit 5e7d79a

Browse files
committed
Add ability to create oriented contact materials through scripting and to add contact materials after initialization
1 parent 0a2aa8d commit 5e7d79a

5 files changed

Lines changed: 214 additions & 7 deletions

File tree

AGXUnity/ContactMaterial.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -408,13 +408,13 @@ public void InitializeOrientedFriction( bool isOriented,
408408
GameObject referenceObject,
409409
FrictionModel.PrimaryDirection primaryDirection )
410410
{
411-
if ( isOriented && FrictionModel.TrackFrictionModel ) {
412-
Debug.LogWarning( "Setting IsOriented on a ContactMaterial with a track FrictionModel is reduntant and will be ignored." );
411+
if ( !isOriented || referenceObject == null || FrictionModel == null )
413412
return;
414-
}
415413

416-
if ( !isOriented || referenceObject == null || FrictionModel == null )
414+
if ( isOriented && FrictionModel.TrackFrictionModel ) {
415+
Debug.LogWarning( "Setting IsOriented on a ContactMaterial with a track FrictionModel is redundant and will be ignored." );
417416
return;
417+
}
418418

419419
if ( !Application.isPlaying ) {
420420
Debug.LogError( "Oriented friction: Invalid to initialize oriented friction in edit mode.", this );
@@ -450,8 +450,10 @@ public void InitializeOrientedFriction( bool isOriented,
450450

451451
if ( rb != null )
452452
FrictionModel.InitializeOriented( rb, primaryDirection );
453-
else
453+
else if ( shape != null )
454454
FrictionModel.InitializeOriented( shape, primaryDirection );
455+
else if ( observer != null )
456+
FrictionModel.InitializeOriented( observer, primaryDirection );
455457
}
456458

457459
protected override void Construct()

AGXUnity/ContactMaterialManager.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace AGXUnity
99
/// Contact material list data.
1010
/// </summary>
1111
[Serializable]
12-
public class ContactMaterialEntry
12+
public class ContactMaterialEntry : IEquatable<ContactMaterialEntry>
1313
{
1414
public ContactMaterial ContactMaterial = null;
1515

@@ -70,6 +70,13 @@ private void UpdateInitializedContactMaterial()
7070
ReferenceObject,
7171
PrimaryDirection );
7272
}
73+
74+
public bool Equals( ContactMaterialEntry other ) =>
75+
other is not null &&
76+
other.ContactMaterial == ContactMaterial &&
77+
other.m_isOriented == m_isOriented &&
78+
other.m_referenceObject == m_referenceObject &&
79+
other.m_primaryDirection == m_primaryDirection;
7380
}
7481

7582
/// <summary>
@@ -101,7 +108,18 @@ public void Add( ContactMaterial contactMaterial )
101108
if ( contactMaterial == null || ContactMaterials.Contains( contactMaterial ) )
102109
return;
103110

104-
m_contactMaterials.Add( new ContactMaterialEntry() { ContactMaterial = contactMaterial } );
111+
Add( new ContactMaterialEntry() { ContactMaterial = contactMaterial } );
112+
}
113+
114+
public void Add( ContactMaterialEntry entry )
115+
{
116+
if ( entry == null || ContactMaterialEntries.Contains( entry ) )
117+
return;
118+
119+
m_contactMaterials.Add( entry );
120+
121+
if ( this.State == States.INITIALIZED )
122+
Initialize( entry );
105123
}
106124

107125
public void Remove( ContactMaterial contactMaterial )

AGXUnity/FrictionModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ public agx.FrictionModel CreateNative( EType type,
264264
m_orientedFrictionReferenceObject.GetComponent<RigidBody>().Native.getFrame() :
265265
m_orientedFrictionReferenceObject.GetComponent<Collide.Shape>() != null ?
266266
m_orientedFrictionReferenceObject.GetComponent<Collide.Shape>().NativeGeometry.getFrame() :
267+
m_orientedFrictionReferenceObject.GetComponent<ObserverFrame>() != null ?
268+
m_orientedFrictionReferenceObject.GetComponent<ObserverFrame>().Native.getFrame() :
267269
null;
268270
}
269271

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
using AGXUnity;
2+
using AGXUnity.Collide;
3+
using NUnit.Framework;
4+
using System.Collections;
5+
using System.Linq;
6+
using UnityEngine;
7+
using UnityEngine.TestTools;
8+
9+
namespace AGXUnityTesting.Runtime
10+
{
11+
public class OrientedFrictionTests : AGXUnityFixture
12+
{
13+
private ShapeMaterial m_groundMat;
14+
private FrictionModel m_friction;
15+
16+
[OneTimeSetUp]
17+
public void SetupGroundAssets()
18+
{
19+
m_groundMat = ShapeMaterial.CreateInstance<ShapeMaterial>();
20+
m_friction = FrictionModel.CreateInstance<FrictionModel>();
21+
m_friction.Type = FrictionModel.EType.BoxFriction;
22+
m_friction.SolveType = FrictionModel.ESolveType.Direct;
23+
}
24+
25+
[UnitySetUp]
26+
public IEnumerator SetupFrictionScene()
27+
{
28+
var go = Factory.Create<AGXUnity.Collide.Box>();
29+
go.name = "Ground";
30+
go.transform.rotation = Quaternion.AngleAxis( 30, Vector3.forward );
31+
32+
var boxComp = go.GetComponent<AGXUnity.Collide.Box>();
33+
boxComp.HalfExtents = new Vector3( 10, 0.2f, 10 );
34+
boxComp.Material = m_groundMat;
35+
36+
AGXUnity.Rendering.ShapeVisual.Create( boxComp );
37+
38+
yield return TestUtils.WaitUntilLoaded();
39+
}
40+
41+
[UnityTearDown]
42+
public IEnumerator TearDownFrictionScene()
43+
{
44+
var objects = Object.FindObjectsByType<ScriptComponent>( FindObjectsSortMode.None );
45+
46+
var toDelete = objects.Where(x => x is not Simulation).Select(x => x.gameObject).ToArray();
47+
48+
yield return TestUtils.DestroyAndWait( toDelete );
49+
}
50+
51+
private (ShapeMaterial, RigidBody, Shape, ObserverFrame) CreateSlidingBox()
52+
{
53+
var rbGO = new GameObject("Sliding box");
54+
var rb = rbGO.AddComponent<RigidBody>();
55+
56+
var boxMat = ShapeMaterial.CreateInstance<ShapeMaterial>();
57+
58+
var boxGO = new GameObject("Box Geometry");
59+
boxGO.transform.parent = rbGO.transform;
60+
61+
var boxGeom = boxGO.AddComponent<Box>();
62+
boxGeom.Material = boxMat;
63+
64+
AGXUnity.Rendering.ShapeVisual.Create( boxGeom );
65+
66+
var oFrameGO = new GameObject("Observer");
67+
oFrameGO.transform.parent = rbGO.transform;
68+
69+
var oFrame = oFrameGO.AddComponent<ObserverFrame>();
70+
71+
rbGO.transform.position = new Vector3( 5, 4, 0 );
72+
rbGO.transform.rotation = Quaternion.AngleAxis( 30, Vector3.forward );
73+
74+
return (boxMat, rb, boxGeom, oFrame);
75+
}
76+
77+
private void TestSlides( RigidBody box, bool shouldSlide )
78+
{
79+
Assert.That( box.transform.position.y, ( shouldSlide ? Is.Negative : Is.Positive ) );
80+
Assert.That( box.LinearVelocity.magnitude, ( shouldSlide ? Is.GreaterThan( 1.0f ) : Is.Zero.Within( 1e-5f ) ) );
81+
}
82+
83+
private void AddOriented( GameObject refObject, ShapeMaterial otherMaterial, FrictionModel.PrimaryDirection direction )
84+
{
85+
var cm = ContactMaterial.CreateInstance<ContactMaterial>();
86+
cm.Material1 = m_groundMat;
87+
cm.Material2 = otherMaterial;
88+
89+
cm.FrictionModel = m_friction;
90+
91+
cm.FrictionCoefficients = new Vector2( 0, 1 );
92+
ContactMaterialManager.Instance.GetInitialized();
93+
ContactMaterialManager.Instance.Add( new ContactMaterialEntry()
94+
{
95+
ContactMaterial = cm,
96+
IsOriented = true,
97+
PrimaryDirection = direction,
98+
ReferenceObject = refObject
99+
} );
100+
}
101+
102+
[UnityTest]
103+
public IEnumerator TestMainAxisRB()
104+
{
105+
var (mat, rb, _, _) = CreateSlidingBox();
106+
107+
AddOriented( rb.gameObject, mat, FrictionModel.PrimaryDirection.X );
108+
109+
yield return TestUtils.SimulateSeconds( 3 );
110+
111+
TestSlides( rb, true );
112+
}
113+
114+
[UnityTest]
115+
public IEnumerator TestOffAxisRB()
116+
{
117+
var (mat, rb, _, _) = CreateSlidingBox();
118+
119+
AddOriented( rb.gameObject, mat, FrictionModel.PrimaryDirection.Z );
120+
121+
yield return TestUtils.SimulateSeconds( 3 );
122+
123+
TestSlides( rb, false );
124+
}
125+
126+
[UnityTest]
127+
public IEnumerator TestMainAxisShape()
128+
{
129+
var (mat, rb, shape, _) = CreateSlidingBox();
130+
131+
AddOriented( shape.gameObject, mat, FrictionModel.PrimaryDirection.X );
132+
133+
yield return TestUtils.SimulateSeconds( 3 );
134+
135+
TestSlides( rb, true );
136+
}
137+
138+
[UnityTest]
139+
public IEnumerator TestOffAxisShape()
140+
{
141+
var (mat, rb, shape, _) = CreateSlidingBox();
142+
143+
AddOriented( shape.gameObject, mat, FrictionModel.PrimaryDirection.Z );
144+
145+
yield return TestUtils.SimulateSeconds( 3 );
146+
147+
TestSlides( rb, false );
148+
}
149+
150+
[UnityTest]
151+
public IEnumerator TestMainAxisObserverFrame()
152+
{
153+
var (mat, rb, _, oFrame) = CreateSlidingBox();
154+
155+
AddOriented( oFrame.gameObject, mat, FrictionModel.PrimaryDirection.X );
156+
157+
yield return TestUtils.SimulateSeconds( 3 );
158+
159+
TestSlides( rb, true );
160+
}
161+
162+
[UnityTest]
163+
public IEnumerator TestOffAxisObserverFrame()
164+
{
165+
var (mat, rb, _, oFrame) = CreateSlidingBox();
166+
167+
AddOriented( oFrame.gameObject, mat, FrictionModel.PrimaryDirection.Z );
168+
169+
yield return TestUtils.SimulateSeconds( 3 );
170+
171+
TestSlides( rb, false );
172+
}
173+
}
174+
}

Tests/Runtime/OrientedFrictionTests.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)