Skip to content

Commit

Permalink
Updated ECSSamples
Browse files Browse the repository at this point in the history
  • Loading branch information
davidv-unity committed Feb 17, 2020
1 parent 71ee202 commit 5fbe871
Show file tree
Hide file tree
Showing 65 changed files with 205 additions and 309 deletions.
2 changes: 1 addition & 1 deletion ECSSamples/Assets/Advanced/BlobAsset/Mesh.prefab
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ MonoBehaviour:
m_GameObject: {fileID: 2206451551555309766}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3aa4602fe8083734482a395b2eefdb13, type: 3}
m_Script: {fileID: 11500000, guid: ada46fd23c7e67b47958492275dcf075, type: 3}
m_Name:
m_EditorClassIdentifier:
MeshScale: 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class MeshBBConversionSystem : GameObjectConversionSystem
protected override void OnCreate()
{
base.OnCreate();
GetEntityQuery(ComponentType.ReadOnly<MeshToBoundingBoxsAuthoring>());
GetEntityQuery(ComponentType.ReadOnly<MeshToBoundingBoxAuthoring>());
}

protected override void OnUpdate()
Expand All @@ -40,7 +40,7 @@ protected override void OnUpdate()
using (var context = new BlobAssetComputationContext<MeshBBFactorySettings, MeshBBBlobAsset>(BlobAssetStore, 128, Allocator.Temp))
{
// First step: for all changed GameObjects we compute the hash of their blob asset then get the asset or register its computation
Entities.ForEach((MeshToBoundingBoxsAuthoring auth) =>
Entities.ForEach((MeshToBoundingBoxAuthoring auth) =>
{
// Compute the blob asset hash based on Authoring properties
var hasMesh = auth.Mesh != null;
Expand All @@ -49,7 +49,7 @@ protected override void OnUpdate()

// Query the context to determine if we need to build the BlobAsset
processBlobAssets.Add(hash);
context.AssociateBlobAssetWithGameObject(hash, auth.gameObject);
context.AssociateBlobAssetWithUnityObject(hash, auth.gameObject);
if (context.NeedToComputeBlobAsset(hash))
{
Profiler.BeginSample("CopyVertices");
Expand Down Expand Up @@ -112,14 +112,15 @@ protected override void OnUpdate()

// Third step, create the ECS component with the associated blob asset
var index = 0;
Entities.ForEach((MeshToBoundingBoxsAuthoring auth) =>
Entities.ForEach((MeshToBoundingBoxAuthoring auth) =>
{
context.GetBlobAsset(processBlobAssets[index++], out var blob);

// Create the ECS component for the given GameObject
var entity = GetPrimaryEntity(auth);

DstEntityManager.AddComponentData(entity, new MeshBBComponent(blob));
DstEntityManager.AddComponentData(entity,new Translation{Value=auth.transform.position});
});

Profiler.EndSample();
Expand Down
1 change: 0 additions & 1 deletion ECSSamples/Assets/Advanced/BlobAsset/MeshBBRenderSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using UnityEngine;

[ExecuteAlways]
[UpdateInGroup(typeof(PresentationSystemGroup))]
public class MeshBBRenderSystem : ComponentSystem
{
protected override void OnUpdate()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using UnityEngine;
using UnityObject = UnityEngine.Object;

public class MeshToBoundingBoxsAuthoring : MonoBehaviour
public class MeshToBoundingBoxAuthoring : MonoBehaviour
{
public float MeshScale = 1;
public Mesh Mesh;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions ECSSamples/Assets/Advanced/BlobAsset/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# BlobAsset Conversion Sample

This sample demonstrates how to convert a information from a GameObject containing a Unity Authoring component to a BlobAsset using the `BlobAssetStore` and `BlobAssetComputationContext` types.

## What does it show

The sample contains a SubScene with 512 GameObjects. Each GameObject has a "MeshToBoundingBoxAuthoring" component that defines the information we want to store in a blob asset. (The GameObjects are stored as a nested prefab to save disk space).

After conversion, the `MeshBBRenderSystem` uses the blob asset to draw a bounding box for each of the 512 converted entities. (The renderer uses the Unity `Debug.Draw()` function, so the bounding box only appears in the Scene view.)

## Sample elements:

* **BlobAsset Scene** — a standard Unity Scene. It contains the Subscene.
* **Subscene** — contains the grid of GameObjects to convert.
* **Prefabs**:
* **M4** — a line made up of four Game objects.
* **M16** — a square made up of four M4 lines.
* **M64** — a cube made up of four M16 squares.
* **M512** — a cube made up of eight M64 cubes .
* **MeshToBoundingBoxsAuthoring** — defines the mesh and scale from which to compute the bounding boxes. Although each component in the sample starts out the same, you can assign different values to each component.
* **MeshBBComponent** —defines the structure of the blob asset used to store the computed bounding boxes and also the IComponentData struct used to assign a BlobAssetReference to an individual entity.
* **MeshBBConversionSystem** — Converts each unique combination of the values of Mesh and Scale encountered in the MeshToBoundingBoxsAuthoring components to a unique blob asset.
* **MeshBBRenderSystem** — draws the bounding boxes in the Unity Scene view.

## What it does

The `MeshToBoundingBoxAuthoring` authoring component has two properties:

1. **Mesh**: you assign a mesh from which the bounding box is computed
2. **Mesh Scale**: a scale that will be applied to the bounding box

The `MeshBBConversionSystem` converts this component to a BlobAsset that contains the bounding box info of the selected mesh scaled with the given value.

Each GameObject in the Subscene with the Authoring component is then converted to an ECS Entity that has a `MeshBBComponent` component data referencing the appropriate BlobAsset.

The BlobAsset is shared among entities if it has the same properties (Mesh & Mesh Scale).

The MeshBBRenderSystem processes all the `MeshBBComponent` instances and renders their bounding boxes in the editor using the Unity `Debug.Draw()` function . (Note that this sample does not render in the Game view or provide any runtime behavior in the Play mode.)

## Some insights

The `MeshBBConversionSystem` is a ` GameObjectConversionSystem` that does most of the interesting work in this sample. Conversion systems run in the Editor when you make a change to the relevant GameObjects and Components in a Subscene and also when you open or close a Subscene for editing.

`MeshBBConversionSystem` performs its conversion task in three steps:

1. For all changed `MeshToBoundingBoxAuthoring` authoring components, the system determines if a BlobAsset must be computed and pushes the values needed to compute the asset onto the `BlobAssetComputationContext` computation stack.
2. Schedules a job to compute the blob assets using the values created in step 1.
3. Creates a MeshBBComponent, assigns the corresponding `BlobAssetReference` for the blob asset created in step 2, and adds the component to the entity.

A `GameObjectConversionSystem` is a `ComponentSystem`, so it normally performs its work on the main thread. However, as this sample illustrates, you can use the C# Job System to move some parts of a conversion to worker threads. The `BlobAssetComputationContext` provides the `AddBlobAssetToCompute()` function to help optimize blob asset creation.

Using the `AddBlobAssetToCompute()` function, you can add a *settings* struct containing the values you need in order to create the blob asset to the *context*, associating a set of values with a hash. The hash value is used to determine whether a given authoring component represents a new blob asset or if it should share one already added for a different authoring component. You also use the hash to retrieve a reference to the blob asset after it is created.

3 changes: 3 additions & 0 deletions ECSSamples/Assets/Advanced/BlobAsset/README.md.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 4 additions & 6 deletions ECSSamples/Assets/Advanced/Boids/Scripts/BoidSchool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public struct BoidSchool : IComponentData
public int Count;
}

public class BoidSchoolSpawnSystem : JobComponentSystem
public class BoidSchoolSpawnSystem : SystemBase
{
[BurstCompile]
struct SetBoidLocalToWorld : IJobParallelFor
Expand All @@ -43,7 +43,7 @@ public void Execute(int i)
}
}

protected override JobHandle OnUpdate(JobHandle inputDeps)
protected override void OnUpdate()
{
Entities.WithStructuralChanges().ForEach((Entity entity, int entityInQueryIndex, in BoidSchool boidSchool, in LocalToWorld boidSchoolLocalToWorld) =>
{
Expand All @@ -61,13 +61,11 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)
Center = boidSchoolLocalToWorld.Position,
Radius = boidSchool.InitialRadius
};
inputDeps = setBoidLocalToWorldJob.Schedule(boidSchool.Count, 64, inputDeps);
inputDeps = boidEntities.Dispose(inputDeps);
Dependency = setBoidLocalToWorldJob.Schedule(boidSchool.Count, 64, Dependency);
Dependency = boidEntities.Dispose(Dependency);

EntityManager.DestroyEntity(entity);
}).Run();

return inputDeps;
}
}
}
48 changes: 23 additions & 25 deletions ECSSamples/Assets/Advanced/Boids/Scripts/BoidSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Samples.Boids
{
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateBefore(typeof(TransformSystemGroup))]
public class BoidSystem : JobComponentSystem
public class BoidSystem : SystemBase
{
EntityQuery m_BoidQuery;
EntityQuery m_TargetQuery;
Expand Down Expand Up @@ -101,7 +101,7 @@ public void ExecuteNext(int cellIndex, int index)
}
}

protected override JobHandle OnUpdate(JobHandle inputDeps)
protected override void OnUpdate()
{
var obstacleCount = m_ObstacleQuery.CalculateEntityCount();
var targetCount = m_TargetQuery.CalculateEntityCount();
Expand Down Expand Up @@ -157,7 +157,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)
{
cellAlignment[entityInQueryIndex] = localToWorld.Forward;
})
.Schedule(inputDeps);
.ScheduleParallel(Dependency);

var initialCellSeparationJobHandle = Entities
.WithSharedComponentFilter(settings)
Expand All @@ -166,7 +166,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)
{
cellSeparation[entityInQueryIndex] = localToWorld.Position;
})
.Schedule(inputDeps);
.ScheduleParallel(Dependency);

var copyTargetPositionsJobHandle = Entities
.WithName("CopyTargetPositionsJob")
Expand All @@ -176,7 +176,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)
{
copyTargetPositions[entityInQueryIndex] = localToWorld.Position;
})
.Schedule(inputDeps);
.ScheduleParallel(Dependency);

var copyObstaclePositionsJobHandle = Entities
.WithName("CopyObstaclePositionsJob")
Expand All @@ -186,7 +186,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)
{
copyObstaclePositions[entityInQueryIndex] = localToWorld.Position;
})
.Schedule(inputDeps);
.ScheduleParallel(Dependency);

// Populates a hash map, where each bucket contains the indices of all Boids whose positions quantize
// to the same value for a given cell radius so that the information can be randomly accessed by
Expand All @@ -203,14 +203,14 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)
var hash = (int)math.hash(new int3(math.floor(localToWorld.Position / settings.CellRadius)));
parallelHashMap.Add(hash, entityInQueryIndex);
})
.Schedule(inputDeps);
.ScheduleParallel(Dependency);

var initialCellCountJob = new MemsetNativeArray<int>
{
Source = cellCount,
Value = 1
};
var initialCellCountJobHandle = initialCellCountJob.Schedule(boidCount, 64, inputDeps);
var initialCellCountJobHandle = initialCellCountJob.Schedule(boidCount, 64, Dependency);

var initialCellBarrierJobHandle = JobHandle.CombineDependencies(initialCellAlignmentJobHandle, initialCellSeparationJobHandle, initialCellCountJobHandle);
var copyTargetObstacleBarrierJobHandle = JobHandle.CombineDependencies(copyTargetPositionsJobHandle, copyObstaclePositionsJobHandle);
Expand All @@ -228,7 +228,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)
targetPositions = copyTargetPositions,
obstaclePositions = copyObstaclePositions
};
var mergeCellsJobHandle = mergeCellsJob.Schedule(hashMap,64,mergeCellsBarrierJobHandle);
var mergeCellsJobHandle = mergeCellsJob.Schedule(hashMap, 64, mergeCellsBarrierJobHandle);

// This reads the previously calculated boid information for all the boids of each cell to update
// the `localToWorld` of each of the boids based on their newly calculated headings using
Expand Down Expand Up @@ -307,33 +307,31 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)
quaternion.LookRotationSafe(nextHeading, math.up()),
new float3(1.0f, 1.0f, 1.0f))
};
}).Schedule(mergeCellsJobHandle);
}).ScheduleParallel(mergeCellsJobHandle);

// Dispose allocated containers with dispose jobs.
inputDeps = steerJobHandle;
var disposeJobHandle = hashMap.Dispose(inputDeps);
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellIndices.Dispose(inputDeps));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellObstaclePositionIndex.Dispose(inputDeps));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellTargetPositionIndex.Dispose(inputDeps));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellCount.Dispose(inputDeps));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellObstacleDistance.Dispose(inputDeps));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellAlignment.Dispose(inputDeps));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellSeparation.Dispose(inputDeps));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, copyObstaclePositions.Dispose(inputDeps));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, copyTargetPositions.Dispose(inputDeps));
inputDeps = disposeJobHandle;
Dependency = steerJobHandle;
var disposeJobHandle = hashMap.Dispose(Dependency);
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellIndices.Dispose(Dependency));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellObstaclePositionIndex.Dispose(Dependency));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellTargetPositionIndex.Dispose(Dependency));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellCount.Dispose(Dependency));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellObstacleDistance.Dispose(Dependency));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellAlignment.Dispose(Dependency));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, cellSeparation.Dispose(Dependency));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, copyObstaclePositions.Dispose(Dependency));
disposeJobHandle = JobHandle.CombineDependencies( disposeJobHandle, copyTargetPositions.Dispose(Dependency));
Dependency = disposeJobHandle;

// We pass the job handle and add the dependency so that we keep the proper ordering between the jobs
// as the looping iterates. For our purposes of execution, this ordering isn't necessary; however, without
// the add dependency call here, the safety system will throw an error, because we're accessing multiple
// pieces of boid data and it would think there could possibly be a race condition.

m_BoidQuery.AddDependency(inputDeps);
m_BoidQuery.AddDependency(Dependency);
m_BoidQuery.ResetFilter();
}
m_UniqueTypes.Clear();

return inputDeps;
}

protected override void OnCreate()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

namespace Samples.Boids
{
public class SampledAnimationClipPlaybackSystem : JobComponentSystem
public class SampledAnimationClipPlaybackSystem : SystemBase
{
protected override JobHandle OnUpdate(JobHandle inputDeps)
protected override void OnUpdate()
{
var deltaTime = math.min(0.05f,Time.DeltaTime);

var transformJobHandle = Entities.ForEach((ref Translation translation, ref Rotation rotation, in SampledAnimationClip sampledAnimationClip) =>
Entities.ForEach((ref Translation translation, ref Rotation rotation, in SampledAnimationClip sampledAnimationClip) =>
{
var frameIndex = sampledAnimationClip.FrameIndex;
var timeOffset = sampledAnimationClip.TimeOffset;
Expand All @@ -25,9 +25,9 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)

translation.Value = math.lerp(prevTranslation, nextTranslation, timeOffset);
rotation.Value = math.slerp(prevRotation, nextRotation, timeOffset);
}).Schedule(inputDeps);
}).ScheduleParallel();

var clipJobHandle = Entities.ForEach((ref SampledAnimationClip sampledAnimationClip) =>
Entities.ForEach((ref SampledAnimationClip sampledAnimationClip) =>
{
var currentTime = sampledAnimationClip.CurrentTime + deltaTime;
var sampleRate = sampledAnimationClip.SampleRate;
Expand All @@ -48,9 +48,7 @@ protected override JobHandle OnUpdate(JobHandle inputDeps)
sampledAnimationClip.CurrentTime = currentTime;
sampledAnimationClip.FrameIndex = frameIndex;
sampledAnimationClip.TimeOffset = timeOffset;
}).Schedule(transformJobHandle);

return clipJobHandle;
}).ScheduleParallel();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static void CalculateShortestWalkableDistancesToTargetInner(NativeArray<int> tar
var cellCount = rowCount * rowCount;
var maxPathLength = 6*(cellCount + 1);

while (open.Count > 0)
while (open.Length > 0)
{
var cellIndex = open.Dequeue();
var cellPosition = CartesianGridOnCubeUtility.CellFaceCoordinates(cellIndex, rowCount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected override JobHandle OnUpdate(JobHandle lastJobHandle)
// Anything that's placed with CartesianGridDirection but does not have CubeFace assigned, needs to
// find appropriate CubeFace, add it and convert transform into local space of face.
Entities
.WithName("Find CubeFace")
.WithName("Find_CubeFace")
.WithStructuralChanges()
.WithNativeDisableUnsafePtrRestriction(faceLocalToWorld)
.WithNativeDisableUnsafePtrRestriction(faceWorldToLocal)
Expand Down
Loading

0 comments on commit 5fbe871

Please sign in to comment.