// Iterate over all colliders and store those whose cell span has changed. public void Execute(int i) { float size = bounds[i].AverageAxisLength(); int level = NativeMultilevelGrid <int> .GridLevelForSize(size); float cellSize = NativeMultilevelGrid <int> .CellSizeOfLevel(level); // get new collider bounds cell coordinates: BurstCellSpan newSpan = new BurstCellSpan(new int4(GridHash.Quantize(bounds[i].min.xyz, cellSize), level), new int4(GridHash.Quantize(bounds[i].max.xyz, cellSize), level)); // if the collider is 2D, project it to the z = 0 cells. if (colliders[i].is2D != 0) { newSpan.min[2] = 0; newSpan.max[2] = 0; } // if the collider is at the tail (removed), we will only remove it from its current cellspan. // if the new cellspan and the current one are different, we must remove it from its current cellspan and add it to its new one. if (i >= colliderCount || cellIndices[i] != newSpan) { // Add the collider to the list of moving colliders: movingColliders.Enqueue(new MovingCollider() { oldSpan = cellIndices[i], newSpan = newSpan, entity = i }); // Update previous coords: cellIndices[i] = newSpan; } }
public ParticleGrid() { this.grid = new NativeMultilevelGrid <int>(1000, Allocator.Persistent); this.movingParticles = new NativeQueue <MovingEntity>(Allocator.Persistent); this.particleContactQueue = new NativeQueue <BurstContact>(Allocator.Persistent); this.fluidInteractionQueue = new NativeQueue <FluidInteraction>(Allocator.Persistent); this.previousActiveParticles = new NativeArray <int>(0, Allocator.Persistent); }
public void Awake() { this.grid = new NativeMultilevelGrid <int>(1000, Allocator.Persistent); this.movingColliders = new NativeQueue <MovingCollider>(Allocator.Persistent); this.colliderContactQueue = new NativeQueue <BurstContact>(Allocator.Persistent); this.cellSpans = new ObiNativeCellSpanList(); ObiColliderWorld.GetInstance().RegisterImplementation(this); }
private void IntraLevelSearch(int cellIndex) { int4 cellCoords = grid.usedCells[cellIndex].Coords; // neighboring cells in the current level: for (int i = 0; i < 13; ++i) { int4 neighborCellCoords = new int4(cellCoords.xyz + GridHash.cellOffsets3D[i], cellCoords.w); int neighborCellIndex; if (grid.TryGetCellIndex(neighborCellCoords, out neighborCellIndex)) { InterCellSearch(cellIndex, neighborCellIndex); } } // neighboring cells in levels above the current one: int levelIndex = gridLevels.IndexOf <int, int>(cellCoords.w); if (levelIndex >= 0) { levelIndex++; for (; levelIndex < gridLevels.Length; ++levelIndex) { int level = gridLevels[levelIndex]; // calculate index of parent cell in parent level: int4 parentCellCoords = NativeMultilevelGrid <int> .GetParentCellCoords(cellCoords, level); // search in all neighbouring cells: for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { for (int z = -1; z <= 1; ++z) { int4 neighborCellCoords = parentCellCoords + new int4(x, y, z, 0); int neighborCellIndex; if (grid.TryGetCellIndex(neighborCellCoords, out neighborCellIndex)) { InterCellSearch(cellIndex, neighborCellIndex); } } } } } } }
// Iterate over all colliders and store those whose cell span has changed. public void Execute(int i) { BurstAabb velocityBounds = bounds[i]; // Expand bounds by rigidbody's linear velocity: if (shapes[i].rigidbodyIndex >= 0) { velocityBounds.Sweep(rigidbodies[shapes[i].rigidbodyIndex].velocity * dt); } // Expand bounds by collision material's stick distance: if (shapes[i].materialIndex >= 0) { velocityBounds.Expand(collisionMaterials[shapes[i].materialIndex].stickDistance); } float size = velocityBounds.AverageAxisLength(); int level = NativeMultilevelGrid <int> .GridLevelForSize(size); float cellSize = NativeMultilevelGrid <int> .CellSizeOfLevel(level); // get new collider bounds cell coordinates: BurstCellSpan newSpan = new BurstCellSpan(new int4(GridHash.Quantize(velocityBounds.min.xyz, cellSize), level), new int4(GridHash.Quantize(velocityBounds.max.xyz, cellSize), level)); // if the collider is 2D, project it to the z = 0 cells. if (shapes[i].is2D != 0) { newSpan.min[2] = 0; newSpan.max[2] = 0; } // if the collider is at the tail (removed), we will only remove it from its current cellspan. // if the new cellspan and the current one are different, we must remove it from its current cellspan and add it to its new one. if (i >= colliderCount || cellIndices[i] != newSpan) { // Add the collider to the list of moving colliders: movingColliders.Enqueue(new MovingCollider() { oldSpan = cellIndices[i], newSpan = newSpan, entity = i }); // Update previous coords: cellIndices[i] = newSpan; } }
public void GetCells(ObiNativeAabbList cells) { if (cells.count == grid.usedCells.Length) { for (int i = 0; i < grid.usedCells.Length; ++i) { var cell = grid.usedCells[i]; float size = NativeMultilevelGrid <int> .CellSizeOfLevel(cell.Coords.w); float4 min = (float4)cell.Coords * size; min[3] = 0; cells[i] = new Aabb(min, min + new float4(size, size, size, 0)); } } }
public void Execute(int i) { int level = NativeMultilevelGrid <int> .GridLevelForSize(simplexBounds[i].AverageAxisLength()); float cellSize = NativeMultilevelGrid <int> .CellSizeOfLevel(level); // get new particle cell coordinate: int4 newCellCoord = new int4(GridHash.Quantize(simplexBounds[i].center.xyz, cellSize), level); // if the solver is 2D, project the particle to the z = 0 cell. if (is2D) { newCellCoord[2] = 0; } cellCoords[i] = newCellCoord; }
public void Execute(int index) { int i = activeParticles[index]; // Find this particle's stick distance: float stickDistance = 0; if (particleMaterialIndices[i] >= 0) { stickDistance = collisionMaterials[particleMaterialIndices[i]].stickDistance; } // Use it (together with radius and fluid radius) to calculate its size in the grid. float size = radii[i].x * 2.2f + stickDistance; size = math.max(size, fluidRadii[i] * 1.1f); int level = NativeMultilevelGrid <int> .GridLevelForSize(size); float cellSize = NativeMultilevelGrid <int> .CellSizeOfLevel(level); // get new particle cell coordinate: int4 newCellCoord = new int4(GridHash.Quantize(positions[i].xyz, cellSize), level); // if the solver is 2D, project the particle to the z = 0 cell. if (is2D) { newCellCoord[2] = 0; } // if the current cell is different from the current one, the particle has changed cell. if (!newCellCoord.Equals(cellCoord[i])) { movingParticles.Enqueue(new MovingEntity() { oldCellCoord = cellCoord[i], newCellCoord = newCellCoord, entity = i }); cellCoord[i] = newCellCoord; } }
private void GetCandidatesForBoundsAtLevel(NativeList <int> candidates, BurstAabb cellBounds, int level, bool is2D = false, int maxSize = 10) { float cellSize = NativeMultilevelGrid <int> .CellSizeOfLevel(level); int3 minCell = GridHash.Quantize(cellBounds.min.xyz, cellSize); int3 maxCell = GridHash.Quantize(cellBounds.max.xyz, cellSize); maxCell = minCell + math.min(maxCell - minCell, new int3(maxSize)); int3 size = maxCell - minCell + new int3(1); int cellIndex; for (int x = minCell[0]; x <= maxCell[0]; ++x) { for (int y = minCell[1]; y <= maxCell[1]; ++y) { // for 2D mode, project each cell at z == 0 and check them too. This way we ensure 2D colliders // (which are inserted in cells with z == 0) are accounted for in the broadphase. if (is2D) { if (colliderGrid.TryGetCellIndex(new int4(x, y, 0, level), out cellIndex)) { var colliderCell = colliderGrid.usedCells[cellIndex]; candidates.AddRange(colliderCell.ContentsPointer, colliderCell.Length); } } for (int z = minCell[2]; z <= maxCell[2]; ++z) { if (colliderGrid.TryGetCellIndex(new int4(x, y, z, level), out cellIndex)) { var colliderCell = colliderGrid.usedCells[cellIndex]; candidates.AddRange(colliderCell.ContentsPointer, colliderCell.Length); } } } } }
public void Execute(int p) { neighbourCount[p] = 0; float4 diffuseProperty = float4.zero; float kernelSum = 0; int offsetCount = mode2D ? 4 : 8; float4 solverDiffusePosition = inertialFrame.frame.InverseTransformPoint(diffusePositions[p]); for (int k = 0; k < gridLevels.Length; ++k) { int l = gridLevels[k]; float radius = NativeMultilevelGrid <int> .CellSizeOfLevel(l); float4 cellCoords = math.floor(solverDiffusePosition / radius); cellCoords[3] = 0; if (mode2D) { cellCoords[2] = 0; } float4 posInCell = solverDiffusePosition - (cellCoords * radius + new float4(radius * 0.5f)); int4 quadrant = (int4)math.sign(posInCell); quadrant[3] = l; for (int i = 0; i < offsetCount; ++i) { int cellIndex; if (grid.TryGetCellIndex((int4)cellCoords + cellOffsets[i] * quadrant, out cellIndex)) { var cell = grid.usedCells[cellIndex]; for (int n = 0; n < cell.Length; ++n) { float4 r = solverDiffusePosition - positions[cell[n]]; r[3] = 0; if (mode2D) { r[2] = 0; } float d = math.length(r); if (d <= radius) { float w = densityKernel.W(d, radius); kernelSum += w; diffuseProperty += properties[cell[n]] * w; neighbourCount[p]++; } } } } } if (kernelSum > BurstMath.epsilon) { diffuseProperties[p] = diffuseProperty / kernelSum; } }
public ParticleGrid() { this.grid = new NativeMultilevelGrid <int>(1000, Allocator.Persistent); this.particleContactQueue = new NativeQueue <BurstContact>(Allocator.Persistent); this.fluidInteractionQueue = new NativeQueue <FluidInteraction>(Allocator.Persistent); }
public void Execute(int i) { int simplexStart = simplexCounts.GetSimplexStartAndSize(i, out int simplexSize); BurstAabb simplexBoundsSS = simplexBounds[i]; // get all colliders overlapped by the cell bounds, in all grid levels: BurstAabb simplexBoundsWS = simplexBoundsSS.Transformed(solverToWorld); NativeList <int> candidates = new NativeList <int>(Allocator.Temp); // max size of the particle bounds in cells: int3 maxSize = new int3(10); bool is2D = parameters.mode == Oni.SolverParameters.Mode.Mode2D; for (int l = 0; l < gridLevels.Length; ++l) { float cellSize = NativeMultilevelGrid <int> .CellSizeOfLevel(gridLevels[l]); int3 minCell = GridHash.Quantize(simplexBoundsWS.min.xyz, cellSize); int3 maxCell = GridHash.Quantize(simplexBoundsWS.max.xyz, cellSize); maxCell = minCell + math.min(maxCell - minCell, maxSize); for (int x = minCell[0]; x <= maxCell[0]; ++x) { for (int y = minCell[1]; y <= maxCell[1]; ++y) { // for 2D mode, project each cell at z == 0 and check them too. This way we ensure 2D colliders // (which are inserted in cells with z == 0) are accounted for in the broadphase. if (is2D) { if (colliderGrid.TryGetCellIndex(new int4(x, y, 0, gridLevels[l]), out int cellIndex)) { var colliderCell = colliderGrid.usedCells[cellIndex]; candidates.AddRange(colliderCell.ContentsPointer, colliderCell.Length); } } for (int z = minCell[2]; z <= maxCell[2]; ++z) { if (colliderGrid.TryGetCellIndex(new int4(x, y, z, gridLevels[l]), out int cellIndex)) { var colliderCell = colliderGrid.usedCells[cellIndex]; candidates.AddRange(colliderCell.ContentsPointer, colliderCell.Length); } } } } } if (candidates.Length > 0) { // make sure each candidate collider only shows up once in the array: NativeArray <int> uniqueCandidates = candidates.AsArray(); uniqueCandidates.Sort(); int uniqueCount = uniqueCandidates.Unique(); // iterate over candidate colliders, generating contacts for each one for (int k = 0; k < uniqueCount; ++k) { int c = uniqueCandidates[k]; BurstColliderShape shape = shapes[c]; BurstAabb colliderBoundsWS = bounds[c]; // Expand bounds by rigidbody's linear velocity: if (shape.rigidbodyIndex >= 0) { colliderBoundsWS.Sweep(rigidbodies[shape.rigidbodyIndex].velocity * deltaTime); } // Expand bounds by collision material's stick distance: if (shape.materialIndex >= 0) { colliderBoundsWS.Expand(collisionMaterials[shape.materialIndex].stickDistance); } // check if any simplex particle and the collider have the same phase: bool samePhase = false; for (int j = 0; j < simplexSize; ++j) { samePhase |= shape.phase == (phases[simplices[simplexStart + j]] & (int)Oni.ParticleFlags.GroupMask); } if (!samePhase && simplexBoundsWS.IntersectsAabb(in colliderBoundsWS, is2D)) { // generate contacts for the collider: BurstAffineTransform colliderToSolver = worldToSolver * transforms[c]; GenerateContacts(in shape, in colliderToSolver, c, i, simplexStart, simplexSize, simplexBoundsSS); } } } }