// 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);
 }
Exemple #3
0
        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);
                                    }
                                }
                            }
                        }
                    }
                }
            }
Exemple #5
0
            // 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));
                }
            }
        }
Exemple #7
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;
                }
            }
Exemple #11
0
 public ParticleGrid()
 {
     this.grid = new NativeMultilevelGrid <int>(1000, Allocator.Persistent);
     this.particleContactQueue  = new NativeQueue <BurstContact>(Allocator.Persistent);
     this.fluidInteractionQueue = new NativeQueue <FluidInteraction>(Allocator.Persistent);
 }
Exemple #12
0
            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);
                        }
                    }
                }
            }