添加插件
This commit is contained in:
374
Assets/Obi/Resources/Compute/DistanceFunctions.cginc
Normal file
374
Assets/Obi/Resources/Compute/DistanceFunctions.cginc
Normal file
@@ -0,0 +1,374 @@
|
||||
#ifndef DISTANCEFUNCTIONS_INCLUDE
|
||||
#define DISTANCEFUNCTIONS_INCLUDE
|
||||
|
||||
#include "SurfacePoint.cginc"
|
||||
#include "Transform.cginc"
|
||||
#include "Bounds.cginc"
|
||||
|
||||
struct Sphere : IDistanceFunction
|
||||
{
|
||||
shape s;
|
||||
transform colliderToSolver;
|
||||
|
||||
void Evaluate(in float4 pos, in float4 radii, in quaternion orientation, inout SurfacePoint projectedPoint)
|
||||
{
|
||||
float4 center = s.center * colliderToSolver.scale;
|
||||
float4 pnt = colliderToSolver.InverseTransformPointUnscaled(pos) - center;
|
||||
|
||||
if (s.is2D())
|
||||
pnt[2] = 0;
|
||||
|
||||
float radius = s.size.x * cmax(colliderToSolver.scale.xyz);
|
||||
float distanceToCenter = length(pnt);
|
||||
|
||||
float4 normal = pnt / (distanceToCenter + EPSILON);
|
||||
|
||||
projectedPoint.pos = colliderToSolver.TransformPointUnscaled(center + normal * (radius + s.contactOffset));
|
||||
projectedPoint.normal = colliderToSolver.TransformDirection(normal);
|
||||
projectedPoint.bary = float4(1,0,0,0);
|
||||
}
|
||||
};
|
||||
|
||||
struct Box : IDistanceFunction
|
||||
{
|
||||
shape s;
|
||||
transform colliderToSolver;
|
||||
|
||||
void Evaluate(in float4 pos, in float4 radii, in quaternion orientation, inout SurfacePoint projectedPoint)
|
||||
{
|
||||
float4 center = s.center * colliderToSolver.scale;
|
||||
float4 size = s.size * colliderToSolver.scale * 0.5f;
|
||||
|
||||
// clamp the point to the surface of the box:
|
||||
float4 pnt = colliderToSolver.InverseTransformPointUnscaled(pos) - center;
|
||||
|
||||
if (s.is2D())
|
||||
pnt[2] = 0;
|
||||
|
||||
// get minimum distance for each axis:
|
||||
float4 distances = size - abs(pnt);
|
||||
|
||||
if (distances.x >= 0 && distances.y >= 0 && distances.z >= 0)
|
||||
{
|
||||
projectedPoint.normal = float4(0,0,0,0);
|
||||
projectedPoint.pos = pnt;
|
||||
|
||||
// find minimum distance in all three axes and the axis index:
|
||||
if (distances.y < distances.x && distances.y < distances.z)
|
||||
{
|
||||
projectedPoint.normal[1] = sign(pnt[1]);
|
||||
projectedPoint.pos[1] = size[1] * projectedPoint.normal[1];
|
||||
}
|
||||
else if (distances.z < distances.x && distances.z < distances.y)
|
||||
{
|
||||
projectedPoint.normal[2] = sign(pnt[2]);
|
||||
projectedPoint.pos[2] = size[2] * projectedPoint.normal[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
projectedPoint.normal[0] = sign(pnt[0]);
|
||||
projectedPoint.pos[0] = size[0] * projectedPoint.normal[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
projectedPoint.pos = clamp(pnt, -size, size);
|
||||
projectedPoint.normal = normalizesafe(pnt - projectedPoint.pos);
|
||||
}
|
||||
|
||||
projectedPoint.pos = colliderToSolver.TransformPointUnscaled(projectedPoint.pos + center + projectedPoint.normal * s.contactOffset);
|
||||
projectedPoint.normal = colliderToSolver.TransformDirection(projectedPoint.normal);
|
||||
projectedPoint.bary = float4(1,0,0,0);
|
||||
}
|
||||
};
|
||||
|
||||
struct Capsule : IDistanceFunction
|
||||
{
|
||||
shape s;
|
||||
transform colliderToSolver;
|
||||
|
||||
void Evaluate(in float4 pos, in float4 radii, in quaternion orientation, inout SurfacePoint projectedPoint)
|
||||
{
|
||||
float4 center = s.center * colliderToSolver.scale;
|
||||
float4 pnt = colliderToSolver.InverseTransformPointUnscaled(pos) - center;
|
||||
|
||||
if (s.is2D())
|
||||
pnt[2] = 0;
|
||||
|
||||
int direction = (int)s.size.z;
|
||||
float height;
|
||||
float radius;
|
||||
float4 halfVector = float4(0,0,0,0);
|
||||
|
||||
if (direction == 0)
|
||||
{
|
||||
radius = s.size.x * max(colliderToSolver.scale[1], colliderToSolver.scale[2]);
|
||||
height = max(radius, s.size.y * 0.5f * colliderToSolver.scale[0]);
|
||||
halfVector[0] = height - radius;
|
||||
}
|
||||
else if (direction == 1)
|
||||
{
|
||||
radius = s.size.x * max(colliderToSolver.scale[2], colliderToSolver.scale[0]);
|
||||
height = max(radius, s.size.y * 0.5f * colliderToSolver.scale[1]);
|
||||
halfVector[1] = height - radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
radius = s.size.x * max(colliderToSolver.scale[0], colliderToSolver.scale[1]);
|
||||
height = max(radius, s.size.y * 0.5f * colliderToSolver.scale[2]);
|
||||
halfVector[2] = height - radius;
|
||||
}
|
||||
|
||||
float mu;
|
||||
float4 centerLine = NearestPointOnEdge(-halfVector, halfVector, pnt, mu);
|
||||
float4 centerToPoint = pnt - centerLine;
|
||||
float distanceToCenter = length(centerToPoint);
|
||||
|
||||
float4 normal = centerToPoint / (distanceToCenter + EPSILON);
|
||||
|
||||
projectedPoint.pos = colliderToSolver.TransformPointUnscaled(center + centerLine + normal * (radius + s.contactOffset));
|
||||
projectedPoint.normal = colliderToSolver.TransformDirection(normal);
|
||||
projectedPoint.bary = float4(1,0,0,0);
|
||||
}
|
||||
};
|
||||
|
||||
struct BIHNode
|
||||
{
|
||||
int firstChild; /**< index of the first child node. The second one is right after the first.*/
|
||||
int start; /**< index of the first element in this node.*/
|
||||
int count; /**< amount of elements in this node.*/
|
||||
|
||||
int axis; /**< axis of the split plane (0,1,2 = x,y,z)*/
|
||||
float min_; /**< minimum split plane*/
|
||||
float max_; /**< maximum split plane*/
|
||||
};
|
||||
|
||||
struct TriangleMeshHeader
|
||||
{
|
||||
int firstNode;
|
||||
int nodeCount;
|
||||
int firstTriangle;
|
||||
int triangleCount;
|
||||
int firstVertex;
|
||||
int vertexCount;
|
||||
};
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
int i1;
|
||||
int i2;
|
||||
int i3;
|
||||
aabb b;
|
||||
};
|
||||
|
||||
struct TriangleMesh : IDistanceFunction
|
||||
{
|
||||
shape s;
|
||||
transform colliderToSolver;
|
||||
|
||||
CachedTri tri;
|
||||
|
||||
void Evaluate(in float4 pos, in float4 radii, in quaternion orientation, inout SurfacePoint projectedPoint)
|
||||
{
|
||||
float4 pnt = colliderToSolver.InverseTransformPointUnscaled(pos);
|
||||
|
||||
if (s.is2D())
|
||||
pnt[2] = 0;
|
||||
|
||||
float4 bary = FLOAT4_ZERO;
|
||||
float4 nearestPoint = NearestPointOnTri(tri, pnt, bary);
|
||||
float4 normal = normalizesafe(pnt - nearestPoint);
|
||||
|
||||
projectedPoint.pos = colliderToSolver.TransformPointUnscaled(nearestPoint + normal * s.contactOffset);
|
||||
projectedPoint.normal = colliderToSolver.TransformDirection(normal);
|
||||
projectedPoint.bary = float4(1,0,0,0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct HeightFieldHeader
|
||||
{
|
||||
int firstSample;
|
||||
int sampleCount;
|
||||
};
|
||||
|
||||
struct Heightfield : IDistanceFunction
|
||||
{
|
||||
shape s;
|
||||
transform colliderToSolver;
|
||||
|
||||
CachedTri tri;
|
||||
float4 triNormal;
|
||||
|
||||
void Evaluate(in float4 pos, in float4 radii, in quaternion orientation, inout SurfacePoint projectedPoint)
|
||||
{
|
||||
float4 pnt = colliderToSolver.InverseTransformPoint(pos);
|
||||
|
||||
float4 bary;
|
||||
float4 nearestPoint = NearestPointOnTri(tri, pnt, bary);
|
||||
float4 normal = normalizesafe(pnt - nearestPoint);
|
||||
|
||||
// flip the contact normal if it points below ground: (doesn't work with holes)
|
||||
//OneSidedNormal(triNormal, normal);
|
||||
|
||||
projectedPoint.pos = colliderToSolver.TransformPoint(nearestPoint + normal * s.contactOffset);
|
||||
projectedPoint.normal = colliderToSolver.TransformDirection(normal);
|
||||
projectedPoint.bary = float4(1,0,0,0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct DistanceFieldHeader
|
||||
{
|
||||
int firstNode;
|
||||
int nodeCount;
|
||||
};
|
||||
|
||||
struct DFNode
|
||||
{
|
||||
float4 distancesA;
|
||||
float4 distancesB;
|
||||
float4 center;
|
||||
int firstChild;
|
||||
|
||||
// add 12 bytes of padding to ensure correct memory alignment:
|
||||
int pad0;
|
||||
int pad1;
|
||||
int pad2;
|
||||
|
||||
float4 GetNormalizedPos(float4 position)
|
||||
{
|
||||
float4 corner = center - float4(center[3],center[3],center[3],center[3]);
|
||||
return (position - corner) / (center[3] * 2);
|
||||
}
|
||||
|
||||
float4 SampleWithGradient(float4 position)
|
||||
{
|
||||
float4 nPos = GetNormalizedPos(position);
|
||||
|
||||
// trilinear interpolation of distance:
|
||||
float4 x = distancesA + (distancesB - distancesA) * nPos[0];
|
||||
float2 y = x.xy + (x.zw - x.xy) * nPos[1];
|
||||
float dist = y[0] + (y[1] - y[0]) * nPos[2];
|
||||
|
||||
// gradient estimation:
|
||||
// x == 0
|
||||
float2 a = distancesA.xy + (distancesA.zw - distancesA.xy) * nPos[1];
|
||||
float x0 = a[0] + (a[1] - a[0]) * nPos[2];
|
||||
|
||||
// x == 1
|
||||
a = distancesB.xy + (distancesB.zw - distancesB.xy) * nPos[1];
|
||||
float x1 = a[0] + (a[1] - a[0]) * nPos[2];
|
||||
|
||||
// y == 0
|
||||
float y0 = x[0] + (x[1] - x[0]) * nPos[2];
|
||||
|
||||
// y == 1
|
||||
float y1 = x[2] + (x[3] - x[2]) * nPos[2];
|
||||
|
||||
return float4(x1 - x0, y1 - y0, y[1] - y[0], dist);
|
||||
|
||||
}
|
||||
|
||||
int GetOctant(float4 position)
|
||||
{
|
||||
int index = 0;
|
||||
if (position[0] > center[0]) index |= 4;
|
||||
if (position[1] > center[1]) index |= 2;
|
||||
if (position[2] > center[2]) index |= 1;
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
struct DistanceField : IDistanceFunction
|
||||
{
|
||||
shape s;
|
||||
transform colliderToSolver;
|
||||
|
||||
StructuredBuffer<DistanceFieldHeader> distanceFieldHeaders;
|
||||
StructuredBuffer<DFNode> dfNodes;
|
||||
|
||||
float4 DFTraverse(float4 particlePosition,
|
||||
in DistanceFieldHeader header)
|
||||
{
|
||||
int stack[12];
|
||||
int stackTop = 0;
|
||||
|
||||
stack[stackTop++] = 0;
|
||||
|
||||
while (stackTop > 0)
|
||||
{
|
||||
// pop node index from the stack:
|
||||
int nodeIndex = stack[--stackTop];
|
||||
DFNode node = dfNodes[header.firstNode + nodeIndex];
|
||||
|
||||
// if the child node exists, recurse down the df octree:
|
||||
if (node.firstChild >= 0)
|
||||
stack[stackTop++] = node.firstChild + node.GetOctant(particlePosition);
|
||||
else
|
||||
return node.SampleWithGradient(particlePosition);
|
||||
}
|
||||
return FLOAT4_ZERO;
|
||||
}
|
||||
|
||||
void Evaluate(in float4 pos, in float4 radii, in quaternion orientation, inout SurfacePoint projectedPoint)
|
||||
{
|
||||
float4 pnt = colliderToSolver.InverseTransformPoint(pos);
|
||||
|
||||
if (s.is2D())
|
||||
pnt[2] = 0;
|
||||
|
||||
float4 sample = DFTraverse(pnt, distanceFieldHeaders[s.dataIndex]);
|
||||
float4 normal = float4(normalize(sample.xyz), 0);
|
||||
|
||||
projectedPoint.pos = colliderToSolver.TransformPoint(pnt - normal * (sample[3] - s.contactOffset));
|
||||
projectedPoint.normal = colliderToSolver.TransformDirection(normal);
|
||||
projectedPoint.bary = float4(1,0,0,0);
|
||||
}
|
||||
};
|
||||
|
||||
struct EdgeMeshHeader
|
||||
{
|
||||
int firstNode;
|
||||
int nodeCount;
|
||||
int firstEdge;
|
||||
int edgeCount;
|
||||
int firstVertex;
|
||||
int vertexCount;
|
||||
};
|
||||
|
||||
struct Edge
|
||||
{
|
||||
int i1;
|
||||
int i2;
|
||||
aabb b;
|
||||
};
|
||||
|
||||
struct EdgeMesh : IDistanceFunction
|
||||
{
|
||||
shape s;
|
||||
transform colliderToSolver;
|
||||
int dataOffset;
|
||||
|
||||
CachedEdge edge;
|
||||
|
||||
void Evaluate(in float4 pos, in float4 radii, in quaternion orientation, inout SurfacePoint projectedPoint)
|
||||
{
|
||||
float4 pnt = colliderToSolver.InverseTransformPointUnscaled(pos);
|
||||
|
||||
if (s.is2D())
|
||||
pnt[2] = 0;
|
||||
|
||||
float mu = 0;
|
||||
float4 nearestPoint = NearestPointOnEdge(edge, pnt, mu);
|
||||
float4 normal = normalizesafe(pnt - nearestPoint);
|
||||
|
||||
projectedPoint.pos = colliderToSolver.TransformPointUnscaled(nearestPoint + normal * s.contactOffset);
|
||||
projectedPoint.normal = colliderToSolver.TransformDirection(normal);
|
||||
projectedPoint.bary = float4(1,0,0,0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user