升级obi
This commit is contained in:
@@ -4,6 +4,7 @@ using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
@@ -20,34 +21,14 @@ namespace Obi
|
||||
public NativeQueue<BurstContact> particleContactQueue;
|
||||
public NativeQueue<FluidInteraction> fluidInteractionQueue;
|
||||
|
||||
|
||||
[BurstCompile]
|
||||
struct CalculateCellCoords : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<BurstAabb> simplexBounds;
|
||||
public NativeArray<int4> cellCoords;
|
||||
[ReadOnly] public bool is2D;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct UpdateGrid : IJob
|
||||
{
|
||||
public NativeMultilevelGrid<int> grid;
|
||||
[ReadOnly] public NativeArray<int4> cellCoords;
|
||||
[ReadOnly] public NativeArray<BurstAabb> simplexBounds;
|
||||
public NativeArray<int4> cellCoords;
|
||||
|
||||
[ReadOnly] public Oni.SolverParameters parameters;
|
||||
[ReadOnly] public int simplexCount;
|
||||
|
||||
public void Execute()
|
||||
@@ -56,6 +37,17 @@ namespace Obi
|
||||
|
||||
for (int i = 0; i < simplexCount; ++i)
|
||||
{
|
||||
int level = NativeMultilevelGrid<int>.GridLevelForSize(simplexBounds[i].MaxAxisLength());
|
||||
float cellSize = NativeMultilevelGrid<int>.CellSizeOfLevel(level);
|
||||
|
||||
// get new cell coordinate:
|
||||
int4 newCellCoord = new int4(GridHash.Quantize(simplexBounds[i].center.xyz, cellSize), level);
|
||||
|
||||
// if the solver is 2D, project to the z = 0 cell.
|
||||
if (parameters.mode == Oni.SolverParameters.Mode.Mode2D) newCellCoord[2] = 0;
|
||||
|
||||
cellCoords[i] = newCellCoord;
|
||||
|
||||
// add to new cell:
|
||||
int cellIndex = grid.GetOrCreateCell(cellCoords[i]);
|
||||
var newCell = grid.usedCells[cellIndex];
|
||||
@@ -69,6 +61,7 @@ namespace Obi
|
||||
public struct GenerateParticleParticleContactsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeMultilevelGrid<int> grid;
|
||||
|
||||
[DeallocateOnJobCompletion]
|
||||
[ReadOnly] public NativeArray<int> gridLevels;
|
||||
|
||||
@@ -80,14 +73,13 @@ namespace Obi
|
||||
[ReadOnly] public NativeArray<float> invMasses;
|
||||
[ReadOnly] public NativeArray<float4> radii;
|
||||
[ReadOnly] public NativeArray<float4> normals;
|
||||
[ReadOnly] public NativeArray<float> fluidRadii;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials;
|
||||
[ReadOnly] public NativeArray<int> phases;
|
||||
[ReadOnly] public NativeArray<int> filters;
|
||||
|
||||
// simplex arrays:
|
||||
[ReadOnly] public NativeArray<int> simplices;
|
||||
[ReadOnly] public SimplexCounts simplexCounts;
|
||||
[ReadOnly] public NativeArray<BurstAabb> simplexBounds;
|
||||
|
||||
[ReadOnly] public NativeArray<int> particleMaterialIndices;
|
||||
[ReadOnly] public NativeArray<BurstCollisionMaterial> collisionMaterials;
|
||||
@@ -165,7 +157,7 @@ namespace Obi
|
||||
}
|
||||
|
||||
// neighboring cells in levels above the current one:
|
||||
int levelIndex = gridLevels.IndexOf<int,int>(cellCoords.w);
|
||||
int levelIndex = gridLevels.IndexOf<int, int>(cellCoords.w);
|
||||
if (levelIndex >= 0)
|
||||
{
|
||||
levelIndex++;
|
||||
@@ -202,10 +194,10 @@ namespace Obi
|
||||
for (int j = 0; j < simplexSize; ++j)
|
||||
{
|
||||
int particleIndex = simplices[simplexStart + j];
|
||||
group = math.max(group, ObiUtils.GetGroupFromPhase(phases[particleIndex]));
|
||||
flags |= ObiUtils.GetFlagsFromPhase(phases[particleIndex]);
|
||||
category |= filters[particleIndex] & ObiUtils.FilterCategoryBitmask;
|
||||
mask |= (filters[particleIndex] & ObiUtils.FilterMaskBitmask) >> 16;
|
||||
group = math.max(group, ObiUtils.GetGroupFromPhase(phases[particleIndex]));
|
||||
restPositionsEnabled |= restPositions[particleIndex].w > 0.5f;
|
||||
}
|
||||
|
||||
@@ -214,10 +206,6 @@ namespace Obi
|
||||
|
||||
private void InteractionTest(int A, int B, ref BurstSimplex simplexShape)
|
||||
{
|
||||
// skip the pair if their bounds don't intersect:
|
||||
if (!simplexBounds[A].IntersectsAabb(simplexBounds[B]))
|
||||
return;
|
||||
|
||||
// get the start index and size of each simplex:
|
||||
int simplexStartA = simplexCounts.GetSimplexStartAndSize(A, out int simplexSizeA);
|
||||
int simplexStartB = simplexCounts.GetSimplexStartAndSize(B, out int simplexSizeB);
|
||||
@@ -247,17 +235,14 @@ namespace Obi
|
||||
// if all simplices are fluid, check their smoothing radii:
|
||||
if ((flagsA & ObiUtils.ParticleFlags.Fluid) != 0 && (flagsB & ObiUtils.ParticleFlags.Fluid) != 0)
|
||||
{
|
||||
// for fluid we only consider the first particle in each simplex.
|
||||
int particleA = simplices[simplexStartA];
|
||||
int particleB = simplices[simplexStartB];
|
||||
|
||||
// for fluid we only consider the first particle in each simplex.
|
||||
float4 predictedPositionA = positions[particleA] + velocities[particleA] * dt;
|
||||
float4 predictedPositionB = positions[particleB] + velocities[particleB] * dt;
|
||||
|
||||
// Calculate particle center distance:
|
||||
float d2 = math.lengthsq(predictedPositionA - predictedPositionB);
|
||||
float d2 = math.lengthsq(positions[particleA].xyz - positions[particleB].xyz);
|
||||
|
||||
float fluidDistance = math.max(fluidRadii[particleA], fluidRadii[particleB]);
|
||||
float fluidDistance = math.max(fluidMaterials[particleA].x, fluidMaterials[particleB].x) + collisionMargin;
|
||||
if (d2 <= fluidDistance * fluidDistance)
|
||||
{
|
||||
fluidInteractionsQueue.Enqueue(new FluidInteraction { particleA = particleA, particleB = particleB });
|
||||
@@ -299,7 +284,7 @@ namespace Obi
|
||||
|
||||
// compare distance along contact normal with radius.
|
||||
if (math.dot(simplexPoint - restPoint.point, restPoint.normal) < simplexRadiusA + simplexRadiusB)
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
simplexBary = BurstMath.BarycenterForSimplexOfSize(simplexSizeA);
|
||||
@@ -310,13 +295,16 @@ namespace Obi
|
||||
simplices, simplexStartA, simplexSizeA, ref simplexBary, out simplexPoint, optimizationIterations, optimizationTolerance);
|
||||
|
||||
simplexRadiusA = 0; simplexRadiusB = 0;
|
||||
float4 velocityA = float4.zero, velocityB = float4.zero, normalB = float4.zero;
|
||||
float4 velocityA = float4.zero, velocityB = float4.zero, normalA = float4.zero, normalB = float4.zero;
|
||||
float invMassA = 0, invMassB = 0;
|
||||
|
||||
for (int j = 0; j < simplexSizeA; ++j)
|
||||
{
|
||||
int particleIndex = simplices[simplexStartA + j];
|
||||
simplexRadiusA += radii[particleIndex].x * simplexBary[j];
|
||||
velocityA += velocities[particleIndex] * simplexBary[j];
|
||||
normalA += (normals[particleIndex].w < 0 ? new float4(math.rotate(orientations[particleIndex],normals[particleIndex].xyz), normals[particleIndex].w) : normals[particleIndex]) * simplexBary[j];
|
||||
invMassA += invMasses[particleIndex] * simplexBary[j];
|
||||
}
|
||||
|
||||
for (int j = 0; j < simplexSizeB; ++j)
|
||||
@@ -324,111 +312,53 @@ namespace Obi
|
||||
int particleIndex = simplices[simplexStartB + j];
|
||||
simplexRadiusB += radii[particleIndex].x * surfacePoint.bary[j];
|
||||
velocityB += velocities[particleIndex] * surfacePoint.bary[j];
|
||||
normalB += normals[particleIndex] * surfacePoint.bary[j];
|
||||
normalB += (normals[particleIndex].w < 0 ? new float4(math.rotate(orientations[particleIndex], normals[particleIndex].xyz), normals[particleIndex].w) : normals[particleIndex]) * surfacePoint.bary[j];
|
||||
invMassB += invMasses[particleIndex] * simplexBary[j];
|
||||
}
|
||||
|
||||
// no contact between fixed simplices:
|
||||
//if (!(invMassA > 0 || invMassB > 0))
|
||||
// return;
|
||||
|
||||
float dAB = math.dot(simplexPoint - surfacePoint.point, surfacePoint.normal);
|
||||
float vel = math.dot(velocityA - velocityB, surfacePoint.normal);
|
||||
float vel = math.dot(velocityA - velocityB, surfacePoint.normal);
|
||||
|
||||
// check if the projected velocity along the contact normal will get us within collision distance.
|
||||
if (vel * dt + dAB <= simplexRadiusA + simplexRadiusB + collisionMargin)
|
||||
{
|
||||
// adapt collision normal for one-sided simplices:
|
||||
if ((flagsB & ObiUtils.ParticleFlags.OneSided) != 0 && categoryA < categoryB)
|
||||
BurstMath.OneSidedNormal(normalB, ref surfacePoint.normal);
|
||||
BurstMath.OneSidedNormal(normalB, ref surfacePoint.normal);
|
||||
|
||||
contactsQueue.Enqueue(new BurstContact()
|
||||
// during inter-collision, if either particle contains SDF data and they overlap:
|
||||
if (groupA != groupB && (normalB.w < 0 || normalA.w < 0) && dAB * 1.05f <= simplexRadiusA + simplexRadiusB)
|
||||
{
|
||||
// as normal, pick SDF gradient belonging to least penetration distance:
|
||||
float4 nij = normalB;
|
||||
if (normalB.w >= 0 || (normalA.w < 0 && normalB.w < normalA.w))
|
||||
nij = new float4(-normalA.xyz, normalA.w);
|
||||
|
||||
// for boundary particles, use one sided sphere normal:
|
||||
if (math.abs(nij.w) <= math.max(simplexRadiusA, simplexRadiusB) * 1.5f)
|
||||
BurstMath.OneSidedNormal(nij, ref surfacePoint.normal);
|
||||
else
|
||||
surfacePoint.normal = nij;
|
||||
}
|
||||
|
||||
surfacePoint.normal.w = 0;
|
||||
contactsQueue.Enqueue(new BurstContact
|
||||
{
|
||||
bodyA = A,
|
||||
bodyB = B,
|
||||
pointA = simplexBary,
|
||||
pointB = surfacePoint.bary,
|
||||
normal = surfacePoint.normal
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct InterpolateDiffusePropertiesJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeMultilevelGrid<int> grid;
|
||||
|
||||
[DeallocateOnJobCompletion]
|
||||
[ReadOnly] public NativeArray<int4> cellOffsets;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> properties;
|
||||
[ReadOnly] public NativeArray<float4> diffusePositions;
|
||||
[ReadOnly] public Poly6Kernel densityKernel;
|
||||
|
||||
public NativeArray<float4> diffuseProperties;
|
||||
public NativeArray<int> neighbourCount;
|
||||
|
||||
[DeallocateOnJobCompletion]
|
||||
[ReadOnly] public NativeArray<int> gridLevels;
|
||||
|
||||
[ReadOnly] public BurstInertialFrame inertialFrame;
|
||||
[ReadOnly] public bool mode2D;
|
||||
|
||||
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);
|
||||
@@ -436,22 +366,15 @@ namespace Obi
|
||||
this.fluidInteractionQueue = new NativeQueue<FluidInteraction>(Allocator.Persistent);
|
||||
}
|
||||
|
||||
public void Update(BurstSolverImpl solver, float deltaTime, JobHandle inputDeps)
|
||||
public void Update(BurstSolverImpl solver, JobHandle inputDeps)
|
||||
{
|
||||
var calculateCells = new CalculateCellCoords
|
||||
{
|
||||
simplexBounds = solver.simplexBounds,
|
||||
cellCoords = solver.cellCoords,
|
||||
is2D = solver.abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D,
|
||||
};
|
||||
|
||||
inputDeps = calculateCells.Schedule(solver.simplexCounts.simplexCount, 4, inputDeps);
|
||||
|
||||
var updateGrid = new UpdateGrid
|
||||
{
|
||||
grid = grid,
|
||||
simplexBounds = solver.simplexBounds,
|
||||
simplexCount = solver.simplexCounts.simplexCount,
|
||||
cellCoords = solver.cellCoords,
|
||||
simplexCount = solver.simplexCounts.simplexCount
|
||||
parameters = solver.abstraction.parameters
|
||||
};
|
||||
updateGrid.Schedule(inputDeps).Complete();
|
||||
}
|
||||
@@ -472,13 +395,12 @@ namespace Obi
|
||||
invMasses = solver.invMasses,
|
||||
radii = solver.principalRadii,
|
||||
normals = solver.normals,
|
||||
fluidRadii = solver.smoothingRadii,
|
||||
fluidMaterials = solver.fluidMaterials,
|
||||
phases = solver.phases,
|
||||
filters = solver.filters,
|
||||
|
||||
simplices = solver.simplices,
|
||||
simplexCounts = solver.simplexCounts,
|
||||
simplexBounds = solver.simplexBounds,
|
||||
|
||||
particleMaterialIndices = solver.abstraction.collisionMaterials.AsNativeArray<int>(),
|
||||
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
|
||||
@@ -494,49 +416,11 @@ namespace Obi
|
||||
return generateParticleContactsJob.Schedule(grid.CellCount, 1);
|
||||
}
|
||||
|
||||
public JobHandle InterpolateDiffuseProperties(BurstSolverImpl solver,
|
||||
NativeArray<float4> properties,
|
||||
NativeArray<float4> diffusePositions,
|
||||
NativeArray<float4> diffuseProperties,
|
||||
NativeArray<int> neighbourCount,
|
||||
int diffuseCount)
|
||||
{
|
||||
|
||||
NativeArray<int4> offsets = new NativeArray<int4>(8, Allocator.TempJob);
|
||||
offsets[0] = new int4(0, 0, 0, 1);
|
||||
offsets[1] = new int4(1, 0, 0, 1);
|
||||
offsets[2] = new int4(0, 1, 0, 1);
|
||||
offsets[3] = new int4(1, 1, 0, 1);
|
||||
offsets[4] = new int4(0, 0, 1, 1);
|
||||
offsets[5] = new int4(1, 0, 1, 1);
|
||||
offsets[6] = new int4(0, 1, 1, 1);
|
||||
offsets[7] = new int4(1, 1, 1, 1);
|
||||
|
||||
var interpolateDiffusePropertiesJob = new InterpolateDiffusePropertiesJob
|
||||
{
|
||||
grid = grid,
|
||||
positions = solver.abstraction.positions.AsNativeArray<float4>(),
|
||||
cellOffsets = offsets,
|
||||
properties = properties,
|
||||
diffusePositions = diffusePositions,
|
||||
diffuseProperties = diffuseProperties,
|
||||
neighbourCount = neighbourCount,
|
||||
densityKernel = new Poly6Kernel(solver.abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
|
||||
gridLevels = grid.populatedLevels.GetKeyArray(Allocator.TempJob),
|
||||
inertialFrame = solver.inertialFrame,
|
||||
mode2D = solver.abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D
|
||||
};
|
||||
|
||||
return interpolateDiffusePropertiesJob.Schedule(diffuseCount, 64);
|
||||
}
|
||||
|
||||
public JobHandle SpatialQuery(BurstSolverImpl solver,
|
||||
NativeArray<BurstQueryShape> shapes,
|
||||
NativeArray<BurstAffineTransform> transforms,
|
||||
NativeQueue<BurstQueryResult> results)
|
||||
{
|
||||
var world = ObiColliderWorld.GetInstance();
|
||||
|
||||
var job = new SpatialQueryJob
|
||||
{
|
||||
grid = grid,
|
||||
|
||||
Reference in New Issue
Block a user