Ejemplo n.º 1
0
    public void ToArray([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()
        };

        fillInts.Schedule(count, batchSize).Complete();

        var array     = stream.ToNativeArray <int>(Allocator.Temp);
        int itemIndex = 0;

        for (int i = 0; i != count; ++i)
        {
            for (int j = 0; j < i; ++j)
            {
                Assert.AreEqual(j, array[itemIndex]);
                itemIndex++;
            }
        }

        array.Dispose();

        stream.Dispose();
    }
Ejemplo n.º 2
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);
                }
            }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
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);
        }
Ejemplo n.º 5
0
    public void WriteWithoutBeginThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        Assert.Throws <ArgumentException>(() => writer.Write(5));

        stream.Dispose();
    }
Ejemplo n.º 6
0
    public Context GetContext(int foreachCount)
    {
        var stream = new NativeStream(foreachCount, Allocator.TempJob);

        m_DebugStreams.Add(stream);
        return(new Context {
            Writer = stream.AsWriter()
        });
    }
Ejemplo n.º 7
0
    public void OutOfBoundsWriteThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        Assert.Throws <ArgumentException>(() => writer.BeginForEachIndex(-1));
        Assert.Throws <ArgumentException>(() => writer.BeginForEachIndex(2));

        stream.Dispose();
    }
    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);
    }
Ejemplo n.º 9
0
    public void UnbalancedBeginThrows()
    {
        var stream = new NativeStream(2, Allocator.Temp);
        var writer = stream.AsWriter();

        writer.BeginForEachIndex(0);
        // Missing EndForEachIndex();
        Assert.Throws <ArgumentException>(() => writer.BeginForEachIndex(1));

        stream.Dispose();
    }
Ejemplo n.º 10
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);
    }
Ejemplo n.º 11
0
    public void ItemCount([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()
        };

        fillInts.Schedule(count, batchSize).Complete();

        Assert.AreEqual(count * (count - 1) / 2, stream.ComputeItemCount());

        stream.Dispose();
    }
Ejemplo n.º 12
0
    public void WriteAfterEndThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        writer.BeginForEachIndex(0);
        writer.Write(2);
        writer.EndForEachIndex();

        Assert.Throws <ArgumentException>(() => writer.Write(5));

        stream.Dispose();
    }
    public void ItemCount([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()
        };

        fillInts.Schedule(count, batchSize).Complete();

        ExpectedCount(ref stream, count * (count - 1) / 2);

        stream.Dispose();
    }
Ejemplo n.º 14
0
    public void DisposeAfterSchedule()
    {
        var stream   = new NativeStream(100, Allocator.TempJob);
        var fillInts = new WriteInts {
            Writer = stream.AsWriter()
        };
        var writerJob = fillInts.Schedule(100, 16);

        var disposeJob = stream.Dispose(writerJob);

        Assert.IsFalse(stream.IsCreated);

        disposeJob.Complete();
    }
Ejemplo n.º 15
0
    public void ParallelWriteThrows()
    {
        var stream   = new NativeStream(100, Allocator.TempJob);
        var fillInts = new WriteInts {
            Writer = stream.AsWriter()
        };

        var writerJob = fillInts.Schedule(100, 16);

        Assert.Throws <InvalidOperationException>(() => fillInts.Schedule(100, 16));

        writerJob.Complete();
        stream.Dispose();
    }
Ejemplo n.º 16
0
    public void WriteManagedThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        writer.BeginForEachIndex(0);

        Assert.Throws <ArgumentException>(() =>
        {
            writer.Write(new ManagedRef());
        });

        stream.Dispose();
    }
Ejemplo n.º 17
0
    static void CreateBlockStream1And2Int(out NativeStream stream)
    {
        stream = new NativeStream(2, Allocator.Temp);

        var writer = stream.AsWriter();

        writer.BeginForEachIndex(0);
        writer.Write(0);
        writer.EndForEachIndex();

        writer.BeginForEachIndex(1);
        writer.Write(1);
        writer.Write(2);
        writer.EndForEachIndex();
    }
Ejemplo n.º 18
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;
            }
Ejemplo n.º 20
0
        // Schedules a set of jobs to iterate the provided dispatch pairs and create contacts based on them.
        internal static SimulationJobHandles ScheduleCreateContactsJobs(ref PhysicsWorld world, float timeStep,
                                                                        ref NativeStream contacts, ref NativeStream jacobians, ref NativeList <DispatchPairSequencer.DispatchPair> dispatchPairs,
                                                                        JobHandle inputDeps, ref DispatchPairSequencer.SolverSchedulerInfo solverSchedulerInfo, int threadCountHint = 0)
        {
            SimulationJobHandles returnHandles = default;

            if (threadCountHint <= 0)
            {
                contacts  = new NativeStream(1, Allocator.TempJob);
                jacobians = new NativeStream(1, Allocator.TempJob);
                returnHandles.FinalExecutionHandle = new CreateContactsJob
                {
                    World               = world,
                    TimeStep            = timeStep,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo,
                    ContactsWriter      = contacts.AsWriter()
                }.Schedule(inputDeps);
            }
            else
            {
                var numWorkItems    = solverSchedulerInfo.NumWorkItems;
                var contactsHandle  = NativeStream.ScheduleConstruct(out contacts, numWorkItems, inputDeps, Allocator.TempJob);
                var jacobiansHandle = NativeStream.ScheduleConstruct(out jacobians, numWorkItems, inputDeps, Allocator.TempJob);

                var processHandle = new CreateContactsJob
                {
                    World               = world,
                    TimeStep            = timeStep,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo,
                    ContactsWriter      = contacts.AsWriter()
                }.ScheduleUnsafeIndex0(numWorkItems, 1, JobHandle.CombineDependencies(contactsHandle, jacobiansHandle));


                returnHandles.FinalExecutionHandle = processHandle;
            }

            return(returnHandles);
        }
Ejemplo n.º 21
0
    public void CopyWriterByValueThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        writer.BeginForEachIndex(0);

        Assert.Throws <ArgumentException>(() =>
        {
            var writerCopy = writer;
            writerCopy.Write(5);
        });

        Assert.Throws <ArgumentException>(() =>
        {
            var writerCopy = writer;
            writerCopy.BeginForEachIndex(1);
            writerCopy.Write(5);
        });

        stream.Dispose();
    }
Ejemplo n.º 22
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);
            }
        }
Ejemplo n.º 23
0
        protected unsafe override void OnUpdate()
        {
            var    contexts     = new NativeList <UIContextData>(8, Allocator.TempJob);
            var    graphData    = new NativeList <UIGraphData>(8, Allocator.TempJob);
            Entity schemaEntity = Entity.Null;
            int    nodeCount    = 0;

            meshes.Clear();
            Entities.ForEach((UIObject obj) =>
            {
                //TODO: Writes every conversion frame but will crash under certain conditions otherwise. Crashes observed involving opening and closing subscenes without modifying anything after script reload.

                var guid = obj.model?.GetOutputGuid();

                if (!string.IsNullOrEmpty(guid))
                {
                    IntPtr ptr;
                    long allocatedLength;
                    using (var fs = File.OpenRead(UnityEditor.AssetDatabase.GUIDToAssetPath(guid))) {
                        allocatedLength = math.ceilpow2(fs.Length);
                        ptr             = (IntPtr)UnsafeUtility.Malloc(allocatedLength, 0, Allocator.Persistent);
                        using (var us = new UnmanagedMemoryStream((byte *)ptr.ToPointer(), 0, fs.Length, FileAccess.Write)) {
                            fs.CopyTo(us);
                        }
                    }
                    var gd = new UIGraphData {
                        value = ptr, allocatedLength = allocatedLength
                    };
                    graphData.Add(gd);
                    nodeCount += gd.GetNodeCount();
                    contexts.Add(UIContextData.CreateContext(obj.camera));
                    meshes.Add(new Mesh());
                    if (schemaEntity == Entity.Null)
                    {
                        schemaEntity = CreateAdditionalEntity(obj);
                        DstEntityManager.SetName(schemaEntity, "UI Schema");
                        DstEntityManager.AddSharedComponentData(schemaEntity, new UISchemaData {
                            value = schema
                        });
                    }
                    DeclareAssetDependency(obj.gameObject, schema);
                }
                obj.cachedGuid = guid;
            });

            if (graphData.Length > 0)
            {
                var graphDataArray = graphData.AsArray();
                var meshData       = Mesh.AllocateWritableMeshData(graphData.Length);
                var submeshes      = new NativeArray <int>(graphData.Length, Allocator.TempJob);
                var stream         = new NativeStream(nodeCount, Allocator.TempJob);
                new UILayoutJob
                {
                    schema        = compiledSchema,
                    graphs        = graphDataArray,
                    contexts      = contexts,
                    meshDataArray = meshData
                }.Schedule(graphData.Length, 1).Complete();
                new UINodeDecompositionJob
                {
                    schema       = compiledSchema,
                    graphs       = graphDataArray,
                    nodes        = stream.AsWriter(),
                    submeshCount = submeshes
                }.Schedule(graphData.Length, 1).Complete();
                Mesh.ApplyAndDisposeWritableMeshData(meshData, meshes);
                var result = stream.ToNativeArray <DedicatedNodeInfo>(Allocator.Temp);
                var nodes  = new NativeMultiHashMap <int, DedicatedNodeInfo>(graphData.Length, Allocator.Temp);
                for (int i = 0; i < result.Length; i++)
                {
                    nodes.Add(result[i].graphIndex, result[i]);
                }
                stream.Dispose();
                submeshes.Dispose();
                int index        = 0;
                var nodeEntities = new NativeList <Entity>(Allocator.Temp);
                Entities.ForEach((UIObject obj) =>
                {
                    if (!string.IsNullOrEmpty(obj.cachedGuid))
                    {
                        var entity = GetPrimaryEntity(obj);
                        var gd     = graphDataArray[index];
                        DstEntityManager.AddComponentData(entity, new UIGraph {
                            value = new BlittableAssetReference(obj.cachedGuid)
                        });
                        DstEntityManager.AddSharedComponentData <UIDirtyState>(entity, false);
                        Material material;
                        if (gd.TryGetConfigBlock(0, UIConfigLayoutTable.MaterialConfig, out IntPtr result))
                        {
                            material = UnityEditor.AssetDatabase.LoadAssetAtPath <Material>(UnityEditor.AssetDatabase.GUIDToAssetPath(((MaterialConfig *)(result.ToPointer()))->material.ToHex()));
                        }
                        else
                        {
                            material = obj.model.GetMaterial();
                        }



                        DeclareAssetDependency(obj.gameObject, obj.model);


                        DeclareAssetDependency(obj.gameObject, material);

                        DstEntityManager.AddSharedComponentData(entity, new RenderMesh
                        {
                            mesh                 = meshes[index],
                            material             = material,
                            subMesh              = 0,
                            castShadows          = ShadowCastingMode.Off,
                            receiveShadows       = false,
                            needMotionVectorPass = false,
                            layer                = obj.gameObject.layer
                        });
                        DstEntityManager.AddComponentData(entity, new UIPixelScale {
                            value = obj.pixelScale
                        });
                        var bounds = meshes[index].GetSubMesh(0).bounds.ToAABB();
                        DstEntityManager.AddComponentData(entity, new RenderBounds {
                            Value = bounds
                        });

                        DstEntityManager.AddComponent <UIContext>(entity);

                        if (obj.camera != null)
                        {
                            DstEntityManager.AddComponentData(entity, new UIContextSource {
                                value = GetPrimaryEntity(obj.camera)
                            });
                            var ltc = new LocalToCamera
                            {
                                cameraLTW = obj.camera.transform.localToWorldMatrix,
                                clipPlane = new float2(obj.camera.nearClipPlane, obj.camera.farClipPlane),
                                alignment = obj.alignment,
                                offsetX   = obj.offsetX,
                                offsetY   = obj.offsetY
                            };
                            DstEntityManager.AddComponentData(entity, ltc);
                            var rotation  = quaternion.LookRotation(ltc.cameraLTW.c2.xyz, ltc.cameraLTW.c1.xyz);
                            var translate = ltc.cameraLTW.c3.xyz + new float3(ltc.alignment.GetOffset(bounds.Size.xy, new float2(Screen.currentResolution.height * obj.camera.aspect, Screen.currentResolution.height)), 0) + math.mul(rotation, math.forward() * ltc.clipPlane.x * 2f) + (math.mul(rotation, math.right()) * ltc.offsetX.Normalize(contexts[index])) + (math.mul(rotation, math.up()) * ltc.offsetY.Normalize(contexts[index]));
                            DstEntityManager.SetComponentData(entity, new LocalToWorld {
                                Value = float4x4.TRS(translate, rotation, obj.pixelScale)
                            });
                            DeclareDependency(obj, obj.camera);
                        }

                        DstEntityManager.AddComponent <PerInstanceCullingTag>(entity);

                        nodeEntities.Clear();
                        var nodeInfoIter = nodes.GetValuesForKey(index);
                        while (nodeInfoIter.MoveNext())
                        {
                            var nodeInfo   = nodeInfoIter.Current;
                            var nodeEntity = CreateAdditionalEntity(obj);
                            var name       = graphData[index].GetNodeName(nodeInfo.nodeIndex);
                            if (string.IsNullOrEmpty(name))
                            {
                                name = $"Node#{nodeInfo.nodeIndex}";
                            }
                            DstEntityManager.SetName(nodeEntity, $"{DstEntityManager.GetName(entity)}[{name}]");
                            DstEntityManager.AddComponentData(nodeEntity, new UINodeInfo {
                                index = nodeInfo.nodeIndex, submesh = nodeInfo.submesh
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new UIParent {
                                value = entity
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new Parent {
                                Value = entity
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new LocalToWorld {
                                Value = float4x4.identity
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new Rotation {
                                Value = quaternion.identity
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new Scale {
                                Value = 1f
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new LocalToParent {
                                Value = float4x4.identity
                            });
                            if (gd.TryGetConfigBlock(0, UIConfigLayoutTable.MaterialConfig, out result))
                            {
                                material = UnityEditor.AssetDatabase.LoadAssetAtPath <Material>(UnityEditor.AssetDatabase.GUIDToAssetPath(((MaterialConfig *)result.ToPointer())->material.ToHex()));
                            }
                            else
                            {
                                material = obj.model.GetMaterial();
                            }
                            DstEntityManager.AddSharedComponentData(nodeEntity, new RenderMesh
                            {
                                mesh                 = meshes[index],
                                material             = material,
                                subMesh              = nodeInfo.submesh,
                                castShadows          = ShadowCastingMode.Off,
                                receiveShadows       = false,
                                needMotionVectorPass = false,
                                layer                = obj.gameObject.layer
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new RenderBounds {
                                Value = meshes[index].GetSubMesh(nodeInfo.submesh).bounds.ToAABB()
                            });
                            DstEntityManager.AddComponent <PerInstanceCullingTag>(nodeEntity);
                            nodeEntities.Add(nodeEntity);
                            ConfigureEditorRenderData(nodeEntity, obj.gameObject, true);
                        }
                        var buffer = DstEntityManager.AddBuffer <UINode>(entity);
                        buffer.AddRange(nodeEntities.AsArray().Reinterpret <UINode>());
                        UnsafeUtility.Free(graphData[index].value.ToPointer(), Allocator.TempJob);
                        index++;
                        ConfigureEditorRenderData(entity, obj.gameObject, true);
                    }
                });
            }

            contexts.Dispose();
            graphData.Dispose();
        }
        public void TreeOverlapPerfTest(int elementCount, bool newOverlap)
        {
            // Execute dummy job just to get Burst compilation out of the way.
            {
                var dummyStream  = new NativeStream(1, Allocator.TempJob);
                var dummyNodes   = new NativeArray <Node>(0, Allocator.TempJob);
                var dummyFilters = new NativeArray <CollisionFilter>(0, Allocator.TempJob);
                new TestTreeOverlapJob
                {
                    CollisionPairWriter = dummyStream.AsWriter(),
                    Nodes      = dummyNodes,
                    Filter     = dummyFilters,
                    NumObjects = 0,
                    DummyRun   = true
                }.Run();
                dummyStream.Dispose();
                dummyNodes.Dispose();
                dummyFilters.Dispose();
            }

            elementCount *= 2;
            int numNodes = elementCount / 3 * 2 + 4;
            var points   = new NativeArray <PointAndIndex>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var aabbs    = new NativeArray <Aabb>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var filters  = new NativeArray <CollisionFilter>(elementCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            // Override filter data with default filters.
            for (int i = 0; i < filters.Length; i++)
            {
                filters[i] = CollisionFilter.Default;
            }

            InitInputWithCopyArrays(points, aabbs, filters);

            var nodes = new NativeArray <Node>(numNodes, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            var bvh = new BoundingVolumeHierarchy(nodes);

            bvh.Build(points, aabbs, out int numNodesOut);
            bvh.CheckIntegrity();

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

            var job = new TestTreeOverlapJob
            {
                Nodes               = nodes,
                Filter              = filters,
                NumObjects          = elementCount,
                CollisionPairWriter = collisionPairs.AsWriter(),
                DummyRun            = false
            };

            Measure.Method(() =>
            {
                job.Run();
            }).MeasurementCount(1)
            .Run();

            points.Dispose();
            aabbs.Dispose();
            nodes.Dispose();
            collisionPairs.Dispose();
            filters.Dispose();
        }
        /// <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();
        }
        public unsafe void BuildTreeAndOverlapTasks([Values(2, 10, 33, 100)] int elementCount)
        {
            const int threadCount = 8;

            elementCount *= 2;

            var tree = new Broadphase.Tree(elementCount);

            var points      = new NativeArray <PointAndIndex>(elementCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
            var aabbs       = new NativeArray <Aabb>(elementCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
            var branchCount = new NativeArray <int>(1, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            InitInputWithCopyArrays(points, aabbs, tree.BodyFilters);

            // Override filter data with default filters.
            for (int i = 0; i < tree.BodyFilters.Length; i++)
            {
                tree.BodyFilters[i] = CollisionFilter.Default;
            }

            for (int i = 0; i < tree.NodeFilters.Length; i++)
            {
                tree.NodeFilters[i] = CollisionFilter.Default;
            }

            var branchNodeOffset = new NativeArray <int>(Constants.MaxNumTreeBranches, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
            var shouldDoWork     = new NativeArray <int>(1, Allocator.Persistent);

            shouldDoWork[0] = 1;
            NativeArray <int> oldBranchCount = new NativeArray <int>(1, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            JobHandle handle = new BuildFirstNLevelsJob
            {
                Points            = points,
                Nodes             = (Node *)tree.Nodes.GetUnsafePtr(),
                Ranges            = tree.Ranges,
                BranchNodeOffsets = branchNodeOffset,
                BranchCount       = branchCount,
                OldBranchCount    = oldBranchCount,
                ThreadCount       = threadCount,
                ShouldDoWork      = shouldDoWork
            }.Schedule();

            handle = new BuildBranchesJob
            {
                Points            = points,
                Aabbs             = aabbs,
                BodyFilters       = tree.BodyFilters,
                Nodes             = (Node *)tree.Nodes.GetUnsafePtr(),
                Ranges            = tree.Ranges,
                BranchNodeOffsets = branchNodeOffset,
                BranchCount       = branchCount
            }.ScheduleUnsafeIndex0(branchCount, 1, handle);

            new FinalizeTreeJob
            {
                Aabbs             = aabbs,
                LeafFilters       = tree.BodyFilters,
                Nodes             = (Node *)tree.Nodes.GetUnsafePtr(),
                BranchNodeOffsets = branchNodeOffset,
                NumNodes          = tree.Nodes.Length,
                BranchCount       = branchCount,
                ShouldDoWork      = shouldDoWork,
                OldBranchCount    = oldBranchCount
            }.Schedule(handle).Complete();

            int numBranchOverlapPairs = branchCount[0] * (branchCount[0] + 1) / 2;
            var nodePairIndices       = new NativeList <int2>(Allocator.TempJob);

            nodePairIndices.ResizeUninitialized(numBranchOverlapPairs);
            var collisionPairs = new NativeStream(numBranchOverlapPairs, Allocator.TempJob);

            handle = new Broadphase.DynamicVsDynamicBuildBranchNodePairsJob
            {
                Ranges          = tree.Ranges,
                NumBranches     = branchCount,
                NodePairIndices = nodePairIndices
            }.Schedule();

            handle = new Broadphase.DynamicVsDynamicFindOverlappingPairsJob
            {
                DynamicTree     = tree,
                NodePairIndices = nodePairIndices,
                PairWriter      = collisionPairs.AsWriter()
            }.Schedule(nodePairIndices, numBranchOverlapPairs, handle);

            handle.Complete();

            int numPairs = collisionPairs.Count();

            Assert.AreEqual(elementCount / 2, numPairs);
            //Debug.Log($"Num colliding pairs: {numPairs}");

            tree.BoundingVolumeHierarchy.CheckIntegrity();

            nodePairIndices.Dispose();
            tree.Dispose();
            collisionPairs.Dispose();
            branchCount.Dispose();
            shouldDoWork.Dispose();
        }
Ejemplo n.º 28
0
        // Schedule a set of jobs which will write all overlapping body pairs to the given steam,
        // where at least one of the bodies is dynamic. The results are unsorted.
        internal JobHandle ScheduleFindOverlapsJobs(out NativeStream dynamicVsDynamicPairsStream, out NativeStream staticVsDynamicPairsStream, ref Simulation.Context context, JobHandle inputDeps)
        {
            var dynamicVsDynamicNodePairIndices = new NativeList <int2>(Allocator.TempJob);
            var staticVsDynamicNodePairIndices  = new NativeList <int2>(Allocator.TempJob);

            JobHandle allocateDeps = new AllocateDynamicVsStaticNodePairs
            {
                dynamicVsDynamicNodePairIndices = dynamicVsDynamicNodePairIndices,
                staticVsDynamicNodePairIndices  = staticVsDynamicNodePairIndices,
                dynamicBranchCount = m_DynamicTree.m_BranchCount,
                staticBranchCount  = m_StaticTree.m_BranchCount
            }.Schedule(inputDeps);

            // Build pairs of branch node indices
            JobHandle dynamicVsDynamicPairs = new DynamicVsDynamicBuildBranchNodePairsJob
            {
                Ranges          = m_DynamicTree.Ranges,
                NumBranches     = m_DynamicTree.m_BranchCount,
                NodePairIndices = dynamicVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(allocateDeps);

            JobHandle staticVsDynamicPairs = new StaticVsDynamicBuildBranchNodePairsJob
            {
                DynamicRanges      = m_DynamicTree.Ranges,
                StaticRanges       = m_StaticTree.Ranges,
                NumStaticBranches  = m_StaticTree.m_BranchCount,
                NumDynamicBranches = m_DynamicTree.m_BranchCount,
                NodePairIndices    = staticVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(allocateDeps);

            //@TODO: We only need a dependency on allocateDeps, but the safety system doesn't understand that we can not change length list in DynamicVsDynamicBuildBranchNodePairsJob & StaticVsDynamicBuildBranchNodePairsJob
            //       if this is a performance issue we can use [NativeDisableContainerSafetyRestriction] on DynamicVsDynamicBuildBranchNodePairsJob & StaticVsDynamicBuildBranchNodePairsJob
            JobHandle dynamicConstruct = NativeStream.ScheduleConstruct(out dynamicVsDynamicPairsStream, dynamicVsDynamicNodePairIndices, dynamicVsDynamicPairs, Allocator.TempJob);
            JobHandle staticConstruct  = NativeStream.ScheduleConstruct(out staticVsDynamicPairsStream, staticVsDynamicNodePairIndices, staticVsDynamicPairs, Allocator.TempJob);

            // Write all overlaps to the stream (also deallocates nodePairIndices)
            JobHandle dynamicVsDynamicHandle = new DynamicVsDynamicFindOverlappingPairsJob
            {
                DynamicNodes       = m_DynamicTree.Nodes,
                BodyFilters        = m_BodyFilters,
                DynamicNodeFilters = m_DynamicTree.NodeFilters,
                PairWriter         = dynamicVsDynamicPairsStream.AsWriter(),
                NodePairIndices    = dynamicVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(dynamicVsDynamicNodePairIndices, 1, JobHandle.CombineDependencies(dynamicVsDynamicPairs, dynamicConstruct));

            // Write all overlaps to the stream (also deallocates nodePairIndices)
            JobHandle staticVsDynamicHandle = new StaticVsDynamicFindOverlappingPairsJob
            {
                StaticNodes        = m_StaticTree.Nodes,
                DynamicNodes       = m_DynamicTree.Nodes,
                BodyFilters        = m_BodyFilters,
                StaticNodeFilters  = m_StaticTree.NodeFilters,
                DynamicNodeFilters = m_DynamicTree.NodeFilters,
                PairWriter         = staticVsDynamicPairsStream.AsWriter(),
                NodePairIndices    = staticVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(staticVsDynamicNodePairIndices, 1, JobHandle.CombineDependencies(staticVsDynamicPairs, staticConstruct));

            // Dispose node pair lists
            context.DisposeOverlapPairs0 = NativeListUtilityTemp.DisposeHotFix(ref dynamicVsDynamicNodePairIndices, dynamicVsDynamicHandle);
            context.DisposeOverlapPairs1 = NativeListUtilityTemp.DisposeHotFix(ref staticVsDynamicNodePairIndices, staticVsDynamicHandle);

            return(JobHandle.CombineDependencies(dynamicVsDynamicHandle, staticVsDynamicHandle));
        }
 public DotsFrameTrace(Allocator allocator)
 {
     NativeStream = new NativeStream(1, allocator);
     _writer      = NativeStream.AsWriter();
     _writer.BeginForEachIndex(0);
 }
Ejemplo n.º 30
0
        // Schedule a set of jobs which will write all overlapping body pairs to the given steam,
        // where at least one of the bodies is dynamic. The results are unsorted.
        public SimulationJobHandles ScheduleFindOverlapsJobs(out NativeStream dynamicVsDynamicPairsStream, out NativeStream staticVsDynamicPairsStream,
                                                             JobHandle inputDeps, int threadCountHint = 0)
        {
            SimulationJobHandles returnHandles = default;

            if (threadCountHint <= 0)
            {
                dynamicVsDynamicPairsStream        = new NativeStream(1, Allocator.TempJob);
                staticVsDynamicPairsStream         = new NativeStream(1, Allocator.TempJob);
                returnHandles.FinalExecutionHandle = new FindOverlapsJob
                {
                    Broadphase = this,
                    DynamicVsDynamicPairsWriter = dynamicVsDynamicPairsStream.AsWriter(),
                    StaticVsDynamicPairsWriter  = staticVsDynamicPairsStream.AsWriter()
                }.Schedule(inputDeps);

                return(returnHandles);
            }

            var dynamicVsDynamicNodePairIndices = new NativeList <int2>(Allocator.TempJob);
            var staticVsDynamicNodePairIndices  = new NativeList <int2>(Allocator.TempJob);

            JobHandle allocateDeps = new AllocateDynamicVsStaticNodePairs
            {
                dynamicVsDynamicNodePairIndices = dynamicVsDynamicNodePairIndices,
                staticVsDynamicNodePairIndices  = staticVsDynamicNodePairIndices,
                dynamicBranchCount = m_DynamicTree.BranchCount,
                staticBranchCount  = m_StaticTree.BranchCount
            }.Schedule(inputDeps);

            // Build pairs of branch node indices
            JobHandle dynamicVsDynamicPairs = new DynamicVsDynamicBuildBranchNodePairsJob
            {
                Ranges          = m_DynamicTree.Ranges,
                NumBranches     = m_DynamicTree.BranchCount,
                NodePairIndices = dynamicVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(allocateDeps);

            JobHandle staticVsDynamicPairs = new StaticVsDynamicBuildBranchNodePairsJob
            {
                DynamicRanges      = m_DynamicTree.Ranges,
                StaticRanges       = m_StaticTree.Ranges,
                NumStaticBranches  = m_StaticTree.BranchCount,
                NumDynamicBranches = m_DynamicTree.BranchCount,
                NodePairIndices    = staticVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(allocateDeps);

            //@TODO: We only need a dependency on allocateDeps, but the safety system doesn't understand that we can not change length list in DynamicVsDynamicBuildBranchNodePairsJob & StaticVsDynamicBuildBranchNodePairsJob
            //       if this is a performance issue we can use [NativeDisableContainerSafetyRestriction] on DynamicVsDynamicBuildBranchNodePairsJob & StaticVsDynamicBuildBranchNodePairsJob
            JobHandle dynamicConstruct = NativeStream.ScheduleConstruct(out dynamicVsDynamicPairsStream, dynamicVsDynamicNodePairIndices, dynamicVsDynamicPairs, Allocator.TempJob);
            JobHandle staticConstruct  = NativeStream.ScheduleConstruct(out staticVsDynamicPairsStream, staticVsDynamicNodePairIndices, staticVsDynamicPairs, Allocator.TempJob);

            // Write all overlaps to the stream (also deallocates nodePairIndices)
            JobHandle dynamicVsDynamicHandle = new DynamicVsDynamicFindOverlappingPairsJob
            {
                DynamicTree     = m_DynamicTree,
                PairWriter      = dynamicVsDynamicPairsStream.AsWriter(),
                NodePairIndices = dynamicVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(dynamicVsDynamicNodePairIndices, 1, JobHandle.CombineDependencies(dynamicVsDynamicPairs, dynamicConstruct));

            // Write all overlaps to the stream (also deallocates nodePairIndices)
            JobHandle staticVsDynamicHandle = new StaticVsDynamicFindOverlappingPairsJob
            {
                StaticTree      = m_StaticTree,
                DynamicTree     = m_DynamicTree,
                PairWriter      = staticVsDynamicPairsStream.AsWriter(),
                NodePairIndices = staticVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(staticVsDynamicNodePairIndices, 1, JobHandle.CombineDependencies(staticVsDynamicPairs, staticConstruct));

            // Dispose node pair lists
            var disposeOverlapPairs0 = NativeListUtilityTemp.DisposeHotFix(ref dynamicVsDynamicNodePairIndices, dynamicVsDynamicHandle);
            var disposeOverlapPairs1 = NativeListUtilityTemp.DisposeHotFix(ref staticVsDynamicNodePairIndices, staticVsDynamicHandle);

            returnHandles.FinalDisposeHandle   = JobHandle.CombineDependencies(disposeOverlapPairs0, disposeOverlapPairs1);
            returnHandles.FinalExecutionHandle = JobHandle.CombineDependencies(dynamicVsDynamicHandle, staticVsDynamicHandle);

            return(returnHandles);
        }