void Update()
    {
        // only do an update if the data has been initialized
        if (!positions.IsCreated)
        {
            return;
        }

        var deltaTime = Time.deltaTime;

        // FORCE ACCUMILATION

        // First off lets apply gravity to all the object in our scene that arnt currently asleep
        var gravityJob = new GravityJob()
        {
            DeltaTime  = deltaTime,
            Gravity    = gravity,
            Velocities = velocities,
            Sleeping   = sleeping
        };
        var gravityDependency = gravityJob.Schedule(objectCount, 32);

        // TODO accumilate other forces here! gravity is just the simplest force to apply to our objects,
        // but theres no limit on the kind of forces we can simulate. We could add friction, air resistnace,
        // constant acceleration, joints and constrainsts, boyancy.. anything we can think of that can effect
        // the velocity of an object can have its own job scheduled here.

        // INTERGRATION AND COLLISION

        // Create temporary arrays for the raycast info. Lets use the TempJob allocator,
        // this means we have to dispose them when the job has finished - its short lived data
        var raycastCommands = new NativeArray <RaycastCommand>(objectCount, Allocator.TempJob);
        var raycastHits     = new NativeArray <RaycastHit>(objectCount, Allocator.TempJob);

        // Lets schedule jobs to do a collision raycast for each object. One job Prepare    s all the raycast commands,
        // the second actually does the raycasts.
        var setupRaycastsJob = new PrepareRaycastCommands()
        {
            DeltaTime  = deltaTime,
            Positions  = positions,
            Raycasts   = raycastCommands,
            Velocities = velocities
        };

        var setupDependency = setupRaycastsJob.Schedule(objectCount, 32, gravityDependency);

        // BUG| WORKAROUND - Checked against Unity 2018.1b8
        // BUG| RaycastCommand seems to be ignoring any passed in dependencies. We have to explicity wait here.
        // BUG| This has been reported to Unity and fixed. When the fix appears in public betas this can be removed.
        setupDependency.Complete();
        // BUG| END WORKAROUND

        var raycastDependency = RaycastCommand.ScheduleBatch(raycastCommands, raycastHits, 32, setupDependency);

        // Now we know if there is a collision along our velocity vector, its time to integrate the velocity into
        // our objects for the current timeset.
        var integrateJob = new IntegratePhysics()
        {
            DeltaTime  = deltaTime,
            Positions  = positions,
            Velocities = velocities,
            Sleeping   = sleeping,
            Hits       = raycastHits
        };
        var integrateDependency = integrateJob.Schedule(objectCount, 32, raycastDependency);

        // finally, respond to any collisions that happened in the lsat update step.
        var collisionResponeJob = new CalculateCollisionResponse()
        {
            Hits       = raycastHits,
            Velocities = velocities,
            Sleeping   = sleeping
        };
        var collisionDependency = collisionResponeJob.Schedule(objectCount, 32, integrateDependency);

        // Now the physics is done, we need to create a drawing matrix for every object. This simple demo dosnt
        // implment roation, so only the translation values in the matrix reallllly matter.
        var renderMatrixJob = new CalculateDrawMatricies()
        {
            positions      = positions,
            renderMatrices = renderMatrices
        };
        var matrixJob = renderMatrixJob.Schedule(objectCount, 32, collisionDependency);

        // All the jobs we want to execute have been scheduled! By calling .Complete() on the last job in the
        // chain, Unity makes the main thread help out with scheduled jobs untill they are all complete.
        // then we can move on and use the data caluclated in the jobs safely, without worry about data being changed
        // by other threads as we try to use it - we *know* all the work is done
        matrixJob.Complete();

        // make sure we dispose of the temporary NativeArrays we used for raycasting
        raycastCommands.Dispose();
        raycastHits.Dispose();

        // Well, all the updating is done! lets actually issue a draw!
        Graphics.DrawMeshInstanced(mesh, 0, material, renderMatrices.ToArray());

        // DEBUG 1 - draw red lines showing object velocity
        //for (int i = 0; i < objectCount; i++)
        //{
        ///   Debug.DrawLine(positions[i], positions[i] + velocities[i], Color.red, 0.016f, true);
        //}

        // DEBUG 2 - draw a trail for a few objects, really helps to visualize the bounce!
        //var duration = 01f;
        //Debug.DrawLine(positions[0], positions[0] + velocities[0], Color.red, duration, true);
        //Debug.DrawLine(positions[200], positions[200] + velocities[200], Color.cyan, duration, true);
        //Debug.DrawLine(positions[400], positions[400] + velocities[400], Color.green, duration, true);
        //Debug.DrawLine(positions[600], positions[600] + velocities[600], Color.magenta, duration, true);
        //Debug.DrawLine(positions[800], positions[800] + velocities[800], Color.yellow, duration, true);
        //Debug.DrawLine(positions[1000], positions[1000] + velocities[1000], Color.blue, duration, true);
        //Debug.DrawLine(positions[100], positions[100] + velocities[100], Color.red, duration, true);
        //Debug.DrawLine(positions[300], positions[300] + velocities[300], Color.cyan, duration, true);
        //Debug.DrawLine(positions[500], positions[500] + velocities[500], Color.green, duration, true);
        //Debug.DrawLine(positions[700], positions[700] + velocities[700], Color.magenta, duration, true);
        //Debug.DrawLine(positions[900], positions[900] + velocities[900], Color.yellow, duration, true);

        // finally lets respawn any object that has been asleep and stable for a while
        // TODO as of Unity 2018.1b6, NativeArray is the only native collection type. When
        // NativeQueue is included in the beta this last task can be jobified!
        for (int i = 0; i < objectCount; i++)
        {
            if (sleeping[i] > 15)
            {
                Respawn(i);
            }
        }
    }
Example #2
0
    void Update()
    {
        // only do an update if the data has been initialized
        if (!positions.IsCreated)
        {
            return;
        }

        sampler.Begin();

        var deltaTime = Time.deltaTime;

        // FORCE ACCUMILATION

        // First off lets apply gravity to all the object in our scene that arnt currently asleep
        var gravityJob = new GravityJob()
        {
            DeltaTime  = deltaTime,
            Gravity    = gravity,
            Velocities = velocities,
            Sleeping   = sleepingTimer
        };
        var gravityDependency = gravityJob.Schedule(objectCount, 32);

        // TODO accumilate other forces here! gravity is just the simplest force to apply to our objects,
        // but theres no limit on the kind of forces we can simulate. We could add friction, air resistnace,
        // constant acceleration, joints and constrainsts, boyancy.. anything we can think of that can effect
        // the velocity of an object can have its own job scheduled here.

        // INTERGRATION AND COLLISION

        // Create temporary arrays for the raycast info. Lets use the TempJob allocator,
        // this means we have to dispose them when the job has finished - its short lived data
        var raycastCommands = new NativeArray <RaycastCommand>(objectCount, Allocator.TempJob);
        var raycastHits     = new NativeArray <RaycastHit>(objectCount, Allocator.TempJob);

        // Lets schedule jobs to do a collision raycast for each object. One job Prepare    s all the raycast commands,
        // the second actually does the raycasts.
        var setupRaycastsJob = new PrepareRaycastCommands()
        {
            DeltaTime  = deltaTime,
            Positions  = positions,
            Raycasts   = raycastCommands,
            Velocities = velocities
        };

        var setupDependency = setupRaycastsJob.Schedule(objectCount, 32, gravityDependency);

        var raycastDependency = RaycastCommand.ScheduleBatch(raycastCommands, raycastHits, 32, setupDependency);

        // Now we know if there is a collision along our velocity vector, its time to integrate the velocity into
        // our objects for the current timeset.
        var integrateJob = new IntegratePhysics()
        {
            DeltaTime  = deltaTime,
            Positions  = positions,
            Velocities = velocities,
            Sleeping   = sleepingTimer,
            Hits       = raycastHits
        };
        var integrateDependency = integrateJob.Schedule(objectCount, 32, raycastDependency);

        // finally, respond to any collisions that happened in the lsat update step.
        var collisionResponeJob = new CalculateCollisionResponse()
        {
            Hits       = raycastHits,
            Velocities = velocities,
            Sleeping   = sleepingTimer
        };
        var collisionDependency = collisionResponeJob.Schedule(objectCount, 32, integrateDependency);

        // Now the physics is done, we need to create a drawing matrix for every object. This simple demo dosnt
        // implment roation, so only the translation values in the matrix reallllly matter.
        var renderMatrixJob = new CalculateDrawMatricies()
        {
            positions      = positions,
            renderMatrices = renderMatrices
        };
        var matrixDependency = renderMatrixJob.Schedule(objectCount, 32, collisionDependency);

        // All the jobs we want to execute have been scheduled! By calling .Complete() on the last job in the
        // chain, Unity makes the main thread help out with scheduled jobs untill they are all complete.
        // then we can move on and use the data caluclated in the jobs safely, without worry about data being changed
        // by other threads as we try to use it - we *know* all the work is done
        matrixDependency.Complete();

        // make sure we dispose of the temporary NativeArrays we used for raycasting
        raycastCommands.Dispose();
        raycastHits.Dispose();

        // lets schedule a job to figure out which objects are sleeping - this can run in the background whilst
        // we dispach the drawing commands for this frame.
        var sleepJob = new FindSleepingObjects()
        {
            Sleeping   = sleepingTimer,
            SleepQueue = asleep.AsParallelWriter()
        };
        var sleepDependancy = sleepJob.Schedule(objectCount, 32, matrixDependency);

        //  lets actually issue a draw!
        renderMatrices.CopyTo(renderMatrixArray); // copy to a preallocated array, we would get garbage from ToArray()
        Graphics.DrawMeshInstanced(mesh, 0, material, renderMatrixArray);

        // DEBUG 1 - draw red lines showing object velocity
        //for (int i = 0; i < objectCount; i++)
        //{
        ///   Debug.DrawLine(positions[i], positions[i] + velocities[i], Color.red, 0.016f, true);
        //}

        // DEBUG 2 - draw a trail for a few objects, really helps to visualize the bounce!
        //var duration = 01f;
        //Debug.DrawLine(positions[0], positions[0] + velocities[0], Color.red, duration, true);
        //Debug.DrawLine(positions[200], positions[200] + velocities[200], Color.cyan, duration, true);
        //Debug.DrawLine(positions[400], positions[400] + velocities[400], Color.green, duration, true);
        //Debug.DrawLine(positions[600], positions[600] + velocities[600], Color.magenta, duration, true);
        //Debug.DrawLine(positions[800], positions[800] + velocities[800], Color.yellow, duration, true);
        //Debug.DrawLine(positions[1000], positions[1000] + velocities[1000], Color.blue, duration, true);
        //Debug.DrawLine(positions[100], positions[100] + velocities[100], Color.red, duration, true);
        //Debug.DrawLine(positions[300], positions[300] + velocities[300], Color.cyan, duration, true);
        //Debug.DrawLine(positions[500], positions[500] + velocities[500], Color.green, duration, true);
        //Debug.DrawLine(positions[700], positions[700] + velocities[700], Color.magenta, duration, true);
        //Debug.DrawLine(positions[900], positions[900] + velocities[900], Color.yellow, duration, true);

        // finally lets respawn any object that has been found to be asleep (ie not moved for 15 frames)
        // were going to respawn that object so there is a constant flow
        sleepDependancy.Complete();
        for (int i = asleep.Count; i != 0; i--)
        {
            int index = asleep.Dequeue();
            Respawn(index);
        }



        sampler.End();
    }