修改水
This commit is contained in:
@@ -24,16 +24,16 @@ namespace Obi
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public BurstAabb(float4 v1, float4 v2, float4 v3, float4 margin)
|
||||
public BurstAabb(float4 v1, float4 v2, float4 v3, float margin)
|
||||
{
|
||||
min = math.min(math.min(v1, v2), v3) - margin;
|
||||
max = math.max(math.max(v1, v2), v3) + margin;
|
||||
min = math.min(math.min(v1, v2), v3) - new float4(margin, margin, margin, 0);
|
||||
max = math.max(math.max(v1, v2), v3) + new float4(margin, margin, margin, 0);
|
||||
}
|
||||
|
||||
public BurstAabb(float4 v1, float4 v2, float4 margin)
|
||||
public BurstAabb(float2 v1, float2 v2, float margin)
|
||||
{
|
||||
min = math.min(v1, v2) - margin;
|
||||
max = math.max(v1, v2) + margin;
|
||||
min = new float4(math.min(v1, v2) - new float2(margin, margin),0,0);
|
||||
max = new float4(math.max(v1, v2) + new float2(margin, margin),0,0);
|
||||
}
|
||||
|
||||
public BurstAabb(float4 previousPosition, float4 position, float radius)
|
||||
@@ -50,7 +50,7 @@ namespace Obi
|
||||
|
||||
public float MaxAxisLength()
|
||||
{
|
||||
return math.cmax((max - min).xyz);
|
||||
return math.cmax(max - min);
|
||||
}
|
||||
|
||||
public void EncapsulateParticle(float4 position, float radius)
|
||||
|
||||
@@ -36,13 +36,6 @@ namespace Obi
|
||||
1 / scale);
|
||||
}
|
||||
|
||||
public BurstAffineTransform Integrate(float4 linearVelocity, float4 angularVelocity, float dt)
|
||||
{
|
||||
return new BurstAffineTransform(BurstIntegration.IntegrateLinear(translation, linearVelocity, dt),
|
||||
BurstIntegration.IntegrateAngular(rotation, angularVelocity, dt),
|
||||
scale);
|
||||
}
|
||||
|
||||
public BurstAffineTransform Interpolate(BurstAffineTransform other, float translationalMu, float rotationalMu, float scaleMu)
|
||||
{
|
||||
return new BurstAffineTransform(math.lerp(translation, other.translation, translationalMu),
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Obi
|
||||
|
||||
switch (frictionCombineMode)
|
||||
{
|
||||
default: // average
|
||||
case Oni.MaterialCombineMode.Average:
|
||||
result.dynamicFriction = (a.dynamicFriction + b.dynamicFriction) * 0.5f;
|
||||
result.staticFriction = (a.staticFriction + b.staticFriction) * 0.5f;
|
||||
result.rollingFriction = (a.rollingFriction + b.rollingFriction) * 0.5f;
|
||||
@@ -37,22 +37,22 @@ namespace Obi
|
||||
result.rollingFriction = math.min(a.rollingFriction, b.rollingFriction);
|
||||
break;
|
||||
|
||||
case Oni.MaterialCombineMode.Multiply:
|
||||
result.dynamicFriction = a.dynamicFriction * b.dynamicFriction;
|
||||
result.staticFriction = a.staticFriction * b.staticFriction;
|
||||
result.rollingFriction = a.rollingFriction * b.rollingFriction;
|
||||
break;
|
||||
|
||||
case Oni.MaterialCombineMode.Maximum:
|
||||
result.dynamicFriction = math.max(a.dynamicFriction, b.dynamicFriction);
|
||||
result.staticFriction = math.max(a.staticFriction, b.staticFriction);
|
||||
result.rollingFriction = math.max(a.rollingFriction, b.rollingFriction);
|
||||
break;
|
||||
|
||||
case Oni.MaterialCombineMode.Multiply:
|
||||
result.dynamicFriction = a.dynamicFriction * b.dynamicFriction;
|
||||
result.staticFriction = a.staticFriction * b.staticFriction;
|
||||
result.rollingFriction = a.rollingFriction * b.rollingFriction;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (stickCombineMode)
|
||||
{
|
||||
default: // average
|
||||
case Oni.MaterialCombineMode.Average:
|
||||
result.stickiness = (a.stickiness + b.stickiness) * 0.5f;
|
||||
break;
|
||||
|
||||
@@ -60,13 +60,13 @@ namespace Obi
|
||||
result.stickiness = math.min(a.stickiness, b.stickiness);
|
||||
break;
|
||||
|
||||
case Oni.MaterialCombineMode.Multiply:
|
||||
result.stickiness = a.stickiness * b.stickiness;
|
||||
break;
|
||||
|
||||
case Oni.MaterialCombineMode.Maximum:
|
||||
result.stickiness = math.max(a.stickiness, b.stickiness);
|
||||
break;
|
||||
|
||||
case Oni.MaterialCombineMode.Multiply:
|
||||
result.stickiness = a.stickiness * b.stickiness;
|
||||
break;
|
||||
}
|
||||
|
||||
result.stickDistance = math.max(a.stickDistance, b.stickDistance);
|
||||
|
||||
@@ -38,11 +38,6 @@ namespace Obi
|
||||
angularAcceleration = float4.zero;
|
||||
}
|
||||
|
||||
public float4 VelocityAtPoint(float4 point)
|
||||
{
|
||||
return velocity + new float4(math.cross(angularVelocity.xyz, (point - prevFrame.translation).xyz), 0);
|
||||
}
|
||||
|
||||
public void Update(float4 position, float4 scale, quaternion rotation, float dt)
|
||||
{
|
||||
prevFrame = frame;
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using System.Collections.Generic;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstPrefixSum
|
||||
{
|
||||
private int inputSize;
|
||||
private const int numBlocks = 8;
|
||||
|
||||
private NativeArray<int> blockSums;
|
||||
|
||||
public BurstPrefixSum(int inputSize)
|
||||
{
|
||||
this.inputSize = inputSize;
|
||||
blockSums = new NativeArray<int>(numBlocks, Allocator.Persistent);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (blockSums.IsCreated)
|
||||
blockSums.Dispose();
|
||||
}
|
||||
|
||||
public unsafe JobHandle Sum(NativeArray<int> input, NativeArray<int> result, int* count, JobHandle inputDeps)
|
||||
{
|
||||
|
||||
// calculate partial prefix sums, one per block:
|
||||
var job = new BlockSumJob
|
||||
{
|
||||
input = input,
|
||||
output = result,
|
||||
blocks = blockSums,
|
||||
count = count
|
||||
};
|
||||
inputDeps = job.Schedule(numBlocks, 1, inputDeps);
|
||||
|
||||
var job3 = new BlockSum
|
||||
{
|
||||
blocks = blockSums
|
||||
};
|
||||
inputDeps = job3.Schedule(inputDeps);
|
||||
|
||||
// add the scanned partial block sums to the result:
|
||||
var job2 = new PrefixSumJob
|
||||
{
|
||||
prefixBlocks = blockSums,
|
||||
output = result,
|
||||
count = count
|
||||
};
|
||||
return job2.Schedule(numBlocks, 1, inputDeps);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
unsafe struct BlockSumJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> input;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> output;
|
||||
public NativeArray<int> blocks;
|
||||
|
||||
[ReadOnly] [NativeDisableUnsafePtrRestriction] public int* count;
|
||||
|
||||
public void Execute(int block)
|
||||
{
|
||||
int length = *count + 1; // add 1 to get total sum in last element+1
|
||||
int blockSize = (int)math.ceil(length / (float)numBlocks);
|
||||
|
||||
int start = block * blockSize;
|
||||
int end = math.min(start + blockSize, length);
|
||||
|
||||
output[start] = 0;
|
||||
|
||||
if (blockSize == 0) { blocks[block] = 0; return; }
|
||||
|
||||
for (int i = start + 1; i < end; ++i)
|
||||
output[i] = output[i - 1] + input[i - 1];
|
||||
|
||||
blocks[block] = output[end - 1] + input[end - 1];
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct BlockSum : IJob
|
||||
{
|
||||
public NativeArray<int> blocks;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
int aux = blocks[0];
|
||||
blocks[0] = 0;
|
||||
|
||||
for (int i = 1; i < blocks.Length; ++i)
|
||||
{
|
||||
int a = blocks[i];
|
||||
blocks[i] = blocks[i - 1] + aux;
|
||||
aux = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
unsafe struct PrefixSumJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> prefixBlocks;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> output;
|
||||
|
||||
[ReadOnly] [NativeDisableUnsafePtrRestriction] public int* count;
|
||||
|
||||
public void Execute(int block)
|
||||
{
|
||||
int length = *count + 1; // add 1 to get total sum in last element+1
|
||||
int blockSize = (int)math.ceil(length / (float)numBlocks);
|
||||
|
||||
int start = block * blockSize;
|
||||
int end = math.min(start + blockSize, length);
|
||||
|
||||
for (int i = start; i < end; ++i)
|
||||
output[i] += prefixBlocks[block];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fa11563c202445279d5e04b0eb1631b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -9,7 +9,7 @@ namespace Obi
|
||||
public float4 size;
|
||||
public QueryShape.QueryType type;
|
||||
public float contactOffset;
|
||||
public float maxDistance;
|
||||
public float distance;
|
||||
public int filter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Obi
|
||||
public float4 com;
|
||||
public float inverseMass;
|
||||
|
||||
public int constraintCount;
|
||||
private int pad0;
|
||||
private int pad1;
|
||||
private int pad2;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
@@ -9,7 +9,7 @@ using Unity.Jobs;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class ConstraintSorter<T> where T : unmanaged, IConstraint
|
||||
public class ConstraintSorter<T> where T : unmanaged, IConstraint
|
||||
{
|
||||
|
||||
public struct ConstraintComparer<K> : IComparer<K> where K : IConstraint
|
||||
@@ -28,7 +28,7 @@ namespace Obi
|
||||
public JobHandle SortConstraints(int particleCount,
|
||||
NativeArray<T> constraints,
|
||||
ref NativeArray<T> sortedConstraints,
|
||||
JobHandle handle)
|
||||
JobHandle handle)
|
||||
{
|
||||
// Count the amount of digits in the largest particle index that can be referenced by a constraint:
|
||||
NativeArray<int> totalCountUpToDigit = new NativeArray<int>(particleCount + 1, Allocator.TempJob);
|
||||
@@ -59,16 +59,16 @@ namespace Obi
|
||||
{
|
||||
InOutArray = sortedConstraints,
|
||||
NextElementIndex = totalCountUpToDigit,
|
||||
comparer = new ConstraintComparer<T>()
|
||||
comparer = new ConstraintComparer<T>()
|
||||
}.Schedule(totalCountUpToDigit.Length, numPerBatch, handle);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct CountSortPerFirstParticleJob : IJob
|
||||
public struct CountSortPerFirstParticleJob : IJob
|
||||
{
|
||||
[ReadOnly][NativeDisableContainerSafetyRestriction] public NativeArray<T> input;
|
||||
[ReadOnly] [NativeDisableContainerSafetyRestriction] public NativeArray<T> input;
|
||||
public NativeArray<T> output;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] public NativeArray<int> digitCount;
|
||||
@@ -117,7 +117,7 @@ namespace Obi
|
||||
[NativeDisableContainerSafetyRestriction] public NativeArray<T> InOutArray;
|
||||
|
||||
// Typically lastDigitIndex is resulting RadixSortPerBodyAJob.digitCount. nextElementIndex[i] = index of first element with bodyA index == i + 1
|
||||
[NativeDisableContainerSafetyRestriction][DeallocateOnJobCompletion] public NativeArray<int> NextElementIndex;
|
||||
[NativeDisableContainerSafetyRestriction] [DeallocateOnJobCompletion] public NativeArray<int> NextElementIndex;
|
||||
|
||||
[ReadOnly] public ConstraintComparer<T> comparer;
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
namespace Obi
|
||||
using System;
|
||||
|
||||
public interface IConstraint
|
||||
{
|
||||
public interface IConstraint
|
||||
{
|
||||
int GetParticleCount();
|
||||
int GetParticle(int index);
|
||||
}
|
||||
int GetParticleCount();
|
||||
int GetParticle(int index);
|
||||
}
|
||||
#endif
|
||||
@@ -1,76 +1,118 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
public struct GridHash
|
||||
{
|
||||
public struct GridHash
|
||||
public readonly static int3[] cellOffsets3D =
|
||||
{
|
||||
public readonly static int3[] cellOffsets3D =
|
||||
{
|
||||
new int3(1,0,0),
|
||||
new int3(0,1,0),
|
||||
new int3(1,1,0),
|
||||
new int3(0,0,1),
|
||||
new int3(1,0,1),
|
||||
new int3(0,1,1),
|
||||
new int3(1,1,1),
|
||||
new int3(-1,1,0),
|
||||
new int3(-1,-1,1),
|
||||
new int3(0,-1,1),
|
||||
new int3(1,-1,1),
|
||||
new int3(-1,0,1),
|
||||
new int3(-1,1,1)
|
||||
};
|
||||
new int3(1,0,0),
|
||||
new int3(0,1,0),
|
||||
new int3(1,1,0),
|
||||
new int3(0,0,1),
|
||||
new int3(1,0,1),
|
||||
new int3(0,1,1),
|
||||
new int3(1,1,1),
|
||||
new int3(-1,1,0),
|
||||
new int3(-1,-1,1),
|
||||
new int3(0,-1,1),
|
||||
new int3(1,-1,1),
|
||||
new int3(-1,0,1),
|
||||
new int3(-1,1,1)
|
||||
};
|
||||
|
||||
public readonly static int3[] cellOffsets =
|
||||
{
|
||||
new int3(0, 0, 0),
|
||||
new int3(-1, 0, 0),
|
||||
new int3(0, -1, 0),
|
||||
new int3(0, 0, -1),
|
||||
new int3(1, 0, 0),
|
||||
new int3(0, 1, 0),
|
||||
new int3(0, 0, 1)
|
||||
};
|
||||
public readonly static int3[] cellOffsets =
|
||||
{
|
||||
new int3(0, 0, 0),
|
||||
new int3(-1, 0, 0),
|
||||
new int3(0, -1, 0),
|
||||
new int3(0, 0, -1),
|
||||
new int3(1, 0, 0),
|
||||
new int3(0, 1, 0),
|
||||
new int3(0, 0, 1)
|
||||
};
|
||||
|
||||
public readonly static int2[] cell2DOffsets =
|
||||
{
|
||||
new int2(0, 0),
|
||||
new int2(-1, 0),
|
||||
new int2(0, -1),
|
||||
new int2(1, 0),
|
||||
new int2(0, 1),
|
||||
};
|
||||
public readonly static int2[] cell2DOffsets =
|
||||
{
|
||||
new int2(0, 0),
|
||||
new int2(-1, 0),
|
||||
new int2(0, -1),
|
||||
new int2(1, 0),
|
||||
new int2(0, 1),
|
||||
};
|
||||
|
||||
public static int3 Quantize(float3 v, float cellSize)
|
||||
public static int Hash(float3 v, float cellSize)
|
||||
{
|
||||
return Hash(Quantize(v, cellSize));
|
||||
}
|
||||
|
||||
public static int3 Quantize(float3 v, float cellSize)
|
||||
{
|
||||
return new int3(math.floor(v / cellSize));
|
||||
}
|
||||
|
||||
public static int Hash(float2 v, float cellSize)
|
||||
{
|
||||
return Hash(Quantize(v, cellSize));
|
||||
}
|
||||
|
||||
public static int2 Quantize(float2 v, float cellSize)
|
||||
{
|
||||
return new int2(math.floor(v / cellSize));
|
||||
}
|
||||
|
||||
public static int Hash(int3 grid)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return new int3(math.floor(v / cellSize));
|
||||
// Simple int3 hash based on a pseudo mix of :
|
||||
// 1) https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||
// 2) https://en.wikipedia.org/wiki/Jenkins_hash_function
|
||||
int hash = grid.x;
|
||||
hash = (hash * 397) ^ grid.y;
|
||||
hash = (hash * 397) ^ grid.z;
|
||||
hash += hash << 3;
|
||||
hash ^= hash >> 11;
|
||||
hash += hash << 15;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int2 Quantize(float2 v, float cellSize)
|
||||
public static int Hash(int2 grid)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return new int2(math.floor(v / cellSize));
|
||||
// Simple int3 hash based on a pseudo mix of :
|
||||
// 1) https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||
// 2) https://en.wikipedia.org/wiki/Jenkins_hash_function
|
||||
int hash = grid.x;
|
||||
hash = (hash * 397) ^ grid.y;
|
||||
hash += hash << 3;
|
||||
hash ^= hash >> 11;
|
||||
hash += hash << 15;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Hash(in int4 cellIndex, int maxCells)
|
||||
{
|
||||
const int p1 = 73856093;
|
||||
const int p2 = 19349663;
|
||||
const int p3 = 83492791;
|
||||
const int p4 = 10380569;
|
||||
return math.abs(p1 * cellIndex.x ^ p2 * cellIndex.y ^ p3 * cellIndex.z ^ p4 * cellIndex.w) % maxCells;
|
||||
}
|
||||
public static ulong Hash(ulong hash, ulong key)
|
||||
{
|
||||
const ulong m = 0xc6a4a7935bd1e995UL;
|
||||
const int r = 47;
|
||||
|
||||
public static int Hash(in int3 cellIndex, int maxCells)
|
||||
{
|
||||
const int p1 = 73856093;
|
||||
const int p2 = 19349663;
|
||||
const int p3 = 83492791;
|
||||
return ((p1 * cellIndex.x ^ p2 * cellIndex.y ^ p3 * cellIndex.z) & 0x7fffffff) % maxCells;
|
||||
ulong h = hash;
|
||||
ulong k = key;
|
||||
|
||||
/*var index = cellIndex - new int3(-32, -32, -32);
|
||||
return index.x + index.y * 64 + index.z * 64 * 64;*/
|
||||
}
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h ^= k;
|
||||
h *= m;
|
||||
|
||||
h ^= h >> r;
|
||||
h *= m;
|
||||
h ^= h >> r;
|
||||
|
||||
return h;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -23,9 +23,7 @@ namespace Obi
|
||||
public unsafe struct NativeMultilevelGrid<T> : IDisposable where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
|
||||
public const float minSize = 0.01f; // minimum cell size is 1 centimeter, enough for very small particles.
|
||||
public const int minLevel = -6; // grid level for minSize.
|
||||
public const int maxLevel = 17;
|
||||
public const float minSize = 0.01f;
|
||||
|
||||
/**
|
||||
* A cell in the multilevel grid. Coords are 4-dimensional, the 4th component is the grid level.
|
||||
@@ -60,7 +58,7 @@ namespace Obi
|
||||
{
|
||||
get
|
||||
{
|
||||
return contents.ElementAt(index);
|
||||
return UnsafeUtility.ReadArrayElement<K>(contents.Ptr, index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +69,11 @@ namespace Obi
|
||||
|
||||
public bool Remove(K entity)
|
||||
{
|
||||
int index = contents.IndexOf(entity);
|
||||
//int index = contents.IndexOf(entity);
|
||||
int index = -1;
|
||||
for (int i = 0; i < contents.Length; ++i)
|
||||
if (contents[i].Equals(entity)) { index = i; break; }
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
contents.RemoveAtSwapBack(index);
|
||||
@@ -86,15 +88,15 @@ namespace Obi
|
||||
}
|
||||
}
|
||||
|
||||
public NativeParallelHashMap<int4, int> grid;
|
||||
public NativeHashMap<int4, int> grid;
|
||||
public NativeList<Cell<T>> usedCells;
|
||||
public NativeParallelHashMap<int, int> populatedLevels;
|
||||
public NativeHashMap<int, int> populatedLevels;
|
||||
|
||||
public NativeMultilevelGrid(int capacity, Allocator label)
|
||||
{
|
||||
grid = new NativeParallelHashMap<int4, int>(capacity, label);
|
||||
grid = new NativeHashMap<int4, int>(capacity, label);
|
||||
usedCells = new NativeList<Cell<T>>(label);
|
||||
populatedLevels = new NativeParallelHashMap<int, int>(10, label);
|
||||
populatedLevels = new NativeHashMap<int, int>(10, label);
|
||||
}
|
||||
|
||||
public int CellCount
|
||||
@@ -170,16 +172,14 @@ namespace Obi
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int GridLevelForSize(float size)
|
||||
{
|
||||
// the magic number is 1/log(2), used because log_a(x) = log_b(x) / log_b(a)
|
||||
// level is clamped between MIN_LEVEL and MAX_LEVEL, then remapped to (0, MAX_LEVEL - MIN_LEVEL)
|
||||
// this allows us to avoid InterlockedMax issues on GPU, since it doesn't work on negative numbers on some APIs.
|
||||
return math.clamp((int)math.ceil(math.log(size) * 1.44269504089f), minLevel, maxLevel) - minLevel;
|
||||
// the magic number is 1/log(2)
|
||||
return (int)math.ceil(math.log(math.max(size,minSize)) * 1.44269504089f);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float CellSizeOfLevel(int level)
|
||||
{
|
||||
return math.exp2(level + minLevel);
|
||||
return math.exp2(level);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,7 +187,7 @@ namespace Obi
|
||||
*/
|
||||
public static int4 GetParentCellCoords(int4 cellCoords, int level)
|
||||
{
|
||||
float decimation = math.exp2(level - cellCoords[3]);
|
||||
float decimation = CellSizeOfLevel(level - cellCoords[3]);
|
||||
int4 cell = (int4)math.floor((float4)cellCoords / decimation);
|
||||
cell[3] = level;
|
||||
return cell;
|
||||
|
||||
@@ -4,7 +4,6 @@ using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
@@ -21,14 +20,34 @@ 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<BurstAabb> simplexBounds;
|
||||
public NativeArray<int4> cellCoords;
|
||||
|
||||
[ReadOnly] public Oni.SolverParameters parameters;
|
||||
[ReadOnly] public NativeArray<int4> cellCoords;
|
||||
[ReadOnly] public int simplexCount;
|
||||
|
||||
public void Execute()
|
||||
@@ -37,17 +56,6 @@ 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];
|
||||
@@ -61,7 +69,6 @@ namespace Obi
|
||||
public struct GenerateParticleParticleContactsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeMultilevelGrid<int> grid;
|
||||
|
||||
[DeallocateOnJobCompletion]
|
||||
[ReadOnly] public NativeArray<int> gridLevels;
|
||||
|
||||
@@ -73,13 +80,14 @@ namespace Obi
|
||||
[ReadOnly] public NativeArray<float> invMasses;
|
||||
[ReadOnly] public NativeArray<float4> radii;
|
||||
[ReadOnly] public NativeArray<float4> normals;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials;
|
||||
[ReadOnly] public NativeArray<float> fluidRadii;
|
||||
[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;
|
||||
@@ -157,7 +165,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++;
|
||||
@@ -194,10 +202,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;
|
||||
}
|
||||
|
||||
@@ -206,6 +214,10 @@ 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);
|
||||
@@ -235,14 +247,17 @@ 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];
|
||||
|
||||
// Calculate particle center distance:
|
||||
float d2 = math.lengthsq(positions[particleA].xyz - positions[particleB].xyz);
|
||||
// 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;
|
||||
|
||||
float fluidDistance = math.max(fluidMaterials[particleA].x, fluidMaterials[particleB].x) + collisionMargin;
|
||||
// Calculate particle center distance:
|
||||
float d2 = math.lengthsq(predictedPositionA - predictedPositionB);
|
||||
|
||||
float fluidDistance = math.max(fluidRadii[particleA], fluidRadii[particleB]);
|
||||
if (d2 <= fluidDistance * fluidDistance)
|
||||
{
|
||||
fluidInteractionsQueue.Enqueue(new FluidInteraction { particleA = particleA, particleB = particleB });
|
||||
@@ -284,7 +299,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);
|
||||
@@ -295,16 +310,13 @@ namespace Obi
|
||||
simplices, simplexStartA, simplexSizeA, ref simplexBary, out simplexPoint, optimizationIterations, optimizationTolerance);
|
||||
|
||||
simplexRadiusA = 0; simplexRadiusB = 0;
|
||||
float4 velocityA = float4.zero, velocityB = float4.zero, normalA = float4.zero, normalB = float4.zero;
|
||||
float invMassA = 0, invMassB = 0;
|
||||
float4 velocityA = float4.zero, velocityB = float4.zero, normalB = float4.zero;
|
||||
|
||||
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)
|
||||
@@ -312,53 +324,111 @@ namespace Obi
|
||||
int particleIndex = simplices[simplexStartB + j];
|
||||
simplexRadiusB += radii[particleIndex].x * surfacePoint.bary[j];
|
||||
velocityB += velocities[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];
|
||||
normalB += normals[particleIndex] * surfacePoint.bary[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);
|
||||
|
||||
// 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
|
||||
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);
|
||||
@@ -366,15 +436,22 @@ namespace Obi
|
||||
this.fluidInteractionQueue = new NativeQueue<FluidInteraction>(Allocator.Persistent);
|
||||
}
|
||||
|
||||
public void Update(BurstSolverImpl solver, JobHandle inputDeps)
|
||||
public void Update(BurstSolverImpl solver, float deltaTime, 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,
|
||||
parameters = solver.abstraction.parameters
|
||||
simplexCount = solver.simplexCounts.simplexCount
|
||||
};
|
||||
updateGrid.Schedule(inputDeps).Complete();
|
||||
}
|
||||
@@ -395,12 +472,13 @@ namespace Obi
|
||||
invMasses = solver.invMasses,
|
||||
radii = solver.principalRadii,
|
||||
normals = solver.normals,
|
||||
fluidMaterials = solver.fluidMaterials,
|
||||
fluidRadii = solver.smoothingRadii,
|
||||
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>(),
|
||||
@@ -416,11 +494,49 @@ 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,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Mathematics;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
@@ -8,25 +9,34 @@ namespace Obi
|
||||
public float4 pointA; // point A, expressed as simplex barycentric coords for simplices, as a solver-space position for colliders.
|
||||
public float4 pointB; // point B, expressed as simplex barycentric coords for simplices, as a solver-space position for colliders.
|
||||
|
||||
public float4 normal; // contact normal on bodyB's surface.
|
||||
public float4 tangent; // contact tangent on bodyB's surface.
|
||||
public float4 normal;
|
||||
public float4 tangent;
|
||||
public float4 bitangent;
|
||||
|
||||
public float distance; // distance between bodyA's and bodyB's surface.
|
||||
public float distance;
|
||||
|
||||
public float normalLambda;
|
||||
public float tangentLambda;
|
||||
public float bitangentLambda;
|
||||
public float stickLambda;
|
||||
public float rollingFrictionImpulse;
|
||||
float normalLambda;
|
||||
float tangentLambda;
|
||||
float bitangentLambda;
|
||||
float stickLambda;
|
||||
float rollingFrictionImpulse;
|
||||
|
||||
public int bodyA;
|
||||
public int bodyB;
|
||||
|
||||
public float normalInvMassA;
|
||||
public float tangentInvMassA;
|
||||
public float bitangentInvMassA;
|
||||
|
||||
public float normalInvMassB;
|
||||
public float tangentInvMassB;
|
||||
public float bitangentInvMassB;
|
||||
|
||||
public double pad0; // padding to ensure correct alignment to 128 bytes.
|
||||
|
||||
public int GetParticleCount() { return 2; }
|
||||
public int GetParticle(int index) { return index == 0 ? bodyA : bodyB; }
|
||||
|
||||
public float4 bitangent => math.normalizesafe(new float4(math.cross(normal.xyz, tangent.xyz), 0));
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return bodyA + "," + bodyB;
|
||||
@@ -40,15 +50,85 @@ namespace Obi
|
||||
return first;
|
||||
}
|
||||
|
||||
public void CalculateTangent(float4 relativeVelocity)
|
||||
public float TotalNormalInvMass
|
||||
{
|
||||
tangent = math.normalizesafe(relativeVelocity - math.dot(relativeVelocity, normal) * normal);
|
||||
get { return normalInvMassA + normalInvMassB; }
|
||||
}
|
||||
|
||||
public float SolveAdhesion(float normalMass, float4 posA, float4 posB, float stickDistance, float stickiness, float dt)
|
||||
public float TotalTangentInvMass
|
||||
{
|
||||
get { return tangentInvMassA + tangentInvMassB; }
|
||||
}
|
||||
|
||||
public float TotalBitangentInvMass
|
||||
{
|
||||
get { return bitangentInvMassA + bitangentInvMassB; }
|
||||
}
|
||||
|
||||
public void CalculateBasis(float4 relativeVelocity)
|
||||
{
|
||||
tangent = math.normalizesafe(relativeVelocity - math.dot(relativeVelocity, normal) * normal);
|
||||
bitangent = math.normalizesafe(new float4(math.cross(normal.xyz, tangent.xyz),0));
|
||||
}
|
||||
|
||||
public void CalculateContactMassesA(float invMass,
|
||||
float4 inverseInertiaTensor,
|
||||
float4 position,
|
||||
quaternion orientation,
|
||||
float4 contactPoint,
|
||||
bool rollingContacts)
|
||||
{
|
||||
// initialize inverse linear masses:
|
||||
normalInvMassA = tangentInvMassA = bitangentInvMassA = invMass;
|
||||
|
||||
if (rollingContacts)
|
||||
{
|
||||
float4 rA = contactPoint - position;
|
||||
float4x4 solverInertiaA = BurstMath.TransformInertiaTensor(inverseInertiaTensor, orientation);
|
||||
|
||||
normalInvMassA += BurstMath.RotationalInvMass(solverInertiaA, rA, normal);
|
||||
tangentInvMassA += BurstMath.RotationalInvMass(solverInertiaA, rA, tangent);
|
||||
bitangentInvMassA += BurstMath.RotationalInvMass(solverInertiaA, rA, bitangent);
|
||||
}
|
||||
}
|
||||
|
||||
public void CalculateContactMassesB(float invMass,
|
||||
float4 inverseInertiaTensor,
|
||||
float4 position,
|
||||
quaternion orientation,
|
||||
float4 contactPoint,
|
||||
bool rollingContacts)
|
||||
{
|
||||
// initialize inverse linear masses:
|
||||
normalInvMassB = tangentInvMassB = bitangentInvMassB = invMass;
|
||||
|
||||
if (rollingContacts)
|
||||
{
|
||||
float4 rB = contactPoint - position;
|
||||
float4x4 solverInertiaB = BurstMath.TransformInertiaTensor(inverseInertiaTensor, orientation);
|
||||
|
||||
normalInvMassB += BurstMath.RotationalInvMass(solverInertiaB, rB, normal);
|
||||
tangentInvMassB += BurstMath.RotationalInvMass(solverInertiaB, rB, tangent);
|
||||
bitangentInvMassB += BurstMath.RotationalInvMass(solverInertiaB, rB, bitangent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void CalculateContactMassesB(in BurstRigidbody rigidbody, in BurstAffineTransform solver2World)
|
||||
{
|
||||
float4 rB = solver2World.TransformPoint(pointB) - rigidbody.com;
|
||||
|
||||
// initialize inverse linear masses:
|
||||
normalInvMassB = tangentInvMassB = bitangentInvMassB = rigidbody.inverseMass;
|
||||
normalInvMassB += BurstMath.RotationalInvMass(rigidbody.inverseInertiaTensor, rB, normal);
|
||||
tangentInvMassB += BurstMath.RotationalInvMass(rigidbody.inverseInertiaTensor, rB, tangent);
|
||||
bitangentInvMassB += BurstMath.RotationalInvMass(rigidbody.inverseInertiaTensor, rB, bitangent);
|
||||
}
|
||||
|
||||
public float SolveAdhesion(float4 posA, float4 posB, float stickDistance, float stickiness, float dt)
|
||||
{
|
||||
|
||||
if (normalMass <= 0 || stickDistance <= 0 || stickiness <= 0 || dt <= 0)
|
||||
if (TotalNormalInvMass <= 0 || stickDistance <= 0 || stickiness <= 0 || dt <= 0)
|
||||
return 0;
|
||||
|
||||
distance = math.dot(posA - posB, normal);
|
||||
@@ -57,7 +137,7 @@ namespace Obi
|
||||
float constraint = stickiness * (1 - math.max(distance / stickDistance, 0)) * dt;
|
||||
|
||||
// calculate lambda multiplier:
|
||||
float dlambda = -constraint / normalMass;
|
||||
float dlambda = -constraint / TotalNormalInvMass;
|
||||
|
||||
// accumulate lambda:
|
||||
float newStickinessLambda = math.min(stickLambda + dlambda, 0);
|
||||
@@ -69,9 +149,10 @@ namespace Obi
|
||||
return lambdaChange;
|
||||
}
|
||||
|
||||
public float SolvePenetration(float normalMass, float4 posA, float4 posB, float maxDepenetrationDelta)
|
||||
public float SolvePenetration(float4 posA, float4 posB, float maxDepenetrationDelta)
|
||||
{
|
||||
if (normalMass <= 0)
|
||||
|
||||
if (TotalNormalInvMass <= 0)
|
||||
return 0;
|
||||
|
||||
//project position delta to normal vector:
|
||||
@@ -81,7 +162,7 @@ namespace Obi
|
||||
float maxProjection = math.max(-distance - maxDepenetrationDelta, 0);
|
||||
|
||||
// calculate lambda multiplier:
|
||||
float dlambda = -(distance + maxProjection) / normalMass;
|
||||
float dlambda = -(distance + maxProjection) / TotalNormalInvMass;
|
||||
|
||||
// accumulate lambda:
|
||||
float newLambda = math.max(normalLambda + dlambda, 0);
|
||||
@@ -93,11 +174,11 @@ namespace Obi
|
||||
return lambdaChange;
|
||||
}
|
||||
|
||||
public float2 SolveFriction(float tangentMass, float bitangentMass, float4 relativeVelocity, float staticFriction, float dynamicFriction, float dt)
|
||||
public float2 SolveFriction(float4 relativeVelocity, float staticFriction, float dynamicFriction, float dt)
|
||||
{
|
||||
float2 lambdaChange = float2.zero;
|
||||
|
||||
if (tangentMass <= 0 || bitangentMass <= 0 ||
|
||||
if (TotalTangentInvMass <= 0 || TotalBitangentInvMass <= 0 ||
|
||||
(dynamicFriction <= 0 && staticFriction <= 0) || (normalLambda <= 0 && stickLambda <= 0))
|
||||
return lambdaChange;
|
||||
|
||||
@@ -110,7 +191,7 @@ namespace Obi
|
||||
float staticFrictionCone = normalLambda / dt * staticFriction;
|
||||
|
||||
// tangent impulse:
|
||||
float tangentLambdaDelta = -tangentPosDelta / tangentMass;
|
||||
float tangentLambdaDelta = -tangentPosDelta / TotalTangentInvMass;
|
||||
float newTangentLambda = tangentLambda + tangentLambdaDelta;
|
||||
|
||||
if (math.abs(newTangentLambda) > staticFrictionCone)
|
||||
@@ -120,7 +201,7 @@ namespace Obi
|
||||
tangentLambda = newTangentLambda;
|
||||
|
||||
// bitangent impulse:
|
||||
float bitangentLambdaDelta = -bitangentPosDelta / bitangentMass;
|
||||
float bitangentLambdaDelta = -bitangentPosDelta / TotalBitangentInvMass;
|
||||
float newBitangentLambda = bitangentLambda + bitangentLambdaDelta;
|
||||
|
||||
if (math.abs(newBitangentLambda) > staticFrictionCone)
|
||||
@@ -158,6 +239,6 @@ namespace Obi
|
||||
|
||||
return rolling_impulse_change;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -10,9 +10,9 @@ namespace Obi
|
||||
public float4 queryPoint; // point B, expressed as simplex barycentric coords for simplices, as a solver-space position for colliders.
|
||||
public float4 normal;
|
||||
public float distance;
|
||||
public float distanceAlongRay;
|
||||
public int simplexIndex;
|
||||
public int queryIndex;
|
||||
public int pad0; // padding to ensure correct alignment.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user