// Resets the simulation storage // - Reallocates input velocities storage if necessary // - Disposes event streams and allocates new ones with a single work item // NOTE: Reset or ScheduleReset needs to be called before passing the SimulationContext // to a simulation step job. If you don't then you may get initialization errors. public void Reset(ref PhysicsWorld world) { m_Bodies = world.Bodies; int numDynamicBodies = world.NumDynamicBodies; if (InputVelocities.Length < numDynamicBodies) { if (InputVelocities.IsCreated) { InputVelocities.Dispose(); } InputVelocities = new NativeArray <Velocity>(numDynamicBodies, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); } if (CollisionEventDataStream.IsCreated) { CollisionEventDataStream.Dispose(); } if (TriggerEventDataStream.IsCreated) { TriggerEventDataStream.Dispose(); } { if (!WorkItemCount.IsCreated) { WorkItemCount = new NativeArray <int>(new int[] { 1 }, Allocator.Persistent); } CollisionEventDataStream = new NativeStream(WorkItemCount[0], Allocator.Persistent); TriggerEventDataStream = new NativeStream(WorkItemCount[0], Allocator.Persistent); } }
protected override void OnDestroy() { base.OnDestroy(); if (_effectStream.IsCreated) { _effectStream.Dispose(Dependency); } if (_effects.IsCreated) { _effects.Dispose(Dependency); } }
// Resets the simulation storage // - Reallocates input velocities storage if necessary // - Disposes event streams and allocates new ones with a single work item // NOTE: Reset or ScheduleReset needs to be called before passing the SimulationContext // to a simulation step job. If you don't then you may get initialization errors. public void Reset(SimulationStepInput stepInput) { m_NumDynamicBodies = stepInput.World.NumDynamicBodies; if (!m_InputVelocities.IsCreated || m_InputVelocities.Length < m_NumDynamicBodies) { if (m_InputVelocities.IsCreated) { m_InputVelocities.Dispose(); } m_InputVelocities = new NativeArray <Velocity>(m_NumDynamicBodies, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); } // Solver stabilization data if (stepInput.SolverStabilizationHeuristicSettings.EnableSolverStabilization) { if (!m_SolverStabilizationMotionData.IsCreated || m_SolverStabilizationMotionData.Length < m_NumDynamicBodies) { if (m_SolverStabilizationMotionData.IsCreated) { m_SolverStabilizationMotionData.Dispose(); } m_SolverStabilizationMotionData = new NativeArray <Solver.StabilizationMotionData>(m_NumDynamicBodies, Allocator.Persistent, NativeArrayOptions.ClearMemory); } else if (m_NumDynamicBodies > 0) { unsafe { UnsafeUtility.MemClear(m_SolverStabilizationMotionData.GetUnsafePtr(), m_NumDynamicBodies * UnsafeUtility.SizeOf <Solver.StabilizationMotionData>()); } } } if (CollisionEventDataStream.IsCreated) { CollisionEventDataStream.Dispose(); } if (TriggerEventDataStream.IsCreated) { TriggerEventDataStream.Dispose(); } { if (!WorkItemCount.IsCreated) { WorkItemCount = new NativeArray <int>(new int[] { 1 }, Allocator.Persistent); } CollisionEventDataStream = new NativeStream(WorkItemCount[0], Allocator.Persistent); TriggerEventDataStream = new NativeStream(WorkItemCount[0], Allocator.Persistent); } }
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(); }
public void Dispose() { if (m_Stream.IsCreated) { m_Stream.Dispose(); } }
public void Dispose() { if (NativeStream.IsCreated) { NativeStream.Dispose(); } }
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); }
public void WriteWithoutBeginThrows() { var stream = new NativeStream(1, Allocator.Temp); var writer = stream.AsWriter(); Assert.Throws <ArgumentException>(() => writer.Write(5)); stream.Dispose(); }
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); }
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(); }
public void CreateAndDestroy([Values(1, 100, 200)] int count) { var stream = new NativeStream(count, Allocator.Temp); Assert.IsTrue(stream.IsCreated); Assert.IsTrue(stream.ForEachCount == count); Assert.IsTrue(stream.ComputeItemCount() == 0); stream.Dispose(); Assert.IsFalse(stream.IsCreated); }
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(); }
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); }
public void Dispose() { if (PixelData.IsCreated) { PixelData.Dispose(); } //reset isCreated PixelData = default; m_Assigned = false; m_JobHandle = default; }
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(); }
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(); }
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 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(); }
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(); }
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(); }
// 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); }
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 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(); }
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(); }
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(); }
public void Dispose() { NativeStream.Dispose(); }
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 Dispose() { PixelData.Dispose(); // setting default will reset PixelData.IsCreated PixelData = default; }