/**
         * Main Update Method
         */
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            int numOFProjectiles = _data.Length;
            int batchSize        = 500;

            var raycastCommands = new NativeArray <RaycastCommand>(numOFProjectiles, Allocator.TempJob);
            var raycastHits     = new NativeArray <RaycastHit>(numOFProjectiles, Allocator.TempJob);

            var raycastCommandsJob = new PrepareRaycastCommands
            {
                DeltaTime   = Time.deltaTime,
                Commands    = raycastCommands,
                Projectiles = _data.Projectile
            };

            // SCHEDULE Job for creating raycast commands
            JobHandle raycastDependency =
                raycastCommandsJob.Schedule(numOFProjectiles, batchSize);

            // SCHEDULE Raycast job
            JobHandle raycastJobHandle =
                RaycastCommand.ScheduleBatch(raycastCommands, raycastHits, batchSize, raycastDependency);

            // Update Projectiles with new state
            var projectileStateUpdate = new ProjectileHitUpdateJob
            {
                Projectiles   = _data.Projectile,
                RaycastHits   = raycastHits,
                Entities      = _data.Entities,
                CommandBuffer = _jobBarrier.CreateCommandBuffer().ToConcurrent()
            };

            JobHandle stateUpdateJob = projectileStateUpdate.Schedule(numOFProjectiles, batchSize, raycastJobHandle);

            stateUpdateJob.Complete();

            raycastCommands.Dispose();
            raycastHits.Dispose();

            return(stateUpdateJob);
        }
    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);
            }
        }
    }
Esempio n. 3
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();
    }
Esempio n. 4
0
        public void Bake(int raySamples, List <Renderer> renderers, Action <SDFVolume, float[], float, object> bakeComplete, object passthrough = null)
        {
            onBakeComplete = bakeComplete;

            int progressInterval = _settings.CellCount / 4;
            int progress         = 0;

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            vec3  halfVoxel   = _settings.HalfVoxel;
            float maxDistance = 0f;

            //adjusted to best timings from testing but it could vary by CPU
            int calcRayLengthBatchCount = 32;

            calcRayLengthBatchCount = Mathf.Clamp(calcRayLengthBatchCount, 1, raySamples);
            int raycastBatchCount = 8;

            raycastBatchCount = Mathf.Clamp(raycastBatchCount, 1, raySamples);
            int prepareRaysBatchCount = 64;

            prepareRaysBatchCount = Mathf.Clamp(prepareRaysBatchCount, 1, raySamples);
            int compareBatchCount = 128;

            //for raycast method front facing geo and flipped backfacing geo is required
            List <Collider> geoFront = new List <Collider>();
            List <Collider> geoBack  = new List <Collider>();

            CreateColliders(ref renderers, ref geoFront, ref geoBack);

            //prepare data
            NativeArray <float>       distances  = new NativeArray <float>(_settings.CellCount, Allocator.TempJob);
            NativeArray <CellResults> allResults = new NativeArray <CellResults>(_settings.CellCount, Allocator.TempJob);

            //constant for all cells
            NativeArray <vec3> sphereSamples = new NativeArray <vec3>(raySamples, Allocator.TempJob);
            //NativeArray<vec3> randomDirections = new NativeArray<vec3>(raySamples, Allocator.TempJob);
            NativeArray <vec4> volumePlanes = new NativeArray <vec4>(6, Allocator.TempJob);

            GetUniformPointsOnSphereNormalized(ref sphereSamples);
            //GetRandomDirections( _halfVoxel*settings.JitterScale, settings.JitterSeed, ref randomDirections);

            vec3 aabbMin = BoundsWorldAABB.min;
            vec3 aabbMax = BoundsWorldAABB.max;
            //the max ray length, used to normalize all resulting distances
            //so they are treated as 0 to 1 within a volume
            float aabbMagnitude = BoundsWorldAABB.size.magnitude;

            Plane pl = new Plane(Vector3.right, aabbMin);
            Plane pr = new Plane(Vector3.left, aabbMax);
            Plane pd = new Plane(Vector3.up, aabbMin);
            Plane pu = new Plane(Vector3.down, aabbMax);
            Plane pb = new Plane(Vector3.forward, aabbMin);
            Plane pf = new Plane(Vector3.back, aabbMax);

            volumePlanes[0] = new vec4(pl.normal.x, pl.normal.y, pl.normal.z, pl.distance);
            volumePlanes[1] = new vec4(pr.normal.x, pr.normal.y, pr.normal.z, pr.distance);
            volumePlanes[2] = new vec4(pd.normal.x, pd.normal.y, pd.normal.z, pd.distance);
            volumePlanes[3] = new vec4(pu.normal.x, pu.normal.y, pu.normal.z, pu.distance);
            volumePlanes[4] = new vec4(pb.normal.x, pb.normal.y, pb.normal.z, pb.distance);
            volumePlanes[5] = new vec4(pf.normal.x, pf.normal.y, pf.normal.z, pf.distance);

            //iterate each cell performing raycasted samples
            for (int i = 0; i < _settings.CellCount; i++)
            {
#if UNITY_EDITOR
                if (i % progressInterval == 0)
                {
                    EditorUtility.DisplayProgressBar(strProgressTitle, strProgress, i / (float)_settings.CellCount);
                }
#endif

                vec3 positionWS    = _settings.ToPositionWS(i, LocalToWorldNoScale);
                vec3 centerVoxelWS = positionWS + halfVoxel;

                NativeArray <float>          rayLengths       = new NativeArray <float>(raySamples, Allocator.TempJob);
                NativeArray <RaycastCommand> allRaycastsFront = new NativeArray <RaycastCommand>(raySamples, Allocator.TempJob);
                NativeArray <RaycastCommand> allRaycastsBack  = new NativeArray <RaycastCommand>(raySamples, Allocator.TempJob);
                NativeArray <RaycastHit>     frontHits        = new NativeArray <RaycastHit>(raySamples, Allocator.TempJob);
                NativeArray <RaycastHit>     backHits         = new NativeArray <RaycastHit>(raySamples, Allocator.TempJob);

                //calculate the ray lengths, just so rays are clipped within the volume when raycasting
                CalculateRayLengths calcRayLengths = new CalculateRayLengths
                {
                    Samples      = sphereSamples,
                    VolumePlanes = volumePlanes,
                    RayLengths   = rayLengths,
                    RayLength    = aabbMagnitude,
                    RayOrigin    = centerVoxelWS
                };
                JobHandle rayLengthHandle = calcRayLengths.Schedule(raySamples, calcRayLengthBatchCount);

                //prepare raycasts front
                PrepareRaycastCommands frontPrc = new PrepareRaycastCommands
                {
                    Samples    = sphereSamples,
                    RayLengths = rayLengths,
                    LayerMask  = LAYER_MASK_FRONT,
                    Raycasts   = allRaycastsFront,
                    RayOrigin  = centerVoxelWS,
                };
                //prepare raycasts back
                PrepareRaycastCommands backPrc = new PrepareRaycastCommands
                {
                    Samples    = sphereSamples,
                    RayLengths = rayLengths,
                    LayerMask  = LAYER_MASK_BACK,
                    Raycasts   = allRaycastsBack,
                    RayOrigin  = centerVoxelWS,
                };

                //schedule front raycasts
                JobHandle prepareFrontHandle = frontPrc.Schedule(
                    raySamples, prepareRaysBatchCount, rayLengthHandle);
                JobHandle scheduleFrontHandle = RaycastCommand.ScheduleBatch(
                    allRaycastsFront, frontHits, raycastBatchCount, prepareFrontHandle);

                //schedule back raycasts
                JobHandle prepareBackHandle = backPrc.Schedule(
                    raySamples, prepareRaysBatchCount, rayLengthHandle);
                JobHandle scheduleBackHandle = RaycastCommand.ScheduleBatch(
                    allRaycastsBack, backHits, raycastBatchCount, prepareBackHandle);

                //combine handles
                JobHandle frontBackHandle = JobHandle.CombineDependencies(scheduleFrontHandle, scheduleBackHandle);

                //process results and put into current cell index
                ProcessHits processHits = new ProcessHits
                {
                    FrontHits = frontHits,
                    BackHits  = backHits,
                    Results   = allResults.Slice(i, 1),
                };

                JobHandle cellHandle = processHits.Schedule(frontBackHandle);
                cellHandle.Complete();

                rayLengths.Dispose();
                allRaycastsFront.Dispose();
                allRaycastsBack.Dispose();
                frontHits.Dispose();
                backHits.Dispose();
            } //for each cell

            //final distances
            CompareDistances compareDistances = new CompareDistances
            {
                Distances = distances,
                Results   = allResults
            };

            JobHandle compareDistancesHandle = compareDistances.Schedule(_settings.CellCount, compareBatchCount);
            compareDistancesHandle.Complete();

            stopwatch.Stop();
            Debug.Log("SDF bake completed in " + stopwatch.Elapsed.ToString("mm\\:ss\\.ff"));
#if UNITY_EDITOR
            EditorUtility.ClearProgressBar();
#endif
            float[] distancesOut = new float[_settings.CellCount];
            distances.CopyTo(distancesOut);

            //cleanup all the temp arrays
            distances.Dispose();
            allResults.Dispose();
            sphereSamples.Dispose();
            //randomDirections.Dispose();
            volumePlanes.Dispose();

            foreach (var c in geoFront)
            {
                Object.DestroyImmediate(c.gameObject);
            }
            foreach (var c in geoBack)
            {
                Object.DestroyImmediate(c.gameObject);
            }

            //NOTE do not use max distance, instead use aabbMagnitude so distance fields are interchangeable
            bakeComplete?.Invoke(this, distancesOut, aabbMagnitude, passthrough);
        }
Esempio n. 5
0
        public void Generate()
        {
            if (mesh == null)
            {
                mesh = new Mesh();
            }

            if (useSeed)
            {
                Random.InitState(randomSeed);
            }

            Vector3[] TEMPpositions = GeneratePositions();
            amount = TEMPpositions.Length;

            NativeArray <Vector3> rayPositions = new NativeArray <Vector3>(amount, Allocator.TempJob);
            NativeArray <Vector3> vertices     = new NativeArray <Vector3>(amount, Allocator.TempJob);
            NativeArray <int>     indices      = new NativeArray <int>(amount, Allocator.TempJob);
            NativeArray <Vector3> normals      = new NativeArray <Vector3>(amount, Allocator.TempJob);
            NativeArray <Vector4> tangents     = new NativeArray <Vector4>(amount, Allocator.TempJob);
            NativeArray <Color>   colors       = new NativeArray <Color>(amount, Allocator.TempJob);

            //Copy generated positions
            rayPositions.CopyFrom(TEMPpositions);

            for (int i = 0; i < amount; i++)
            {
                colors[i] = new Color(
                    Random.Range(grassHeightRange.x, grassHeightRange.y), //Height
                    1,                                                    //This is used by the wind, but could be saved and used before the wind is applied
                    Random.Range(grassWidthRange.x, grassWidthRange.y));  //Width;
            }

            var raycastCommands = new NativeArray <RaycastCommand>(amount, Allocator.TempJob);
            NativeArray <RaycastHit> raycastHits = new NativeArray <RaycastHit>(amount, Allocator.TempJob);

            var setupRaycastsJob = new PrepareRaycastCommands()
            {
                Raycasts  = raycastCommands,
                Positions = rayPositions
            };

            var setupDependency = setupRaycastsJob.Schedule(amount, 32, default(JobHandle));

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

            raycastDependency.Complete();

            var setupMeshDataJob = new PrepareMeshData()
            {
                Vertices    = vertices,
                Indices     = indices,
                Normals     = normals,
                Tangents    = tangents,
                Colors      = colors,
                hit         = raycastHits,
                ObjPosition = transform.position
            };

            var setupMeshDependency = setupMeshDataJob.Schedule(amount, 32, raycastDependency);

            setupMeshDependency.Complete();

            mesh.Clear();
#if UNITY_2019_3_OR_NEWER
            mesh.SetVertices(vertices);
            mesh.SetIndices(indices, MeshTopology.Points, 0);
            mesh.SetNormals(normals);
            mesh.SetTangents(tangents);
            mesh.SetColors(colors);
#else
            mesh.vertices = vertices.ToArray();
            mesh.SetIndices(indices.ToArray(), MeshTopology.Points, 0);
            mesh.normals  = normals.ToArray();
            mesh.tangents = tangents.ToArray();
            mesh.colors   = colors.ToArray();
#endif

            meshFilter.sharedMesh = mesh;

            raycastCommands.Dispose();
            raycastHits.Dispose();
            rayPositions.Dispose();
            vertices.Dispose();
            indices.Dispose();
            normals.Dispose();
            tangents.Dispose();
            colors.Dispose();
        }