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); } } } } } } }
public void Execute() { while (movingParticles.Count > 0) { MovingEntity movingParticle = movingParticles.Dequeue(); // remove from old cell: int cellIndex; if (grid.TryGetCellIndex(movingParticle.oldCellCoord, out cellIndex)) { var oldCell = grid.usedCells[cellIndex]; oldCell.Remove(movingParticle.entity); grid.usedCells[cellIndex] = oldCell; } // add to new cell: cellIndex = grid.GetOrCreateCell(movingParticle.newCellCoord); var newCell = grid.usedCells[cellIndex]; newCell.Add(movingParticle.entity); grid.usedCells[cellIndex] = newCell; } grid.RemoveEmpty(); }
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 currentA = 0; int currentB = 0; int lastA = previousActiveParticles.Length; int lastB = activeParticles.Length; NativeList <int> inactive = new NativeList <int>(math.max(lastA, lastB), Allocator.Temp); // perform a set difference to find particles rendered inactive since last update: while (currentA != lastA && currentB != lastB) { if (previousActiveParticles[currentA] < activeParticles[currentB]) { inactive.Add(previousActiveParticles[currentA++]); } else if (activeParticles[currentB] < previousActiveParticles[currentA]) { ++currentB; } else { ++currentA; ++currentB; } } // copy remaining elements: for (int i = currentA; i < lastA; ++i) { inactive.Add(previousActiveParticles[i]); } // remove these particles from their current cell: for (int i = 0; i < inactive.Length; ++i) { int cellIndex; if (grid.TryGetCellIndex(cellCoords[inactive[i]], out cellIndex)) { var oldCell = grid.usedCells[cellIndex]; oldCell.Remove(inactive[i]); grid.usedCells[cellIndex] = oldCell; // set their current cell coord to an invalid value: cellCoords[inactive[i]] = new int4(int.MaxValue); } } }
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 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); } } } }