Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
## [1.0.11] - 2023-06-19

### Changed

* Prevent spawning `ParallelSolverJobs` unnecessarily ahead of time, which was leading to a potentially high overhead in time consumption. Instead, schedule the right number of jobs for the dispatch pair phases created by the scheduler to prevent scheduling and processing overheads. This leads to speed-ups in the time consumed by jobs in the `SolveAndIntegrateSystem` specifically in cases with low to medium joint and contact counts.
* The `PhysicsColliderKeyEntityPair` buffer is now added only when needed and its internal capacity of the buffer is set to zero, ensuring its content always lives outside of the chunk. This way, we don't unnecessarily increase the rigid body sizes in chunks, allowing for a larger number of rigid bodies in a single chunk, which improves performance.

### Fixed

* Fixed regression in accessibility of `PhysicsShapeAuthoring` API. The functions `GetCapsuleProperties()` and `SetCapsule()` were made internal by accident during the move of the custom physics authoring components from the package API to a package sample and are now public again.
  • Loading branch information
Unity Technologies committed Jun 19, 2023
1 parent 01dd583 commit 4ea831e
Show file tree
Hide file tree
Showing 20 changed files with 432 additions and 235 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
# Changelog


## [1.0.11] - 2023-06-19

### Changed

* Prevent spawning `ParallelSolverJobs` unnecessarily ahead of time, which was leading to a potentially high overhead in time consumption. Instead, schedule the right number of jobs for the dispatch pair phases created by the scheduler to prevent scheduling and processing overheads. This leads to speed-ups in the time consumed by jobs in the `SolveAndIntegrateSystem` specifically in cases with low to medium joint and contact counts.
* The `PhysicsColliderKeyEntityPair` buffer is now added only when needed and its internal capacity of the buffer is set to zero, ensuring its content always lives outside of the chunk. This way, we don't unnecessarily increase the rigid body sizes in chunks, allowing for a larger number of rigid bodies in a single chunk, which improves performance.

### Fixed

* Fixed regression in accessibility of `PhysicsShapeAuthoring` API. The functions `GetCapsuleProperties()` and `SetCapsule()` were made internal by accident during the move of the custom physics authoring components from the package API to a package sample and are now public again.


## [1.0.10] - 2023-05-23

### Added
Expand Down
2 changes: 1 addition & 1 deletion Documentation~/concepts-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The current set of data components for a rigid body is as follows:
| Component | Description |
|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `PhysicsCollider` | The shape of the body. Needed for any bodies that can collide. |
| `PhysicsColliderKeyEntityPair` | A buffer element used to associate an original Entity with a collider key in a Compound Collider. |
| `PhysicsColliderKeyEntityPair` | A buffer element used to associate an original Entity with a collider key in a Compound Collider. Only present when the rigid body contains a compound collider. |
| `PhysicsCustomTags` | Custom flags applied to the body. They can be used for certain collision event applications. Assumed to be zero if not present, optional component. |
| `PhysicsDamping` | The amount of damping to apply to the motion of a dynamic body. Assumed to be zero if not present. |
| `PhysicsGravityFactor` | The scalar for how much gravity should affect a dynamic body. Assumed to be 1 if not present, optional component. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ bool rebuildOrientation
height = props.Height;
}

internal CapsuleGeometryAuthoring GetCapsuleProperties()
public CapsuleGeometryAuthoring GetCapsuleProperties()
{
GetCylindricalProperties(
m_Capsule, out var center, out var height, out var radius, out var orientationEuler, m_ShapeType != ShapeType.Capsule
Expand Down Expand Up @@ -610,7 +610,7 @@ internal void SetBox(BoxGeometry geometry, EulerAngles orientation)
SyncSphereProperties();
}

internal void SetCapsule(CapsuleGeometryAuthoring geometry)
public void SetCapsule(CapsuleGeometryAuthoring geometry)
{
m_ShapeType = ShapeType.Capsule;
m_PrimitiveCenter = geometry.Center;
Expand Down
63 changes: 42 additions & 21 deletions Tests/EditModeTests/Authoring/BaseHierarchyConversionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ public void TearDown()
}

protected void TestConvertedData<T>(Action<T> checkValue) where T : unmanaged, IComponentData =>
TestConvertedData((Action<NativeArray<T>>)(components => { checkValue(components[0]); }), 1);
TestConvertedData<T>((world, entities, components) => { checkValue(components[0]); }, 1);

protected void TestConvertedData<T>(Action<NativeArray<T>> checkValue, int assumeCount) where T : unmanaged, IComponentData =>
TestConvertedData<T>((world, entities, components) => { checkValue(components); }, assumeCount);

public static Entity ConvertBakeGameObject(GameObject go, World world, BlobAssetStore blobAssetStore)
{
Expand Down Expand Up @@ -123,7 +126,7 @@ public static Entity ConvertBakeGameObject(GameObject go, World world, BlobAsset
#endif
}

protected void TestConvertedData<T>(Action<NativeArray<T>> checkValues, int assumeCount) where T : unmanaged, IComponentData
protected void TestConvertedData<T>(Action<World, NativeArray<Entity>, NativeArray<T>> checkValues, int assumeCount) where T : unmanaged, IComponentData
{
var world = new World("Test world");

Expand All @@ -133,14 +136,11 @@ protected void TestConvertedData<T>(Action<NativeArray<T>> checkValues, int assu
{
ConvertBakeGameObject(Root, world, blobAssetStore);

using (var group = world.EntityManager.CreateEntityQuery(typeof(T)))
{
using (var components = group.ToComponentDataArray<T>(Allocator.Persistent))
{
Assume.That(components, Has.Length.EqualTo(assumeCount));
checkValues(components);
}
}
using var group = world.EntityManager.CreateEntityQuery(typeof(T));
using var components = group.ToComponentDataArray<T>(Allocator.Temp);
using var entities = group.ToEntityArray(Allocator.Temp);
Assume.That(components, Has.Length.EqualTo(assumeCount));
checkValues(world, entities, components);
}
}
finally
Expand All @@ -149,15 +149,36 @@ protected void TestConvertedData<T>(Action<NativeArray<T>> checkValues, int assu
}
}

protected void TestConvertedSharedData<T, S>(S sharedComponent)
where T : unmanaged, IComponentData
where S : unmanaged, ISharedComponentData =>
TestConvertedSharedData<T, S>((world, entities, components) => {}, 1, sharedComponent);

protected void TestConvertedSharedData<T, S>(Action<T> checkValue, S sharedComponent)
where T : unmanaged, IComponentData
where S : unmanaged, ISharedComponentData =>
TestConvertedSharedData((Action<NativeArray<T>>)(components =>
TestConvertedSharedData<T, S>((world, entities, components) =>
{
checkValue?.Invoke(components[0]);
}), 1, sharedComponent);
}, 1, sharedComponent);

protected void TestConvertedSharedData<T, S>(Action<NativeArray<T>> checkValues, int assumeCount, S sharedComponent)
protected void TestConvertedSharedData<T, S>(Action<World, Entity, T> checkValue, S sharedComponent)
where T : unmanaged, IComponentData
where S : unmanaged, ISharedComponentData =>
TestConvertedSharedData<T, S>((world, entities, components) =>
{
checkValue?.Invoke(world, entities[0], components[0]);
}, 1, sharedComponent);

protected void TestConvertedSharedData<T, S>(Action<NativeArray<T>> checkValue, int assumeCount, S sharedComponent)
where T : unmanaged, IComponentData
where S : unmanaged, ISharedComponentData =>
TestConvertedSharedData<T, S>((world, entities, components) =>
{
checkValue?.Invoke(components);
}, assumeCount, sharedComponent);

protected void TestConvertedSharedData<T, S>(Action<World, NativeArray<Entity>, NativeArray<T>> checkValues, int assumeCount, S sharedComponent)
where T : unmanaged, IComponentData
where S : unmanaged, ISharedComponentData
{
Expand All @@ -172,11 +193,10 @@ protected void TestConvertedSharedData<T, S>(Action<NativeArray<T>> checkValues,
using (var group = world.EntityManager.CreateEntityQuery(new ComponentType[] { typeof(T), typeof(S) }))
{
group.AddSharedComponentFilter(sharedComponent);
using (var components = group.ToComponentDataArray<T>(Allocator.Persistent))
{
Assume.That(components, Has.Length.EqualTo(assumeCount));
checkValues(components);
}
using var components = group.ToComponentDataArray<T>(Allocator.Temp);
using var entities = group.ToEntityArray(Allocator.Temp);
Assume.That(components, Has.Length.EqualTo(assumeCount));
checkValues(world, entities, components);
}
}
}
Expand Down Expand Up @@ -236,9 +256,10 @@ protected void VerifyNoDataProduced<T>() where T : unmanaged, IComponentData
{
ConvertBakeGameObject(Root, world, blobAssetStore);

using (var group = world.EntityManager.CreateEntityQuery(typeof(T)))
using (var bodies = group.ToComponentDataArray<T>(Allocator.Persistent))
Assert.That(bodies.Length, Is.EqualTo(0), $"Conversion pipeline produced {typeof(T).Name}");
using var group = world.EntityManager.CreateEntityQuery(typeof(T));
using var components = group.ToComponentDataArray<T>(Allocator.Temp);

Assert.That(components.Length, Is.EqualTo(0), $"Conversion pipeline produced {typeof(T).Name}");
}
}
finally
Expand Down
65 changes: 56 additions & 9 deletions Tests/EditModeTests/Authoring/RigidbodyConversionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,59 @@ public void RigidbodyConversion_NoCollider()
VerifyNoDataProduced<PhysicsCollider>();
}

static readonly TestCaseData[] k_EntityBufferTestCases =
{
new TestCaseData(
new[] { typeof(Rigidbody), typeof(BoxCollider) }, // parent components
Array.Empty<Type>(), // child components
false, // expect entity buffer
0 // expected buffer size
).SetName("RigidbodyConversion_ExpectEntityBufferOrNot_WithSingleCollider"),
new TestCaseData(
new[] { typeof(Rigidbody) },
new[] { typeof(BoxCollider) },
true,
1
).SetName("RigidbodyConversion_ExpectEntityBufferOrNot_WithSingleColliderInDescendent"),
new TestCaseData(
new[] { typeof(Rigidbody), typeof(BoxCollider), typeof(BoxCollider) },
Array.Empty<Type>(),
true,
2
).SetName("RigidbodyConversion_ExpectEntityBufferOrNot_WithMultipleColliders"),
new TestCaseData(
new[] { typeof(Rigidbody) },
new[] { typeof(BoxCollider), typeof(BoxCollider) },
true,
2
).SetName("RigidbodyConversion_ExpectEntityBufferOrNot_WithMultipleCollidersInDescendent"),
new TestCaseData(
new[] { typeof(Rigidbody), typeof(BoxCollider) },
new[] { typeof(BoxCollider), typeof(BoxCollider) },
true,
3
).SetName("RigidbodyConversion_ExpectEntityBufferOrNot_WithMultipleCollidersInHierarchy")
};

// Make sure there is a PhysicsColliderKeyEntityPair buffer in a rigid body only when needed, and it has the right size if present.
[TestCaseSource(nameof(k_EntityBufferTestCases))]
public void RigidbodyConversion_ExpectEntityBuffer(Type[] parentComponentTypes, Type[] childComponentTypes, bool expectEntityBuffer, int expectedBufferSize)
{
CreateHierarchy(parentComponentTypes, childComponentTypes, Array.Empty<Type>());
TestConvertedData<PhysicsCollider>((w, e, c) =>
{
Assert.That(e.Length, Is.EqualTo(1));
var entity = e[0];
var hasBuffer = w.EntityManager.HasBuffer<PhysicsColliderKeyEntityPair>(entity);
Assert.AreEqual(expectEntityBuffer, hasBuffer);
if (hasBuffer)
{
var buffer = w.EntityManager.GetBuffer<PhysicsColliderKeyEntityPair>(entity);
Assert.That(buffer.Length, Is.EqualTo(expectedBufferSize));
}
}, 1);
}

// Make sure we get the correct mass (infinite) with kinematic bodies
[Test]
public void RigidbodyConversion_KinematicCausesInfiniteMass()
Expand Down Expand Up @@ -110,9 +163,7 @@ public void RigidbodyConversion_DefaultPhysicsWorldIndex()
CreateHierarchy(new[] { typeof(Rigidbody) }, Array.Empty<Type>(), Array.Empty<Type>());

// Note: testing for presence of PhysicsVelocity component which is expected for a default rigid body
TestConvertedSharedData<PhysicsVelocity, PhysicsWorldIndex>(
null,
k_DefaultWorldIndex);
TestConvertedSharedData<PhysicsVelocity, PhysicsWorldIndex>(k_DefaultWorldIndex);
}

// Make sure we get the default physics world index when using a default PhysicsWorldIndexAuthoring component
Expand All @@ -122,9 +173,7 @@ public void RigidbodyConversion_WithPhysicsWorldIndexAuthoring_DefaultPhysicsWor
CreateHierarchy(new[] { typeof(Rigidbody), typeof(PhysicsWorldIndexAuthoring) }, Array.Empty<Type>(), Array.Empty<Type>());

// Note: testing for presence of PhysicsVelocity component which is expected for a default rigid body
TestConvertedSharedData<PhysicsVelocity, PhysicsWorldIndex>(
null,
k_DefaultWorldIndex);
TestConvertedSharedData<PhysicsVelocity, PhysicsWorldIndex>(k_DefaultWorldIndex);
}

// Make sure we get the correct physics world index when using the PhysicsWorldIndexAuthoring component
Expand All @@ -135,9 +184,7 @@ public void RigidbodyConversion_WithPhysicsWorldIndexAuthoring_NonDefaultPhysics
Root.GetComponent<PhysicsWorldIndexAuthoring>().WorldIndex = 3;

// Note: testing for presence of PhysicsVelocity component which is expected for a default rigid body
TestConvertedSharedData<PhysicsVelocity, PhysicsWorldIndex>(
null,
new PhysicsWorldIndex(3));
TestConvertedSharedData<PhysicsVelocity, PhysicsWorldIndex>(new PhysicsWorldIndex(3));
}

// Make sure there is no leftover baking data when using the PhysicsWorldIndexAuthoring component
Expand Down
Loading

0 comments on commit 4ea831e

Please sign in to comment.