Beispiel #1
0
        unsafe static void SolveSingleJoint(JointData *jointData, int numIterations, float timestep,
                                            ref MotionVelocity velocityA, ref MotionVelocity velocityB, ref MotionData motionA, ref MotionData motionB, out NativeStream jacobiansOut)
        {
            var stepInput = new Solver.StepInput
            {
                IsLastIteration        = false,
                InvNumSolverIterations = 1.0f / numIterations,
                Timestep    = timestep,
                InvTimestep = timestep > 0.0f ? 1.0f / timestep : 0.0f
            };

            // Build jacobians
            jacobiansOut = new NativeStream(1, Allocator.Temp);
            {
                NativeStream.Writer jacobianWriter = jacobiansOut.AsWriter();
                jacobianWriter.BeginForEachIndex(0);
                Solver.BuildJointJacobian(jointData, new BodyIndexPair(), velocityA, velocityB, motionA, motionB, timestep, numIterations, ref jacobianWriter);
                jacobianWriter.EndForEachIndex();
            }

            var eventWriter = new NativeStream.Writer(); // no events expected

            // Solve the joint
            for (int iIteration = 0; iIteration < numIterations; iIteration++)
            {
                stepInput.IsLastIteration = (iIteration == numIterations - 1);
                NativeStream.Reader jacobianReader = jacobiansOut.AsReader();
                var jacIterator = new JacobianIterator(jacobianReader, 0);
                while (jacIterator.HasJacobiansLeft())
                {
                    ref JacobianHeader header = ref jacIterator.ReadJacobianHeader();
                    header.Solve(ref velocityA, ref velocityB, stepInput, ref eventWriter, ref eventWriter);
                }
            }
Beispiel #2
0
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            if (m_CharacterControllersGroup.CalculateEntityCount() == 0)
            {
                return(inputDeps);
            }

            var chunks = m_CharacterControllersGroup.CreateArchetypeChunkArray(Allocator.TempJob);

            var characterMoveType   = GetArchetypeChunkComponentType <CharacterMoveSetting>();
            var userCommandType     = GetArchetypeChunkComponentType <UserCommand>();
            var movePredictedType   = GetArchetypeChunkComponentType <CharacterMovePredictedState>();
            var transformType       = GetArchetypeChunkComponentType <TransformPredictedState>();
            var velocityType        = GetArchetypeChunkComponentType <VelocityPredictedState>();
            var physicsColliderType = GetArchetypeChunkComponentType <PhysicsCollider>();
            var entityType          = GetArchetypeChunkEntityType();

            var deferredImpulses = new NativeStream(chunks.Length, Allocator.TempJob);
            var tickDuration     = GetSingleton <WorldTime>().TickDuration;
            var ccJob            = new CharacterControllerJob
            {
                EntityType = entityType,
                // Archetypes
                CharacterMoveType          = characterMoveType,
                UserCommandComponentType   = userCommandType,
                CharacterMovePredictedType = movePredictedType,
                PhysicsColliderType        = physicsColliderType,
                TransformType = transformType,
                VelocityType  = velocityType,

                // Input
                DeltaTime             = tickDuration,
                PhysicsWorld          = m_BuildPhysicsWorldSystem.PhysicsWorld,
                DeferredImpulseWriter = deferredImpulses.AsWriter()
            };

            inputDeps = JobHandle.CombineDependencies(inputDeps, m_ExportPhysicsWorldSystem.FinalJobHandle);
            inputDeps = ccJob.Schedule(m_CharacterControllersGroup, inputDeps);

            var applyJob = new ApplyDefferedPhysicsUpdatesJob
            {
                Chunks = chunks,
                DeferredImpulseReader      = deferredImpulses.AsReader(),
                PhysicsMassData            = GetComponentDataFromEntity <PhysicsMass>(),
                TransformPredictedData     = GetComponentDataFromEntity <TransformPredictedState>(),
                VelocityPredictedData      = GetComponentDataFromEntity <VelocityPredictedState>(),
                CharacterMovePredictedData = GetComponentDataFromEntity <CharacterMovePredictedState>()
            };

            inputDeps = applyJob.Schedule(inputDeps);
            var disposeHandle = deferredImpulses.Dispose(inputDeps);

            disposeHandle.Complete();

            // Must finish all jobs before physics step end
            //  m_EndFramePhysicsSystem.HandlesToWaitFor.Add(disposeHandle);

            return(inputDeps);
        }
Beispiel #3
0
        // Schedule jobs to build Jacobians from the contacts stored in the simulation context
        internal static SimulationJobHandles ScheduleBuildJacobiansJobs(ref PhysicsWorld world, float timeStep, float3 gravity,
                                                                        int numSolverIterations, JobHandle inputDeps, ref NativeList <DispatchPairSequencer.DispatchPair> dispatchPairs,
                                                                        ref DispatchPairSequencer.SolverSchedulerInfo solverSchedulerInfo,
                                                                        ref NativeStream contacts, ref NativeStream jacobians, int threadCountHint = 0)
        {
            SimulationJobHandles returnHandles = default;

            if (threadCountHint <= 0)
            {
                returnHandles.FinalExecutionHandle = new BuildJacobiansJob
                {
                    ContactsReader      = contacts.AsReader(),
                    JacobiansWriter     = jacobians.AsWriter(),
                    TimeStep            = timeStep,
                    Gravity             = gravity,
                    NumSolverIterations = numSolverIterations,
                    World               = world,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo
                }.Schedule(inputDeps);
            }
            else
            {
                var buildJob = new BuildJacobiansJob
                {
                    ContactsReader      = contacts.AsReader(),
                    JacobiansWriter     = jacobians.AsWriter(),
                    TimeStep            = timeStep,
                    InvTimeStep         = timeStep > 0.0f ? 1.0f / timeStep : 0.0f,
                    GravityAcceleration = math.length(gravity),
                    NumSolverIterations = numSolverIterations,
                    World               = world,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo
                };

                JobHandle handle = buildJob.ScheduleUnsafeIndex0(solverSchedulerInfo.NumWorkItems, 1, inputDeps);

                returnHandles.FinalDisposeHandle = JobHandle.CombineDependencies(
                    dispatchPairs.Dispose(handle),
                    contacts.Dispose(handle));
                returnHandles.FinalExecutionHandle = handle;
            }

            return(returnHandles);
        }
Beispiel #4
0
            internal Enumerator(NativeStream stream)
            {
                m_Reader          = stream.IsCreated ? stream.AsReader() : new NativeStream.Reader();
                m_CurrentWorkItem = 0;
                m_NumWorkItems    = stream.IsCreated ? stream.ForEachCount : 0;
                Current           = default;

                AdvanceReader();
            }
    protected override void OnUpdate()
    {
        if (m_CharacterControllersGroup.CalculateEntityCount() == 0)
        {
            return;
        }

        var chunks = m_CharacterControllersGroup.CreateArchetypeChunkArray(Allocator.TempJob);

        var ccComponentType          = GetComponentTypeHandle <CharacterControllerComponentData>();
        var ccInternalType           = GetComponentTypeHandle <CharacterControllerInternalData>();
        var physicsColliderType      = GetComponentTypeHandle <PhysicsCollider>();
        var translationType          = GetComponentTypeHandle <Translation>();
        var rotationType             = GetComponentTypeHandle <Rotation>();
        var collisionEventBufferType = GetBufferTypeHandle <StatefulCollisionEvent>();
        var triggerEventBufferType   = GetBufferTypeHandle <StatefulTriggerEvent>();

        var deferredImpulses = new NativeStream(chunks.Length, Allocator.TempJob);

        var ccJob = new CharacterControllerJob
        {
            // Archetypes
            CharacterControllerComponentType = ccComponentType,
            CharacterControllerInternalType  = ccInternalType,
            PhysicsColliderType      = physicsColliderType,
            TranslationType          = translationType,
            RotationType             = rotationType,
            CollisionEventBufferType = collisionEventBufferType,
            TriggerEventBufferType   = triggerEventBufferType,

            // Input
            DeltaTime             = UnityEngine.Time.fixedDeltaTime,
            PhysicsWorld          = m_BuildPhysicsWorldSystem.PhysicsWorld,
            DeferredImpulseWriter = deferredImpulses.AsWriter()
        };

        Dependency = JobHandle.CombineDependencies(Dependency, m_ExportPhysicsWorldSystem.GetOutputDependency());
        Dependency = ccJob.Schedule(m_CharacterControllersGroup, Dependency);

        var applyJob = new ApplyDefferedPhysicsUpdatesJob()
        {
            Chunks = chunks,
            DeferredImpulseReader = deferredImpulses.AsReader(),
            PhysicsVelocityData   = GetComponentDataFromEntity <PhysicsVelocity>(),
            PhysicsMassData       = GetComponentDataFromEntity <PhysicsMass>(),
            TranslationData       = GetComponentDataFromEntity <Translation>(),
            RotationData          = GetComponentDataFromEntity <Rotation>()
        };

        Dependency = applyJob.Schedule(Dependency);
        var disposeHandle = deferredImpulses.Dispose(Dependency);

        // Must finish all jobs before physics step end
        m_EndFramePhysicsSystem.AddInputDependency(disposeHandle);
    }
Beispiel #6
0
            internal Enumerator(NativeStream stream, NativeSlice <RigidBody> bodies)
            {
                m_Reader          = stream.IsCreated ? stream.AsReader() : new NativeStream.Reader();
                m_CurrentWorkItem = 0;
                m_NumWorkItems    = stream.IsCreated ? stream.ForEachCount : 0;
                Current           = default;

                m_Bodies = bodies;

                AdvanceReader();
            }
Beispiel #7
0
        public void JacobianIteratorHasJacobiansLeftTest()
        {
            var jacobianStream = new NativeStream(1, Allocator.Temp);

            NativeStream.Reader jacobianStreamReader = jacobianStream.AsReader();
            int workItemIndex = 0;
            var jacIterator   = new JacobianIterator(jacobianStreamReader, workItemIndex);

            Assert.IsFalse(jacIterator.HasJacobiansLeft());

            jacobianStream.Dispose();
        }
Beispiel #8
0
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        if (m_CharacterControllersGroup.CalculateEntityCount() == 0)
        {
            return(inputDeps);
        }

        var chunks = m_CharacterControllersGroup.CreateArchetypeChunkArray(Allocator.TempJob);

        var ccComponentType     = GetArchetypeChunkComponentType <CharacterControllerComponentData>();
        var ccInternalType      = GetArchetypeChunkComponentType <CharacterControllerInternalData>();
        var physicsColliderType = GetArchetypeChunkComponentType <PhysicsCollider>();
        var translationType     = GetArchetypeChunkComponentType <Translation>();
        var rotationType        = GetArchetypeChunkComponentType <Rotation>();

        var deferredImpulses = new NativeStream(chunks.Length, Allocator.TempJob);

        var ccJob = new CharacterControllerJob
        {
            // Archetypes
            CharacterControllerComponentType = ccComponentType,
            CharacterControllerInternalType  = ccInternalType,
            PhysicsColliderType = physicsColliderType,
            TranslationType     = translationType,
            RotationType        = rotationType,
            // Input
            DeltaTime             = UnityEngine.Time.fixedDeltaTime,
            cameraWorldPoint      = mainCamera.ScreenToWorldPoint(Input.mousePosition),
            PhysicsWorld          = m_BuildPhysicsWorldSystem.PhysicsWorld,
            DeferredImpulseWriter = deferredImpulses.AsWriter()
        };

        inputDeps = JobHandle.CombineDependencies(inputDeps, m_ExportPhysicsWorldSystem.FinalJobHandle);
        inputDeps = ccJob.Schedule(m_CharacterControllersGroup, inputDeps);

        var applyJob = new ApplyDefferedPhysicsUpdatesJob()
        {
            Chunks = chunks,
            DeferredImpulseReader = deferredImpulses.AsReader(),
            PhysicsVelocityData   = GetComponentDataFromEntity <PhysicsVelocity>(),
            PhysicsMassData       = GetComponentDataFromEntity <PhysicsMass>(),
            TranslationData       = GetComponentDataFromEntity <Translation>(),
            RotationData          = GetComponentDataFromEntity <Rotation>()
        };

        inputDeps = applyJob.Schedule(inputDeps);
        var disposeHandle = deferredImpulses.Dispose(inputDeps);

        // Must finish all jobs before physics step end
        m_EndFramePhysicsSystem.HandlesToWaitFor.Add(disposeHandle);

        return(inputDeps);
    }
            internal Enumerator(NativeStream stream, NativeArray <Velocity> inputVelocities, float timeStep)
            {
                m_Reader          = stream.IsCreated ? stream.AsReader() : new NativeStream.Reader();
                m_CurrentWorkItem = 0;
                m_NumWorkItems    = stream.IsCreated ? stream.ForEachCount : 0;

                m_InputVelocities = inputVelocities;
                m_TimeStep        = timeStep;

                unsafe
                {
                    m_Current = default;
                }

                AdvanceReader();
            }
Beispiel #10
0
    public void PopulateInts([Values(1, 100, 200)] int count, [Values(1, 3, 10)] int batchSize)
    {
        var stream   = new NativeStream(count, Allocator.TempJob);
        var fillInts = new WriteInts {
            Writer = stream.AsWriter()
        };
        var jobHandle = fillInts.Schedule(count, batchSize);

        var compareInts = new ReadInts {
            Reader = stream.AsReader()
        };
        var res0 = compareInts.Schedule(count, batchSize, jobHandle);
        var res1 = compareInts.Schedule(count, batchSize, jobHandle);

        res0.Complete();
        res1.Complete();

        stream.Dispose();
    }
    public void NativeStreamBasic()
    {
        var stream = new NativeStream(1, Allocator.Persistent);


        var writer = stream.AsWriter();
        var reader = stream.AsReader();

        writer.BeginForEachIndex(0);
        for (var i = 0; i < 100; i++)
        {
            if (i % 2 == 0)
            {
                //unsafe{
                //	var pInt = (int*)writer.Allocate(sizeof(int));
                //	*pInt = i;
                //}
                ref int x = ref writer.Allocate <int>();
                x = i;
            }
        protected sealed override void OnUpdate()
        {
            Dependency = JobHandle.CombineDependencies(Dependency, TriggerJobHandle);

            // If the producer did not actually write anything to the stream, the native stream will not be flaged as created.
            // In that case we don't need to do anything.
            // Not doing this checks actually result in a non authrorized access to the memory and crashes Unity.
            if (!_effectStream.IsCreated)
            {
                return;
            }

            NativeStream.Reader effectReader = _effectStream.AsReader();
            SetupEffectMap      AllocateJob  = new SetupEffectMap()
            {
                EffectReader = effectReader,
                Effects      = _effects
            };

            Dependency = AllocateJob.Schedule(Dependency);


            NativeMultiHashMap <Entity, EFFECT_CTX> .ParallelWriter effectsWriter = _effects.AsParallelWriter();
            RemapEffects RemapEffectsJob = new RemapEffects()
            {
                EffectReader  = effectReader,
                EffectsWriter = _effects.AsParallelWriter()
            };

            Dependency = RemapEffectsJob.Schedule(_forEachCount, 1, Dependency);

            // Call the effect consumption logic defined in hte derived class.
            Consume();

            Dependency = _effectStream.Dispose(Dependency);
        }
        /// <summary>
        /// Voxelizes the mesh into the specified grid. The mesh is scaled to fit the grid (minus padding).
        /// Returns the voxelization job containing its job handle. The voxelization job must be disposed once the job has completed.
        /// </summary>
        /// <param name="vertices"></param>
        /// <param name="normals"></param>
        /// <param name="grid"></param>
        /// <param name="material"></param>
        /// <param name="properties"></param>
        /// <returns>The voxelization job containing its job handle. The voxelization job must be disposed once the job has completed.</returns>
        public static VoxelizationJob Voxelize <TIndexer>(NativeArray <float3> vertices, NativeArray <float3> normals, NativeArray3D <Voxel, TIndexer> grid, int material, VoxelizationProperties properties)
            where TIndexer : struct, IIndexer
        {
            var triangles = vertices.Length / 3;

            var width  = grid.Length(0);
            var height = grid.Length(1);
            var depth  = grid.Length(2);

            var scaledVertices = new NativeArray <float3>(vertices.Length, Allocator.TempJob);

            var scaleJobHandle = new VoxelizerMeshScaleJob
            {
                inVertices  = vertices,
                outVertices = scaledVertices,
                width       = grid.Length(0),
                height      = grid.Length(1),
                depth       = grid.Length(2),
                padding     = properties.padding
            }.Schedule();

            var binsStream = new NativeStream(triangles, Allocator.TempJob);

            //Bin triangles
            var binJobHandle = new VoxelizerBinJob
            {
                vertices = scaledVertices,
                width    = width,
                height   = height,
                depth    = depth,
                stream   = binsStream.AsWriter()
            }.Schedule(triangles, properties.parallelForBatchCount, scaleJobHandle);

            var binColsX = new NativeList <VoxelizerCollectBinsJob.Column>(Allocator.TempJob);
            var binColsY = new NativeList <VoxelizerCollectBinsJob.Column>(Allocator.TempJob);
            var binColsZ = new NativeList <VoxelizerCollectBinsJob.Column>(Allocator.TempJob);

            var binsX = new NativeList <int>(Allocator.TempJob);
            var binsY = new NativeList <int>(Allocator.TempJob);
            var binsZ = new NativeList <int>(Allocator.TempJob);

            //Collect bins and reorder
            var collectBinsJobHandle = new VoxelizerCollectBinsJob
            {
                stream      = binsStream.AsReader(),
                streams     = triangles,
                width       = width,
                height      = height,
                depth       = depth,
                binColumnsX = binColsX,
                binsX       = binsX,
                binColumnsY = binColsY,
                binsY       = binsY,
                binColumnsZ = binColsZ,
                binsZ       = binsZ
            }.Schedule(binJobHandle);

            var intersectionsStreamX = new NativeStream(height * depth, Allocator.TempJob);
            var intersectionsStreamY = new NativeStream(width * depth, Allocator.TempJob);
            var intersectionsStreamZ = new NativeStream(width * height, Allocator.TempJob);

            //Intersect X axis
            var intersectXJobHandle = new VoxelizerMeshIntersectionJob
            {
                vertices      = scaledVertices,
                normals       = normals,
                columns       = binColsX.AsDeferredJobArray(),
                bins          = binsX,
                width         = width,
                height        = height,
                depth         = depth,
                axis          = 0,
                stream        = intersectionsStreamX.AsWriter(),
                smoothNormals = properties.smoothNormals
            }.Schedule(binColsX, properties.parallelForBatchCount, collectBinsJobHandle);

            //Intersect Y axis
            var intersectYJobHandle = new VoxelizerMeshIntersectionJob
            {
                vertices      = scaledVertices,
                normals       = normals,
                columns       = binColsY.AsDeferredJobArray(),
                bins          = binsY,
                width         = width,
                height        = height,
                depth         = depth,
                axis          = 1,
                stream        = intersectionsStreamY.AsWriter(),
                smoothNormals = properties.smoothNormals
            }.Schedule(binColsY, properties.parallelForBatchCount, collectBinsJobHandle);

            //Intersect Z axis
            var intersectZJobHandle = new VoxelizerMeshIntersectionJob
            {
                vertices      = scaledVertices,
                normals       = normals,
                columns       = binColsZ.AsDeferredJobArray(),
                bins          = binsZ,
                width         = width,
                height        = height,
                depth         = depth,
                axis          = 2,
                stream        = intersectionsStreamZ.AsWriter(),
                smoothNormals = properties.smoothNormals
            }.Schedule(binColsZ, properties.parallelForBatchCount, collectBinsJobHandle);

            var intersectionColsX = new NativeList <VoxelizerCollectBinsJob.Column>(height * depth, Allocator.TempJob);
            var intersectionColsY = new NativeList <VoxelizerCollectBinsJob.Column>(width * depth, Allocator.TempJob);
            var intersectionColsZ = new NativeList <VoxelizerCollectBinsJob.Column>(width * height, Allocator.TempJob);

            var intersectionsX = new NativeList <float4>(Allocator.TempJob);
            var intersectionsY = new NativeList <float4>(Allocator.TempJob);
            var intersectionsZ = new NativeList <float4>(Allocator.TempJob);

            //Collect X axis
            var collectXJobHandle = new VoxelizerCollectIntersectionsJob
            {
                stream        = intersectionsStreamX.AsReader(),
                binColumns    = binColsX,
                columns       = intersectionColsX,
                intersections = intersectionsX
            }.Schedule(intersectXJobHandle);

            //Collect Y axis
            var collectYJobHandle = new VoxelizerCollectIntersectionsJob
            {
                stream        = intersectionsStreamY.AsReader(),
                binColumns    = binColsY,
                columns       = intersectionColsY,
                intersections = intersectionsY
            }.Schedule(intersectYJobHandle);

            //Collect Z axis
            var collectZJobHandle = new VoxelizerCollectIntersectionsJob
            {
                stream        = intersectionsStreamZ.AsReader(),
                binColumns    = binColsZ,
                columns       = intersectionColsZ,
                intersections = intersectionsZ
            }.Schedule(intersectZJobHandle);

            //Voxelizing using only the axis intersections can result in holes.
            //The voxelizer job will detect those holes and put them in this list
            //so they can be fixed later
            var holes = new NativeList <VoxelizerFillJob <TIndexer> .Hole>(Allocator.TempJob);

            //Fill in materials and normals where possible
            var voxelizerFillJobHandle = new VoxelizerFillJob <TIndexer>
            {
                colsX          = intersectionColsX,
                colsY          = intersectionColsY,
                colsZ          = intersectionColsZ,
                intersectionsX = intersectionsX,
                intersectionsY = intersectionsY,
                intersectionsZ = intersectionsZ,
                material       = material,
                grid           = grid,
                holes          = holes,
                angleThreshold = properties.angleThreshold,
                snapThreshold  = properties.snapThreshold
            }.Schedule(JobHandle.CombineDependencies(collectXJobHandle, collectYJobHandle, collectZJobHandle));

            //If there are holes in the voxel data, i.e. missing intersections and normals,
            //then they are patched up in a second pass
            var patchesQueue = new NativeQueue <VoxelizerFindPatchesJob <TIndexer> .PatchedHole>(Allocator.TempJob);

            //Find all hole patches in parallel
            var findPatchesJobHandle = new VoxelizerFindPatchesJob <TIndexer>
            {
                vertices       = scaledVertices,
                normals        = normals,
                holes          = holes.AsDeferredJobArray(),
                angleThreshold = properties.angleThreshold,
                smoothNormals  = properties.smoothNormals,
                queue          = patchesQueue.AsParallelWriter()
            }.Schedule(holes, properties.parallelForBatchCount, voxelizerFillJobHandle);

            //Apply the hole patches to the grid
            var applyPatchesJobHandle = new VoxelizerApplyPatchesJob <TIndexer>
            {
                queue = patchesQueue,
                grid  = grid
            }.Schedule(findPatchesJobHandle);

            return(new VoxelizationJob(applyPatchesJobHandle,
                                       scaledVertices,
                                       binsStream,
                                       binColsX, binColsY, binColsZ,
                                       binsX, binsY, binsZ,
                                       intersectionsStreamX, intersectionsStreamY, intersectionsStreamZ,
                                       intersectionColsX, intersectionColsY, intersectionColsZ,
                                       intersectionsX, intersectionsY, intersectionsZ,
                                       holes,
                                       patchesQueue));
        }
        public unsafe void OverlapTaskFilteringTest([Values(2, 10, 33, 100)] int elementCount)
        {
            elementCount *= 2;
            int numNodes = elementCount + Constants.MaxNumTreeBranches;

            var points      = new NativeArray <PointAndIndex>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var aabbs       = new NativeArray <Aabb>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var bodyFilters = new NativeArray <CollisionFilter>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);

            InitInputWithCopyArrays(points, aabbs, bodyFilters);

            var   nodes    = new NativeArray <Node>(numNodes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            Node *nodesPtr = (Node *)nodes.GetUnsafePtr();

            var seenUnfiltered = new HashSet <BodyIndexPair>();
            {
                var bvhUnfiltered = new BoundingVolumeHierarchy(nodes);
                bvhUnfiltered.Build(points, aabbs, out int numNodesOut);
                bvhUnfiltered.CheckIntegrity();

                EverythingWriter pairWriter = new EverythingWriter {
                    SeenPairs = seenUnfiltered
                };
                BoundingVolumeHierarchy.TreeOverlap(ref pairWriter, nodesPtr, nodesPtr);
            }

            var nodeFilters = new NativeArray <CollisionFilter>(numNodes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var bvhFiltered = new BoundingVolumeHierarchy(nodes, nodeFilters);
            int numNodesFilteredTree;

            bvhFiltered.Build(points, aabbs, out numNodesFilteredTree);
            bvhFiltered.BuildCombinedCollisionFilter(bodyFilters, 0, numNodesFilteredTree - 1);

            var filteredCollisionPairs = new NativeStream(1, Allocator.TempJob);

            NativeStream.Writer filteredPairWriter = filteredCollisionPairs.AsWriter();
            filteredPairWriter.BeginForEachIndex(0);
            CollisionFilter *bodyFiltersPtr = (CollisionFilter *)bodyFilters.GetUnsafePtr();
            var bufferedPairs = new Broadphase.BodyPairWriter(&filteredPairWriter, bodyFiltersPtr, bodyFiltersPtr, 0, 0);

            CollisionFilter *nodeFiltersPtr = (CollisionFilter *)nodeFilters.GetUnsafePtr();

            BoundingVolumeHierarchy.TreeOverlap(ref bufferedPairs, nodesPtr, nodesPtr, nodeFiltersPtr, nodeFiltersPtr);
            bufferedPairs.Close();
            filteredPairWriter.EndForEachIndex();

            NativeStream.Reader filteredPairReader = filteredCollisionPairs.AsReader();
            filteredPairReader.BeginForEachIndex(0);

            // Check that every pair in our filtered set also appears in the unfiltered set
            while (filteredPairReader.RemainingItemCount > 0)
            {
                var pair = filteredPairReader.Read <BodyIndexPair>();

                Assert.IsTrue(seenUnfiltered.Contains(pair));
                seenUnfiltered.Remove(pair); // Remove the pair
            }

            // Pairs were removed, so the only remaining ones should be filtered
            foreach (BodyIndexPair pair in seenUnfiltered)
            {
                bool shouldCollide = CollisionFilter.IsCollisionEnabled(bodyFilters[pair.BodyIndexA], bodyFilters[pair.BodyIndexB]);
                Assert.IsFalse(shouldCollide);
            }

            nodeFilters.Dispose();
            nodes.Dispose();
            bodyFilters.Dispose();
            aabbs.Dispose();
            points.Dispose();
            filteredCollisionPairs.Dispose();
        }
    protected unsafe override JobHandle OnUpdate(JobHandle inputDeps)
    {
        var entityCount = m_CharacterControllerGroup.CalculateEntityCount();

        if (entityCount == 0)
        {
            return(inputDeps);
        }

        var defferredImpulses = new NativeStream(entityCount, Allocator.TempJob);
        var time        = m_TimeSingletonQuery.GetSingleton <GlobalGameTime>().gameTime;
        var physicWorld = m_BuildPhysicsWorld.PhysicsWorld;

        var writer = defferredImpulses.AsWriter();

        var constraints  = new NativeList <SurfaceConstraintInfo>(Allocator.Temp);
        var castHits     = new NativeList <ColliderCastHit>(Allocator.Temp);
        var distanceHits = new NativeList <DistanceHit>(Allocator.Temp);

        var input  = new ColliderCastInput();
        var hit    = new ColliderCastHit();
        var hasHit = false;

        var deltaTime = Time.DeltaTime;

        Entities
        .WithName("CharacterControllerStepSystem")
        .ForEach((
                     ref CharacterControllerComponentData ccData,
                     ref CharacterControllerCollider ccCollider,
                     ref CharacterControllerMoveQuery moveQuery,
                     ref CharacterControllerMoveResult moveResult,
                     ref CharacterControllerVelocity velocity
                     ) => {
            var collider = (Collider *)ccCollider.Collider.GetUnsafePtr();

            var stepInput = new CharacterControllerUtilities.CharacterControllerStepInput {
                World = physicWorld,
                //DeltaTime = time.tickDuration,
                DeltaTime        = deltaTime,
                Gravity          = new float3(0.0f, -9.8f, 0.0f),
                MaxIterations    = ccData.MaxIterations,
                Tau              = CharacterControllerUtilities.k_DefaultTau,
                Damping          = CharacterControllerUtilities.k_DefaultDamping,
                SkinWidth        = ccData.SkinWidth,
                ContactTolerance = ccData.ContactTolearance,
                MaxSlope         = ccData.MaxSlope,
                RigidBodyIndex   = -1,
                CurrentVelocity  = velocity.WorldVelocity,
                MaxMovementSpeed = ccData.MaxMovementSpeed,
                FollowGroud      = moveQuery.FollowGroud
            };

            var transform = new RigidTransform {
                pos = moveQuery.StartPosition,
                rot = quaternion.identity
            };

            CharacterControllerUtilities.CollideAndIntegrate(
                stepInput,
                ccData.CharacterMass,
                ccData.AffectsPhysicsBodies > 0,
                collider,
                ref transform,
                ref velocity.WorldVelocity,
                ref writer,
                ref constraints,
                ref castHits,
                ref distanceHits,
                out input,
                out hit);

            moveResult.MoveResult = transform.pos;
        })
        .Run();


        var applyJob = new ApplyDefferedImpulses()
        {
            DeferredImpulseReader = defferredImpulses.AsReader(),
            PhysicsVelocityData   = GetComponentDataFromEntity <PhysicsVelocity>(),
            PhysicsMassData       = GetComponentDataFromEntity <PhysicsMass>(),
            TranslationData       = GetComponentDataFromEntity <Translation>(),
            RotationData          = GetComponentDataFromEntity <Rotation>()
        };

        applyJob.Run();

        CharacterControllerDebug.input = input;
        CharacterControllerDebug.hit   = hit;

        defferredImpulses.Dispose();
        constraints.Dispose();
        castHits.Dispose();
        distanceHits.Dispose();

        return(inputDeps);
    }
Beispiel #16
0
        protected override void OnUpdate()
        {
            var ecsJH = Dependency;

            //Query arrays
            var aliveListenerEntities = m_aliveListenersQuery.ToEntityArrayAsync(Allocator.TempJob, out JobHandle aliveListenerEntitiesJH);
            var deadListenerEntities  = m_deadListenersQuery.ToEntityArrayAsync(Allocator.TempJob, out JobHandle deadListenerEntitiesJH);
            var listenerEntitiesJH    = JobHandle.CombineDependencies(aliveListenerEntitiesJH, deadListenerEntitiesJH);

            //Type handles
            var entityHandle      = GetEntityTypeHandle();
            var listenerHandle    = GetComponentTypeHandle <AudioListener>(true);
            var oneshotHandle     = GetComponentTypeHandle <AudioSourceOneShot>(false);
            var loopedHandle      = GetComponentTypeHandle <AudioSourceLooped>(false);
            var coneHandle        = GetComponentTypeHandle <AudioSourceEmitterCone>(true);
            var translationHandle = GetComponentTypeHandle <Translation>(true);
            var rotationHandle    = GetComponentTypeHandle <Rotation>(true);
            var ltwHandle         = GetComponentTypeHandle <LocalToWorld>(true);
            var parentHandle      = GetComponentTypeHandle <Parent>(true);

            var audioSettingsCdfe          = GetComponentDataFromEntity <AudioSettings>(true);
            var listenerCdfe               = GetComponentDataFromEntity <AudioListener>(true);
            var listenerGraphStateCdfe     = GetComponentDataFromEntity <ListenerGraphState>(false);
            var entityOutputGraphStateCdfe = GetComponentDataFromEntity <EntityOutputGraphState>(false);

            //Buffer
            m_currentBufferId++;
            var ildBuffer = new ManagedIldBuffer
            {
                buffer   = new NativeList <float>(Allocator.Persistent),
                channels = new NativeList <IldBufferChannel>(Allocator.Persistent),
                bufferId = m_currentBufferId
            };

            //Containers
            var destroyCommandBuffer     = latiosWorld.syncPoint.CreateDestroyCommandBuffer().AsParallelWriter();
            var entityCommandBuffer      = latiosWorld.syncPoint.CreateEntityCommandBuffer();
            var dspCommandBlock          = m_graph.CreateCommandBlock();
            var listenersWithTransforms  = new NativeList <ListenerWithTransform>(aliveListenerEntities.Length, Allocator.TempJob);
            var listenerBufferParameters = new NativeArray <ListenerBufferParameters>(aliveListenerEntities.Length,
                                                                                      Allocator.TempJob,
                                                                                      NativeArrayOptions.UninitializedMemory);
            var forIndexToListenerAndChannelIndices = new NativeList <int2>(Allocator.TempJob);
            var oneshotEmitters = new NativeArray <OneshotEmitter>(m_oneshotsQuery.CalculateEntityCount(),
                                                                   Allocator.TempJob,
                                                                   NativeArrayOptions.UninitializedMemory);
            var loopedEmitters       = new NativeArray <LoopedEmitter>(m_loopedQuery.CalculateEntityCount(), Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
            var oneshotWeightsStream = new NativeStream(oneshotEmitters.Length / CullingAndWeighting.BATCH_SIZE + 1, Allocator.TempJob);
            var loopedWeightsStream  = new NativeStream(loopedEmitters.Length / CullingAndWeighting.BATCH_SIZE + 1, Allocator.TempJob);
            var oneshotListenerEmitterPairsStream = new NativeStream(oneshotEmitters.Length / CullingAndWeighting.BATCH_SIZE + 1, Allocator.TempJob);
            var loopedListenerEmitterPairsStream  = new NativeStream(loopedEmitters.Length / CullingAndWeighting.BATCH_SIZE + 1, Allocator.TempJob);
            var oneshotClipFrameLookups           = new NativeList <ClipFrameLookup>(Allocator.TempJob);
            var loopedClipFrameLookups            = new NativeList <ClipFrameLookup>(Allocator.TempJob);
            var oneshotBatchedWeights             = new NativeList <Weights>(Allocator.TempJob);
            var loopedBatchedWeights         = new NativeList <Weights>(Allocator.TempJob);
            var oneshotTargetListenerIndices = new NativeList <int>(Allocator.TempJob);
            var loopedTargetListenerIndices  = new NativeList <int>(Allocator.TempJob);

            //Jobs
            m_lastUpdateJobHandle.Complete();

            //This may lag behind what the job threads will see.
            //That's fine, as this is only used for disposing memory.
            int lastReadIldBufferFromMainThread = m_lastReadBufferId.Value;

            var captureListenersJH = new InitUpdateDestroy.UpdateListenersJob
            {
                listenerHandle          = listenerHandle,
                translationHandle       = translationHandle,
                rotationHandle          = rotationHandle,
                ltwHandle               = ltwHandle,
                listenersWithTransforms = listenersWithTransforms
            }.Schedule(m_aliveListenersQuery, ecsJH);

            var captureFrameJH = new GraphHandling.CaptureIldFrameJob
            {
                packedFrameCounterBufferId = m_packedFrameCounterBufferId,
                audioFrame       = m_audioFrame,
                lastReadBufferId = m_lastReadBufferId
            }.Schedule();

            var ecsCaptureFrameJH = JobHandle.CombineDependencies(ecsJH, captureFrameJH);

            var updateListenersGraphJH = new GraphHandling.UpdateListenersGraphJob
            {
                listenerEntities          = aliveListenerEntities,
                destroyedListenerEntities = deadListenerEntities,
                listenerCdfe                 = listenerCdfe,
                listenerGraphStateCdfe       = listenerGraphStateCdfe,
                listenerOutputGraphStateCdfe = entityOutputGraphStateCdfe,
                ecb = entityCommandBuffer,
                audioSettingsCdfe                   = audioSettingsCdfe,
                worldBlackboardEntity               = worldBlackboardEntity,
                audioFrame                          = m_audioFrame,
                systemMixNodePortFreelist           = m_mixNodePortFreelist,
                systemMixNodePortCount              = m_mixNodePortCount,
                systemMixNode                       = m_mixNode,
                systemIldNodePortCount              = m_ildNodePortCount,
                systemIldNode                       = m_ildNode,
                commandBlock                        = dspCommandBlock,
                listenerBufferParameters            = listenerBufferParameters,
                forIndexToListenerAndChannelIndices = forIndexToListenerAndChannelIndices,
                outputSamplesMegaBuffer             = ildBuffer.buffer,
                outputSamplesMegaBufferChannels     = ildBuffer.channels,
                bufferId           = m_currentBufferId,
                samplesPerSubframe = m_samplesPerSubframe
            }.Schedule(JobHandle.CombineDependencies(captureListenersJH, captureFrameJH, listenerEntitiesJH));

            var destroyOneshotsJH = new InitUpdateDestroy.DestroyOneshotsWhenFinishedJob
            {
                dcb                   = destroyCommandBuffer,
                entityHandle          = entityHandle,
                oneshotHandle         = oneshotHandle,
                audioFrame            = m_audioFrame,
                sampleRate            = m_sampleRate,
                settingsCdfe          = audioSettingsCdfe,
                samplesPerSubframe    = m_samplesPerSubframe,
                worldBlackboardEntity = worldBlackboardEntity
            }.ScheduleParallel(m_oneshotsToDestroyWhenFinishedQuery, 1, ecsCaptureFrameJH);

            var updateOneshotsJH = new InitUpdateDestroy.UpdateOneshotsJob
            {
                oneshotHandle        = oneshotHandle,
                ltwHandle            = ltwHandle,
                translationHandle    = translationHandle,
                rotationHandle       = rotationHandle,
                parentHandle         = parentHandle,
                coneHandle           = coneHandle,
                audioFrame           = m_audioFrame,
                lastConsumedBufferId = m_lastReadBufferId,
                bufferId             = m_currentBufferId,
                emitters             = oneshotEmitters
            }.ScheduleParallel(m_oneshotsQuery, 1, destroyOneshotsJH);

            var updateLoopedJH = new InitUpdateDestroy.UpdateLoopedsJob
            {
                loopedHandle         = loopedHandle,
                ltwHandle            = ltwHandle,
                translationHandle    = translationHandle,
                rotationHandle       = rotationHandle,
                parentHandle         = parentHandle,
                coneHandle           = coneHandle,
                audioFrame           = m_audioFrame,
                lastConsumedBufferId = m_lastReadBufferId,
                bufferId             = m_currentBufferId,
                emitters             = loopedEmitters
            }.ScheduleParallel(m_loopedQuery, 1, ecsCaptureFrameJH);

            //No more ECS
            var oneshotsCullingWeightingJH = new CullingAndWeighting.OneshotsJob
            {
                emitters = oneshotEmitters,
                listenersWithTransforms = listenersWithTransforms,
                weights = oneshotWeightsStream.AsWriter(),
                listenerEmitterPairs = oneshotListenerEmitterPairsStream.AsWriter()
            }.ScheduleBatch(oneshotEmitters.Length, CullingAndWeighting.BATCH_SIZE, JobHandle.CombineDependencies(captureListenersJH, updateOneshotsJH));

            var loopedCullingWeightingJH = new CullingAndWeighting.LoopedJob
            {
                emitters = loopedEmitters,
                listenersWithTransforms = listenersWithTransforms,
                weights = loopedWeightsStream.AsWriter(),
                listenerEmitterPairs = loopedListenerEmitterPairsStream.AsWriter()
            }.ScheduleBatch(loopedEmitters.Length, CullingAndWeighting.BATCH_SIZE, JobHandle.CombineDependencies(captureListenersJH, updateLoopedJH));

            var oneshotsBatchingJH = new Batching.BatchOneshotsJob
            {
                emitters              = oneshotEmitters,
                pairWeights           = oneshotWeightsStream.AsReader(),
                listenerEmitterPairs  = oneshotListenerEmitterPairsStream.AsReader(),
                clipFrameLookups      = oneshotClipFrameLookups,
                batchedWeights        = oneshotBatchedWeights,
                targetListenerIndices = oneshotTargetListenerIndices
            }.Schedule(oneshotsCullingWeightingJH);

            var loopedBatchingJH = new Batching.BatchLoopedJob
            {
                emitters              = loopedEmitters,
                pairWeights           = loopedWeightsStream.AsReader(),
                listenerEmitterPairs  = loopedListenerEmitterPairsStream.AsReader(),
                clipFrameLookups      = loopedClipFrameLookups,
                batchedWeights        = loopedBatchedWeights,
                targetListenerIndices = loopedTargetListenerIndices
            }.Schedule(loopedCullingWeightingJH);

            var oneshotSamplingJH = new Sampling.SampleOneshotClipsJob
            {
                clipFrameLookups                    = oneshotClipFrameLookups.AsDeferredJobArray(),
                weights                             = oneshotBatchedWeights.AsDeferredJobArray(),
                targetListenerIndices               = oneshotTargetListenerIndices.AsDeferredJobArray(),
                listenerBufferParameters            = listenerBufferParameters,
                forIndexToListenerAndChannelIndices = forIndexToListenerAndChannelIndices.AsDeferredJobArray(),
                outputSamplesMegaBuffer             = ildBuffer.buffer.AsDeferredJobArray(),
                sampleRate                          = m_sampleRate,
                samplesPerSubframe                  = m_samplesPerSubframe,
                audioFrame                          = m_audioFrame
            }.Schedule(forIndexToListenerAndChannelIndices, 1, JobHandle.CombineDependencies(updateListenersGraphJH, oneshotsBatchingJH));

            var loopedSamplingJH = new Sampling.SampleLoopedClipsJob
            {
                clipFrameLookups                    = loopedClipFrameLookups.AsDeferredJobArray(),
                weights                             = loopedBatchedWeights.AsDeferredJobArray(),
                targetListenerIndices               = loopedTargetListenerIndices.AsDeferredJobArray(),
                listenerBufferParameters            = listenerBufferParameters,
                forIndexToListenerAndChannelIndices = forIndexToListenerAndChannelIndices.AsDeferredJobArray(),
                outputSamplesMegaBuffer             = ildBuffer.buffer.AsDeferredJobArray(),
                sampleRate                          = m_sampleRate,
                samplesPerSubframe                  = m_samplesPerSubframe,
                audioFrame                          = m_audioFrame
            }.Schedule(forIndexToListenerAndChannelIndices, 1, JobHandle.CombineDependencies(oneshotSamplingJH, loopedBatchingJH));

            var shipItJH = new GraphHandling.SubmitToDspGraphJob
            {
                commandBlock = dspCommandBlock
            }.Schedule(loopedSamplingJH);

            Dependency = JobHandle.CombineDependencies(updateListenersGraphJH, //handles captureListener and captureFrame
                                                       updateOneshotsJH,       //handles destroyOneshots
                                                       updateLoopedJH
                                                       );

            var disposeJobHandles = new NativeList <JobHandle>(Allocator.TempJob);

            disposeJobHandles.Add(aliveListenerEntities.Dispose(updateListenersGraphJH));
            disposeJobHandles.Add(deadListenerEntities.Dispose(updateListenersGraphJH));
            disposeJobHandles.Add(listenersWithTransforms.Dispose(JobHandle.CombineDependencies(oneshotsCullingWeightingJH, loopedCullingWeightingJH)));
            disposeJobHandles.Add(listenerBufferParameters.Dispose(loopedSamplingJH));
            disposeJobHandles.Add(forIndexToListenerAndChannelIndices.Dispose(loopedSamplingJH));
            disposeJobHandles.Add(oneshotEmitters.Dispose(oneshotsBatchingJH));
            disposeJobHandles.Add(loopedEmitters.Dispose(loopedBatchingJH));
            disposeJobHandles.Add(oneshotWeightsStream.Dispose(oneshotsBatchingJH));
            disposeJobHandles.Add(loopedWeightsStream.Dispose(loopedBatchingJH));
            disposeJobHandles.Add(oneshotListenerEmitterPairsStream.Dispose(oneshotsBatchingJH));
            disposeJobHandles.Add(loopedListenerEmitterPairsStream.Dispose(loopedBatchingJH));
            disposeJobHandles.Add(oneshotClipFrameLookups.Dispose(oneshotSamplingJH));
            disposeJobHandles.Add(loopedClipFrameLookups.Dispose(loopedSamplingJH));
            disposeJobHandles.Add(oneshotBatchedWeights.Dispose(oneshotSamplingJH));
            disposeJobHandles.Add(loopedBatchedWeights.Dispose(loopedSamplingJH));
            disposeJobHandles.Add(oneshotTargetListenerIndices.Dispose(oneshotSamplingJH));
            disposeJobHandles.Add(loopedTargetListenerIndices.Dispose(loopedSamplingJH));
            disposeJobHandles.Add(shipItJH);

            for (int i = 0; i < m_buffersInFlight.Count; i++)
            {
                var buffer = m_buffersInFlight[i];
                if (buffer.bufferId - lastReadIldBufferFromMainThread < 0)
                {
                    disposeJobHandles.Add(buffer.buffer.Dispose(ecsJH));
                    disposeJobHandles.Add(buffer.channels.Dispose(ecsJH));
                    m_buffersInFlight.RemoveAtSwapBack(i);
                    i--;
                }
            }

            m_lastUpdateJobHandle = JobHandle.CombineDependencies(disposeJobHandles);
            disposeJobHandles.Dispose();

            m_buffersInFlight.Add(ildBuffer);
        }
Beispiel #17
0
        // Schedule jobs to solve the Jacobians stored in the simulation context
        internal static unsafe SimulationJobHandles ScheduleSolveJacobiansJobs(ref DynamicsWorld dynamicsWorld, float timestep, int numIterations,
                                                                               ref NativeStream jacobians, ref NativeStream collisionEvents, ref NativeStream triggerEvents,
                                                                               ref DispatchPairSequencer.SolverSchedulerInfo solverSchedulerInfo, JobHandle inputDeps, int threadCountHint = 0)
        {
            SimulationJobHandles returnHandles = default;

            if (threadCountHint <= 0)
            {
                collisionEvents = new NativeStream(1, Allocator.Persistent);
                triggerEvents   = new NativeStream(1, Allocator.Persistent);
                returnHandles.FinalExecutionHandle = new SolverJob
                {
                    CollisionEventsWriter = collisionEvents.AsWriter(),
                    JacobiansReader       = jacobians.AsReader(),
                    NumIterations         = numIterations,
                    Timestep            = timestep,
                    TriggerEventsWriter = triggerEvents.AsWriter(),
                    MotionVelocities    = dynamicsWorld.MotionVelocities,
                    Phases = solverSchedulerInfo.PhaseInfo
                }.Schedule(inputDeps);

                return(returnHandles);
            }

            JobHandle handle;

            int numPhases = solverSchedulerInfo.NumPhases;

            // Use persistent allocator to allow these to live until the start of next step
            {
                NativeArray <int> workItemList = solverSchedulerInfo.NumWorkItems;

                //TODO: Change this to Allocator.TempJob when https://github.com/Unity-Technologies/Unity.Physics/issues/7 is resolved
                JobHandle collisionEventStreamHandle = NativeStream.ScheduleConstruct(out collisionEvents, workItemList, inputDeps, Allocator.Persistent);
                JobHandle triggerEventStreamHandle   = NativeStream.ScheduleConstruct(out triggerEvents, workItemList, inputDeps, Allocator.Persistent);

                handle = JobHandle.CombineDependencies(collisionEventStreamHandle, triggerEventStreamHandle);

                float invNumIterations = math.rcp(numIterations);

                var phaseInfoPtrs = (DispatchPairSequencer.SolverSchedulerInfo.SolvePhaseInfo *)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(solverSchedulerInfo.PhaseInfo);

                for (int solverIterationId = 0; solverIterationId < numIterations; solverIterationId++)
                {
                    bool lastIteration = solverIterationId == numIterations - 1;
                    for (int phaseId = 0; phaseId < numPhases; phaseId++)
                    {
                        var job = new SolverJob
                        {
                            JacobiansReader  = jacobians.AsReader(),
                            PhaseIndex       = phaseId,
                            Phases           = solverSchedulerInfo.PhaseInfo,
                            MotionVelocities = dynamicsWorld.MotionVelocities,
                            StepInput        = new StepInput
                            {
                                InvNumSolverIterations = invNumIterations,
                                IsLastIteration        = lastIteration,
                                Timestep    = timestep,
                                InvTimestep = timestep > 0.0f ? 1.0f / timestep : 0.0f
                            }
                        };

                        // Only initialize event writers for last solver iteration jobs
                        if (lastIteration)
                        {
                            job.CollisionEventsWriter = collisionEvents.AsWriter();
                            job.TriggerEventsWriter   = triggerEvents.AsWriter();
                        }

                        // NOTE: The last phase must be executed on a single job since it
                        // int.MaxValue can't be used as batchSize since 19.1 overflows in that case...
                        bool isLastPhase = phaseId == numPhases - 1;
                        int  batchSize   = isLastPhase ? (int.MaxValue / 2) : 1;

                        int *numWorkItems = &(phaseInfoPtrs[phaseId].NumWorkItems);
                        handle = job.Schedule(numWorkItems, batchSize, handle);
                    }
                }
            }

            // Dispose processed data
            returnHandles.FinalDisposeHandle = JobHandle.CombineDependencies(
                jacobians.Dispose(handle),
                solverSchedulerInfo.ScheduleDisposeJob(handle));
            returnHandles.FinalExecutionHandle = handle;

            return(returnHandles);
        }
 public NativeStream.Reader AsReader()
 {
     return(NativeStream.AsReader());
 }
 public NativeStream.Reader GetEffectReader()
 {
     return(_effectStream.AsReader());
 }
Beispiel #20
0
        // Steps the simulation immediately on a single thread without spawning any jobs.
        public static void StepImmediate(SimulationStepInput input, ref SimulationContext simulationContext)
        {
            if (input.TimeStep < 0)
            {
                throw new ArgumentOutOfRangeException();
            }
            if (input.NumSolverIterations <= 0)
            {
                throw new ArgumentOutOfRangeException();
            }

            if (input.World.NumDynamicBodies == 0)
            {
                // No need to do anything, since nothing can move
                return;
            }

            // Inform the context of the timeStep
            simulationContext.TimeStep = input.TimeStep;

            // Find all body pairs that overlap in the broadphase
            var dynamicVsDynamicBodyPairs = new NativeStream(1, Allocator.Temp);
            var dynamicVsStaticBodyPairs  = new NativeStream(1, Allocator.Temp);
            {
                var dynamicVsDynamicBodyPairsWriter = dynamicVsDynamicBodyPairs.AsWriter();
                var dynamicVsStaticBodyPairsWriter  = dynamicVsStaticBodyPairs.AsWriter();
                input.World.CollisionWorld.FindOverlaps(ref dynamicVsDynamicBodyPairsWriter, ref dynamicVsStaticBodyPairsWriter);
            }

            // Create dispatch pairs
            var dispatchPairs = new NativeList <DispatchPairSequencer.DispatchPair>(Allocator.Temp);

            DispatchPairSequencer.CreateDispatchPairs(ref dynamicVsDynamicBodyPairs, ref dynamicVsStaticBodyPairs,
                                                      input.World.NumDynamicBodies, input.World.Joints, ref dispatchPairs);

            // Apply gravity and copy input velocities
            Solver.ApplyGravityAndCopyInputVelocities(input.World.DynamicsWorld.MotionDatas, input.World.DynamicsWorld.MotionVelocities,
                                                      simulationContext.InputVelocities, input.TimeStep * input.Gravity);

            // Narrow phase
            var contacts = new NativeStream(1, Allocator.Temp);
            {
                var contactsWriter = contacts.AsWriter();
                NarrowPhase.CreateContacts(ref input.World, dispatchPairs.AsArray(), input.TimeStep, ref contactsWriter);
            }

            // Build Jacobians
            var jacobians = new NativeStream(1, Allocator.Temp);

            {
                var contactsReader  = contacts.AsReader();
                var jacobiansWriter = jacobians.AsWriter();
                Solver.BuildJacobians(ref input.World, input.TimeStep, input.Gravity, input.NumSolverIterations,
                                      dispatchPairs.AsArray(), ref contactsReader, ref jacobiansWriter);
            }

            // Solve Jacobians
            {
                var jacobiansReader       = jacobians.AsReader();
                var collisionEventsWriter = simulationContext.CollisionEventDataStream.AsWriter();
                var triggerEventsWriter   = simulationContext.TriggerEventDataStream.AsWriter();
                Solver.SolveJacobians(ref jacobiansReader, input.World.DynamicsWorld.MotionVelocities, input.TimeStep, input.NumSolverIterations,
                                      ref collisionEventsWriter, ref triggerEventsWriter);
            }

            // Integrate motions
            Integrator.Integrate(input.World.DynamicsWorld.MotionDatas, input.World.DynamicsWorld.MotionVelocities, input.TimeStep);

            // Synchronize the collision world if asked for
            if (input.SynchronizeCollisionWorld)
            {
                input.World.CollisionWorld.UpdateDynamicTree(ref input.World, input.TimeStep, input.Gravity);
            }
        }