mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-05 05:07:48 +00:00
GEEKING
This commit is contained in:
+102
@@ -0,0 +1,102 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
|
||||
float adot3(float4 a, float4 b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
}
|
||||
|
||||
float alength3(float4 a)
|
||||
{
|
||||
a.w = 0;
|
||||
return length(a);
|
||||
}
|
||||
|
||||
float4 anormalize3(float4 a)
|
||||
{
|
||||
a.w = 0;
|
||||
return normalize(a);
|
||||
}
|
||||
|
||||
float4 projectOnAxis( float4 v, float4 a )
|
||||
{
|
||||
return (a*adot3(v, a));
|
||||
}
|
||||
|
||||
__kernel void
|
||||
ApplyForcesKernel(
|
||||
const uint numNodes,
|
||||
const float solverdt,
|
||||
const float epsilon,
|
||||
__global int * g_vertexClothIdentifier,
|
||||
__global float4 * g_vertexNormal,
|
||||
__global float * g_vertexArea,
|
||||
__global float * g_vertexInverseMass,
|
||||
__global float * g_clothLiftFactor,
|
||||
__global float * g_clothDragFactor,
|
||||
__global float4 * g_clothWindVelocity,
|
||||
__global float4 * g_clothAcceleration,
|
||||
__global float * g_clothMediumDensity,
|
||||
__global float4 * g_vertexForceAccumulator,
|
||||
__global float4 * g_vertexVelocity GUID_ARG)
|
||||
{
|
||||
unsigned int nodeID = get_global_id(0);
|
||||
if( nodeID < numNodes )
|
||||
{
|
||||
int clothId = g_vertexClothIdentifier[nodeID];
|
||||
float nodeIM = g_vertexInverseMass[nodeID];
|
||||
|
||||
if( nodeIM > 0.0f )
|
||||
{
|
||||
float4 nodeV = g_vertexVelocity[nodeID];
|
||||
float4 normal = g_vertexNormal[nodeID];
|
||||
float area = g_vertexArea[nodeID];
|
||||
float4 nodeF = g_vertexForceAccumulator[nodeID];
|
||||
|
||||
// Read per-cloth values
|
||||
float4 clothAcceleration = g_clothAcceleration[clothId];
|
||||
float4 clothWindVelocity = g_clothWindVelocity[clothId];
|
||||
float liftFactor = g_clothLiftFactor[clothId];
|
||||
float dragFactor = g_clothDragFactor[clothId];
|
||||
float mediumDensity = g_clothMediumDensity[clothId];
|
||||
|
||||
// Apply the acceleration to the cloth rather than do this via a force
|
||||
nodeV += (clothAcceleration*solverdt);
|
||||
|
||||
g_vertexVelocity[nodeID] = nodeV;
|
||||
|
||||
// Aerodynamics
|
||||
float4 rel_v = nodeV - clothWindVelocity;
|
||||
float rel_v_len = alength3(rel_v);
|
||||
float rel_v2 = dot(rel_v, rel_v);
|
||||
|
||||
if( rel_v2 > epsilon )
|
||||
{
|
||||
float4 rel_v_nrm = anormalize3(rel_v);
|
||||
float4 nrm = normal;
|
||||
|
||||
nrm = nrm * (dot(nrm, rel_v) < 0 ? -1.f : 1.f);
|
||||
|
||||
float4 fDrag = (float4)(0.f, 0.f, 0.f, 0.f);
|
||||
float4 fLift = (float4)(0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
float n_dot_v = dot(nrm, rel_v_nrm);
|
||||
|
||||
// drag force
|
||||
if ( dragFactor > 0.f )
|
||||
fDrag = 0.5f * dragFactor * mediumDensity * rel_v2 * area * n_dot_v * (-1.0f) * rel_v_nrm;
|
||||
|
||||
// lift force
|
||||
// Check angle of attack
|
||||
// cos(10º) = 0.98480
|
||||
if ( 0 < n_dot_v && n_dot_v < 0.98480f)
|
||||
fLift = 0.5f * liftFactor * mediumDensity * rel_v_len * area * sqrt(1.0f-n_dot_v*n_dot_v) * (cross(cross(nrm, rel_v_nrm), rel_v_nrm));
|
||||
|
||||
nodeF += fDrag + fLift;
|
||||
g_vertexForceAccumulator[nodeID] = nodeF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
MSTRINGIFY(
|
||||
#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable\n
|
||||
#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable\n
|
||||
|
||||
__kernel void
|
||||
ComputeBoundsKernel(
|
||||
const int numNodes,
|
||||
const int numSoftBodies,
|
||||
__global int * g_vertexClothIdentifier,
|
||||
__global float4 * g_vertexPositions,
|
||||
/* Unfortunately, to get the atomics below to work these arrays cannot be */
|
||||
/* uint4, though that is the layout of the data */
|
||||
/* Therefore this is little-endian-only code */
|
||||
volatile __global uint * g_clothMinBounds,
|
||||
volatile __global uint * g_clothMaxBounds,
|
||||
volatile __local uint * clothMinBounds,
|
||||
volatile __local uint * clothMaxBounds)
|
||||
{
|
||||
// Init min and max bounds arrays
|
||||
if( get_local_id(0) < numSoftBodies )
|
||||
{
|
||||
|
||||
clothMinBounds[get_local_id(0)*4] = UINT_MAX;
|
||||
clothMinBounds[get_local_id(0)*4+1] = UINT_MAX;
|
||||
clothMinBounds[get_local_id(0)*4+2] = UINT_MAX;
|
||||
clothMinBounds[get_local_id(0)*4+3] = UINT_MAX;
|
||||
clothMaxBounds[get_local_id(0)*4] = 0;
|
||||
clothMaxBounds[get_local_id(0)*4+1] = 0;
|
||||
clothMaxBounds[get_local_id(0)*4+2] = 0;
|
||||
clothMaxBounds[get_local_id(0)*4+3] = 0;
|
||||
|
||||
}
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
int nodeID = get_global_id(0);
|
||||
if( nodeID < numNodes )
|
||||
{
|
||||
int clothIdentifier = g_vertexClothIdentifier[nodeID];
|
||||
if( clothIdentifier >= 0 )
|
||||
{
|
||||
|
||||
float4 position = (float4)(g_vertexPositions[nodeID].xyz, 0.f);
|
||||
|
||||
/* Reinterpret position as uint */
|
||||
uint4 positionUInt = (uint4)(as_uint(position.x), as_uint(position.y), as_uint(position.z), 0);
|
||||
|
||||
/* Invert sign bit of positives and whole of negatives to allow comparison as unsigned ints */
|
||||
positionUInt.x ^= (1+~(positionUInt.x >> 31) | 0x80000000);
|
||||
positionUInt.y ^= (1+~(positionUInt.y >> 31) | 0x80000000);
|
||||
positionUInt.z ^= (1+~(positionUInt.z >> 31) | 0x80000000);
|
||||
|
||||
// Min/max with the LDS values
|
||||
atom_min(&(clothMinBounds[clothIdentifier*4]), positionUInt.x);
|
||||
atom_min(&(clothMinBounds[clothIdentifier*4+1]), positionUInt.y);
|
||||
atom_min(&(clothMinBounds[clothIdentifier*4+2]), positionUInt.z);
|
||||
|
||||
atom_max(&(clothMaxBounds[clothIdentifier*4]), positionUInt.x);
|
||||
atom_max(&(clothMaxBounds[clothIdentifier*4+1]), positionUInt.y);
|
||||
atom_max(&(clothMaxBounds[clothIdentifier*4+2]), positionUInt.z);
|
||||
}
|
||||
}
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
|
||||
/* Use global atomics to update the global versions of the data */
|
||||
if( get_local_id(0) < numSoftBodies )
|
||||
{
|
||||
/*atom_min(&(g_clothMinBounds[get_local_id(0)].x), clothMinBounds[get_local_id(0)].x);*/
|
||||
atom_min(&(g_clothMinBounds[get_local_id(0)*4]), clothMinBounds[get_local_id(0)*4]);
|
||||
atom_min(&(g_clothMinBounds[get_local_id(0)*4+1]), clothMinBounds[get_local_id(0)*4+1]);
|
||||
atom_min(&(g_clothMinBounds[get_local_id(0)*4+2]), clothMinBounds[get_local_id(0)*4+2]);
|
||||
|
||||
atom_max(&(g_clothMaxBounds[get_local_id(0)*4]), clothMaxBounds[get_local_id(0)*4]);
|
||||
atom_max(&(g_clothMaxBounds[get_local_id(0)*4+1]), clothMaxBounds[get_local_id(0)*4+1]);
|
||||
atom_max(&(g_clothMaxBounds[get_local_id(0)*4+2]), clothMaxBounds[get_local_id(0)*4+2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
);
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
// Node indices for each link
|
||||
|
||||
|
||||
|
||||
__kernel void
|
||||
IntegrateKernel(
|
||||
const int numNodes,
|
||||
const float solverdt,
|
||||
__global float * g_vertexInverseMasses,
|
||||
__global float4 * g_vertexPositions,
|
||||
__global float4 * g_vertexVelocity,
|
||||
__global float4 * g_vertexPreviousPositions,
|
||||
__global float4 * g_vertexForceAccumulator GUID_ARG)
|
||||
{
|
||||
int nodeID = get_global_id(0);
|
||||
if( nodeID < numNodes )
|
||||
{
|
||||
float4 position = g_vertexPositions[nodeID];
|
||||
float4 velocity = g_vertexVelocity[nodeID];
|
||||
float4 force = g_vertexForceAccumulator[nodeID];
|
||||
float inverseMass = g_vertexInverseMasses[nodeID];
|
||||
|
||||
g_vertexPreviousPositions[nodeID] = position;
|
||||
velocity += force * inverseMass * solverdt;
|
||||
position += velocity * solverdt;
|
||||
|
||||
g_vertexForceAccumulator[nodeID] = (float4)(0.f, 0.f, 0.f, 0.0f);
|
||||
g_vertexPositions[nodeID] = position;
|
||||
g_vertexVelocity[nodeID] = velocity;
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
__kernel void
|
||||
OutputToVertexArrayWithNormalsKernel(
|
||||
const int startNode, const int numNodes, __global float *g_vertexBuffer,
|
||||
const int positionOffset, const int positionStride, const __global float4* g_vertexPositions,
|
||||
const int normalOffset, const int normalStride, const __global float4* g_vertexNormals )
|
||||
{
|
||||
int nodeID = get_global_id(0);
|
||||
if( nodeID < numNodes )
|
||||
{
|
||||
float4 position = g_vertexPositions[nodeID + startNode];
|
||||
float4 normal = g_vertexNormals[nodeID + startNode];
|
||||
|
||||
// Stride should account for the float->float4 conversion
|
||||
int positionDestination = nodeID * positionStride + positionOffset;
|
||||
g_vertexBuffer[positionDestination] = position.x;
|
||||
g_vertexBuffer[positionDestination+1] = position.y;
|
||||
g_vertexBuffer[positionDestination+2] = position.z;
|
||||
|
||||
int normalDestination = nodeID * normalStride + normalOffset;
|
||||
g_vertexBuffer[normalDestination] = normal.x;
|
||||
g_vertexBuffer[normalDestination+1] = normal.y;
|
||||
g_vertexBuffer[normalDestination+2] = normal.z;
|
||||
}
|
||||
}
|
||||
|
||||
__kernel void
|
||||
OutputToVertexArrayWithoutNormalsKernel(
|
||||
const int startNode, const int numNodes, __global float *g_vertexBuffer,
|
||||
const int positionOffset, const int positionStride, const __global float4* g_vertexPositions )
|
||||
{
|
||||
int nodeID = get_global_id(0);
|
||||
if( nodeID < numNodes )
|
||||
{
|
||||
float4 position = g_vertexPositions[nodeID + startNode];
|
||||
|
||||
// Stride should account for the float->float4 conversion
|
||||
int positionDestination = nodeID * positionStride + positionOffset;
|
||||
g_vertexBuffer[positionDestination] = position.x;
|
||||
g_vertexBuffer[positionDestination+1] = position.y;
|
||||
g_vertexBuffer[positionDestination+2] = position.z;
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
|
||||
|
||||
__kernel void
|
||||
PrepareLinksKernel(
|
||||
const int numLinks,
|
||||
__global int2 * g_linksVertexIndices,
|
||||
__global float * g_linksMassLSC,
|
||||
__global float4 * g_nodesPreviousPosition,
|
||||
__global float * g_linksLengthRatio,
|
||||
__global float4 * g_linksCurrentLength GUID_ARG)
|
||||
{
|
||||
int linkID = get_global_id(0);
|
||||
if( linkID < numLinks )
|
||||
{
|
||||
|
||||
int2 nodeIndices = g_linksVertexIndices[linkID];
|
||||
int node0 = nodeIndices.x;
|
||||
int node1 = nodeIndices.y;
|
||||
|
||||
float4 nodePreviousPosition0 = g_nodesPreviousPosition[node0];
|
||||
float4 nodePreviousPosition1 = g_nodesPreviousPosition[node1];
|
||||
|
||||
float massLSC = g_linksMassLSC[linkID];
|
||||
|
||||
float4 linkCurrentLength = nodePreviousPosition1 - nodePreviousPosition0;
|
||||
linkCurrentLength.w = 0.f;
|
||||
|
||||
float linkLengthRatio = dot(linkCurrentLength, linkCurrentLength)*massLSC;
|
||||
linkLengthRatio = 1.0f/linkLengthRatio;
|
||||
|
||||
g_linksCurrentLength[linkID] = linkCurrentLength;
|
||||
g_linksLengthRatio[linkID] = linkLengthRatio;
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
|
||||
|
||||
float mydot3a(float4 a, float4 b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int firstObject;
|
||||
int endObject;
|
||||
} CollisionObjectIndices;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float4 shapeTransform[4]; // column major 4x4 matrix
|
||||
float4 linearVelocity;
|
||||
float4 angularVelocity;
|
||||
|
||||
int softBodyIdentifier;
|
||||
int collisionShapeType;
|
||||
|
||||
|
||||
// Shape information
|
||||
// Compressed from the union
|
||||
float radius;
|
||||
float halfHeight;
|
||||
int upAxis;
|
||||
|
||||
float margin;
|
||||
float friction;
|
||||
|
||||
int padding0;
|
||||
|
||||
} CollisionShapeDescription;
|
||||
|
||||
// From btBroadphaseProxy.h
|
||||
__constant int CAPSULE_SHAPE_PROXYTYPE = 10;
|
||||
|
||||
// Multiply column-major matrix against vector
|
||||
float4 matrixVectorMul( float4 matrix[4], float4 vector )
|
||||
{
|
||||
float4 returnVector;
|
||||
float4 row0 = (float4)(matrix[0].x, matrix[1].x, matrix[2].x, matrix[3].x);
|
||||
float4 row1 = (float4)(matrix[0].y, matrix[1].y, matrix[2].y, matrix[3].y);
|
||||
float4 row2 = (float4)(matrix[0].z, matrix[1].z, matrix[2].z, matrix[3].z);
|
||||
float4 row3 = (float4)(matrix[0].w, matrix[1].w, matrix[2].w, matrix[3].w);
|
||||
returnVector.x = dot(row0, vector);
|
||||
returnVector.y = dot(row1, vector);
|
||||
returnVector.z = dot(row2, vector);
|
||||
returnVector.w = dot(row3, vector);
|
||||
return returnVector;
|
||||
}
|
||||
|
||||
__kernel void
|
||||
SolveCollisionsAndUpdateVelocitiesKernel(
|
||||
const int numNodes,
|
||||
const float isolverdt,
|
||||
__global int *g_vertexClothIdentifier,
|
||||
__global float4 *g_vertexPreviousPositions,
|
||||
__global float * g_perClothFriction,
|
||||
__global float * g_clothDampingFactor,
|
||||
__global CollisionObjectIndices * g_perClothCollisionObjectIndices,
|
||||
__global CollisionShapeDescription * g_collisionObjectDetails,
|
||||
__global float4 * g_vertexForces,
|
||||
__global float4 *g_vertexVelocities,
|
||||
__global float4 *g_vertexPositions GUID_ARG)
|
||||
{
|
||||
int nodeID = get_global_id(0);
|
||||
float4 forceOnVertex = (float4)(0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
if( get_global_id(0) < numNodes )
|
||||
{
|
||||
int clothIdentifier = g_vertexClothIdentifier[nodeID];
|
||||
|
||||
// Abort if this is not a valid cloth
|
||||
if( clothIdentifier < 0 )
|
||||
return;
|
||||
|
||||
|
||||
float4 position = (float4)(g_vertexPositions[nodeID].xyz, 1.f);
|
||||
float4 previousPosition = (float4)(g_vertexPreviousPositions[nodeID].xyz, 1.f);
|
||||
|
||||
float clothFriction = g_perClothFriction[clothIdentifier];
|
||||
float dampingFactor = g_clothDampingFactor[clothIdentifier];
|
||||
float velocityCoefficient = (1.f - dampingFactor);
|
||||
float4 difference = position - previousPosition;
|
||||
float4 velocity = difference*velocityCoefficient*isolverdt;
|
||||
|
||||
CollisionObjectIndices collisionObjectIndices = g_perClothCollisionObjectIndices[clothIdentifier];
|
||||
|
||||
int numObjects = collisionObjectIndices.endObject - collisionObjectIndices.firstObject;
|
||||
|
||||
if( numObjects > 0 )
|
||||
{
|
||||
// We have some possible collisions to deal with
|
||||
for( int collision = collisionObjectIndices.firstObject; collision < collisionObjectIndices.endObject; ++collision )
|
||||
{
|
||||
CollisionShapeDescription shapeDescription = g_collisionObjectDetails[collision];
|
||||
float colliderFriction = shapeDescription.friction;
|
||||
|
||||
if( shapeDescription.collisionShapeType == CAPSULE_SHAPE_PROXYTYPE )
|
||||
{
|
||||
// Colliding with a capsule
|
||||
|
||||
float capsuleHalfHeight = shapeDescription.halfHeight;
|
||||
float capsuleRadius = shapeDescription.radius;
|
||||
float capsuleMargin = shapeDescription.margin;
|
||||
int capsuleupAxis = shapeDescription.upAxis;
|
||||
|
||||
// Four columns of worldTransform matrix
|
||||
float4 worldTransform[4];
|
||||
worldTransform[0] = shapeDescription.shapeTransform[0];
|
||||
worldTransform[1] = shapeDescription.shapeTransform[1];
|
||||
worldTransform[2] = shapeDescription.shapeTransform[2];
|
||||
worldTransform[3] = shapeDescription.shapeTransform[3];
|
||||
|
||||
// Correctly define capsule centerline vector
|
||||
float4 c1 = (float4)(0.f, 0.f, 0.f, 1.f);
|
||||
float4 c2 = (float4)(0.f, 0.f, 0.f, 1.f);
|
||||
c1.x = select( 0.f, -capsuleHalfHeight, capsuleupAxis == 0 );
|
||||
c1.y = select( 0.f, -capsuleHalfHeight, capsuleupAxis == 1 );
|
||||
c1.z = select( 0.f, -capsuleHalfHeight, capsuleupAxis == 2 );
|
||||
c2.x = -c1.x;
|
||||
c2.y = -c1.y;
|
||||
c2.z = -c1.z;
|
||||
|
||||
|
||||
float4 worldC1 = matrixVectorMul(worldTransform, c1);
|
||||
float4 worldC2 = matrixVectorMul(worldTransform, c2);
|
||||
float4 segment = (worldC2 - worldC1);
|
||||
|
||||
// compute distance of tangent to vertex along line segment in capsule
|
||||
float distanceAlongSegment = -( mydot3a( (worldC1 - position), segment ) / mydot3a(segment, segment) );
|
||||
|
||||
float4 closestPoint = (worldC1 + (float4)(segment * distanceAlongSegment));
|
||||
float distanceFromLine = length(position - closestPoint);
|
||||
float distanceFromC1 = length(worldC1 - position);
|
||||
float distanceFromC2 = length(worldC2 - position);
|
||||
|
||||
// Final distance from collision, point to push from, direction to push in
|
||||
// for impulse force
|
||||
float dist;
|
||||
float4 normalVector;
|
||||
if( distanceAlongSegment < 0 )
|
||||
{
|
||||
dist = distanceFromC1;
|
||||
normalVector = (float4)(normalize(position - worldC1).xyz, 0.f);
|
||||
} else if( distanceAlongSegment > 1.f ) {
|
||||
dist = distanceFromC2;
|
||||
normalVector = (float4)(normalize(position - worldC2).xyz, 0.f);
|
||||
} else {
|
||||
dist = distanceFromLine;
|
||||
normalVector = (float4)(normalize(position - closestPoint).xyz, 0.f);
|
||||
}
|
||||
|
||||
float4 colliderLinearVelocity = shapeDescription.linearVelocity;
|
||||
float4 colliderAngularVelocity = shapeDescription.angularVelocity;
|
||||
float4 velocityOfSurfacePoint = colliderLinearVelocity + cross(colliderAngularVelocity, position - (float4)(worldTransform[0].w, worldTransform[1].w, worldTransform[2].w, 0.f));
|
||||
|
||||
float minDistance = capsuleRadius + capsuleMargin;
|
||||
|
||||
// In case of no collision, this is the value of velocity
|
||||
velocity = (position - previousPosition) * velocityCoefficient * isolverdt;
|
||||
|
||||
|
||||
// Check for a collision
|
||||
if( dist < minDistance )
|
||||
{
|
||||
// Project back to surface along normal
|
||||
position = position + (float4)((minDistance - dist)*normalVector*0.9f);
|
||||
velocity = (position - previousPosition) * velocityCoefficient * isolverdt;
|
||||
float4 relativeVelocity = velocity - velocityOfSurfacePoint;
|
||||
|
||||
float4 p1 = normalize(cross(normalVector, segment));
|
||||
float4 p2 = normalize(cross(p1, normalVector));
|
||||
// Full friction is sum of velocities in each direction of plane
|
||||
float4 frictionVector = p1*mydot3a(relativeVelocity, p1) + p2*mydot3a(relativeVelocity, p2);
|
||||
|
||||
// Real friction is peak friction corrected by friction coefficients
|
||||
frictionVector = frictionVector * (colliderFriction*clothFriction);
|
||||
|
||||
float approachSpeed = dot(relativeVelocity, normalVector);
|
||||
|
||||
if( approachSpeed <= 0.0f )
|
||||
forceOnVertex -= frictionVector;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_vertexVelocities[nodeID] = (float4)(velocity.xyz, 0.f);
|
||||
|
||||
// Update external force
|
||||
g_vertexForces[nodeID] = (float4)(forceOnVertex.xyz, 0.f);
|
||||
|
||||
g_vertexPositions[nodeID] = (float4)(position.xyz, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
//#pragma OPENCL EXTENSION cl_amd_printf:enable\n
|
||||
|
||||
float mydot3a(float4 a, float4 b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
}
|
||||
|
||||
float mylength3(float4 a)
|
||||
{
|
||||
a.w = 0;
|
||||
return length(a);
|
||||
}
|
||||
|
||||
float4 mynormalize3(float4 a)
|
||||
{
|
||||
a.w = 0;
|
||||
return normalize(a);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int firstObject;
|
||||
int endObject;
|
||||
} CollisionObjectIndices;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float4 shapeTransform[4]; // column major 4x4 matrix
|
||||
float4 linearVelocity;
|
||||
float4 angularVelocity;
|
||||
|
||||
int softBodyIdentifier;
|
||||
int collisionShapeType;
|
||||
|
||||
|
||||
// Shape information
|
||||
// Compressed from the union
|
||||
float radius;
|
||||
float halfHeight;
|
||||
int upAxis;
|
||||
|
||||
float margin;
|
||||
float friction;
|
||||
|
||||
int padding0;
|
||||
|
||||
} CollisionShapeDescription;
|
||||
|
||||
// From btBroadphaseProxy.h
|
||||
__constant int CAPSULE_SHAPE_PROXYTYPE = 10;
|
||||
|
||||
// Multiply column-major matrix against vector
|
||||
float4 matrixVectorMul( float4 matrix[4], float4 vector )
|
||||
{
|
||||
float4 returnVector;
|
||||
float4 row0 = (float4)(matrix[0].x, matrix[1].x, matrix[2].x, matrix[3].x);
|
||||
float4 row1 = (float4)(matrix[0].y, matrix[1].y, matrix[2].y, matrix[3].y);
|
||||
float4 row2 = (float4)(matrix[0].z, matrix[1].z, matrix[2].z, matrix[3].z);
|
||||
float4 row3 = (float4)(matrix[0].w, matrix[1].w, matrix[2].w, matrix[3].w);
|
||||
returnVector.x = dot(row0, vector);
|
||||
returnVector.y = dot(row1, vector);
|
||||
returnVector.z = dot(row2, vector);
|
||||
returnVector.w = dot(row3, vector);
|
||||
return returnVector;
|
||||
}
|
||||
|
||||
__kernel void
|
||||
SolveCollisionsAndUpdateVelocitiesKernel(
|
||||
const int numNodes,
|
||||
const float isolverdt,
|
||||
__global int *g_vertexClothIdentifier,
|
||||
__global float4 *g_vertexPreviousPositions,
|
||||
__global float * g_perClothFriction,
|
||||
__global float * g_clothDampingFactor,
|
||||
__global CollisionObjectIndices * g_perClothCollisionObjectIndices,
|
||||
__global CollisionShapeDescription * g_collisionObjectDetails,
|
||||
__global float4 * g_vertexForces,
|
||||
__global float4 *g_vertexVelocities,
|
||||
__global float4 *g_vertexPositions,
|
||||
__local CollisionShapeDescription *localCollisionShapes,
|
||||
__global float * g_vertexInverseMasses)
|
||||
{
|
||||
int nodeID = get_global_id(0);
|
||||
float4 forceOnVertex = (float4)(0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
int clothIdentifier = g_vertexClothIdentifier[nodeID];
|
||||
|
||||
// Abort if this is not a valid cloth
|
||||
if( clothIdentifier < 0 )
|
||||
return;
|
||||
|
||||
|
||||
float4 position = (float4)(g_vertexPositions[nodeID].xyz, 0.f);
|
||||
float4 previousPosition = (float4)(g_vertexPreviousPositions[nodeID].xyz, 0.f);
|
||||
|
||||
float clothFriction = g_perClothFriction[clothIdentifier];
|
||||
float dampingFactor = g_clothDampingFactor[clothIdentifier];
|
||||
float velocityCoefficient = (1.f - dampingFactor);
|
||||
float4 difference = position - previousPosition;
|
||||
float4 velocity = difference*velocityCoefficient*isolverdt;
|
||||
float inverseMass = g_vertexInverseMasses[nodeID];
|
||||
|
||||
CollisionObjectIndices collisionObjectIndices = g_perClothCollisionObjectIndices[clothIdentifier];
|
||||
|
||||
int numObjects = collisionObjectIndices.endObject - collisionObjectIndices.firstObject;
|
||||
|
||||
if( numObjects > 0 )
|
||||
{
|
||||
// We have some possible collisions to deal with
|
||||
|
||||
// First load all of the collision objects into LDS
|
||||
int numObjects = collisionObjectIndices.endObject - collisionObjectIndices.firstObject;
|
||||
if( get_local_id(0) < numObjects )
|
||||
{
|
||||
localCollisionShapes[get_local_id(0)] = g_collisionObjectDetails[ collisionObjectIndices.firstObject + get_local_id(0) ];
|
||||
}
|
||||
}
|
||||
|
||||
// Safe as the vertices are padded so that not more than one soft body is in a group
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
// Annoyingly, even though I know the flow control is not varying, the compiler will not let me skip this
|
||||
if( numObjects > 0 )
|
||||
{
|
||||
|
||||
|
||||
// We have some possible collisions to deal with
|
||||
for( int collision = 0; collision < numObjects; ++collision )
|
||||
{
|
||||
CollisionShapeDescription shapeDescription = localCollisionShapes[collision];
|
||||
float colliderFriction = localCollisionShapes[collision].friction;
|
||||
|
||||
if( localCollisionShapes[collision].collisionShapeType == CAPSULE_SHAPE_PROXYTYPE )
|
||||
{
|
||||
// Colliding with a capsule
|
||||
|
||||
float capsuleHalfHeight = localCollisionShapes[collision].halfHeight;
|
||||
float capsuleRadius = localCollisionShapes[collision].radius;
|
||||
float capsuleMargin = localCollisionShapes[collision].margin;
|
||||
int capsuleupAxis = localCollisionShapes[collision].upAxis;
|
||||
|
||||
if ( capsuleHalfHeight <= 0 )
|
||||
capsuleHalfHeight = 0.0001f;
|
||||
float4 worldTransform[4];
|
||||
worldTransform[0] = localCollisionShapes[collision].shapeTransform[0];
|
||||
worldTransform[1] = localCollisionShapes[collision].shapeTransform[1];
|
||||
worldTransform[2] = localCollisionShapes[collision].shapeTransform[2];
|
||||
worldTransform[3] = localCollisionShapes[collision].shapeTransform[3];
|
||||
|
||||
// Correctly define capsule centerline vector
|
||||
float4 c1 = (float4)(0.f, 0.f, 0.f, 1.f);
|
||||
float4 c2 = (float4)(0.f, 0.f, 0.f, 1.f);
|
||||
c1.x = select( 0.f, -capsuleHalfHeight, capsuleupAxis == 0 );
|
||||
c1.y = select( 0.f, -capsuleHalfHeight, capsuleupAxis == 1 );
|
||||
c1.z = select( 0.f, -capsuleHalfHeight, capsuleupAxis == 2 );
|
||||
c2.x = -c1.x;
|
||||
c2.y = -c1.y;
|
||||
c2.z = -c1.z;
|
||||
|
||||
float4 worldC1 = matrixVectorMul(worldTransform, c1);
|
||||
float4 worldC2 = matrixVectorMul(worldTransform, c2);
|
||||
float4 segment = (float4)((worldC2 - worldC1).xyz, 0.f);
|
||||
|
||||
float4 segmentNormalized = mynormalize3(segment);
|
||||
float distanceAlongSegment =mydot3a( (position - worldC1), segmentNormalized );
|
||||
|
||||
float4 closestPointOnSegment = (worldC1 + (float4)(segmentNormalized * distanceAlongSegment));
|
||||
float distanceFromLine = mylength3(position - closestPointOnSegment);
|
||||
float distanceFromC1 = mylength3(worldC1 - position);
|
||||
float distanceFromC2 = mylength3(worldC2 - position);
|
||||
|
||||
// Final distance from collision, point to push from, direction to push in
|
||||
// for impulse force
|
||||
float dist;
|
||||
float4 normalVector;
|
||||
|
||||
if( distanceAlongSegment < 0 )
|
||||
{
|
||||
dist = distanceFromC1;
|
||||
normalVector = (float4)(normalize(position - worldC1).xyz, 0.f);
|
||||
} else if( distanceAlongSegment > length(segment) ) {
|
||||
dist = distanceFromC2;
|
||||
normalVector = (float4)(normalize(position - worldC2).xyz, 0.f);
|
||||
} else {
|
||||
dist = distanceFromLine;
|
||||
normalVector = (float4)(normalize(position - closestPointOnSegment).xyz, 0.f);
|
||||
}
|
||||
|
||||
float minDistance = capsuleRadius + capsuleMargin;
|
||||
float4 closestPointOnSurface = (float4)((position + (minDistance - dist) * normalVector).xyz, 0.f);
|
||||
|
||||
float4 colliderLinearVelocity = shapeDescription.linearVelocity;
|
||||
float4 colliderAngularVelocity = shapeDescription.angularVelocity;
|
||||
float4 velocityOfSurfacePoint = colliderLinearVelocity + cross(colliderAngularVelocity, closestPointOnSurface - (float4)(worldTransform[0].w, worldTransform[1].w, worldTransform[2].w, 0.f));
|
||||
|
||||
|
||||
// Check for a collision
|
||||
if( dist < minDistance )
|
||||
{
|
||||
// Project back to surface along normal
|
||||
position = closestPointOnSurface;
|
||||
velocity = (position - previousPosition) * velocityCoefficient * isolverdt;
|
||||
float4 relativeVelocity = velocity - velocityOfSurfacePoint;
|
||||
|
||||
float4 p1 = mynormalize3(cross(normalVector, segment));
|
||||
float4 p2 = mynormalize3(cross(p1, normalVector));
|
||||
|
||||
float4 tangentialVel = p1*mydot3a(relativeVelocity, p1) + p2*mydot3a(relativeVelocity, p2);
|
||||
float frictionCoef = (colliderFriction * clothFriction);
|
||||
if (frictionCoef>1.f)
|
||||
frictionCoef = 1.f;
|
||||
|
||||
//only apply friction if objects are not moving apart
|
||||
float projVel = mydot3a(relativeVelocity,normalVector);
|
||||
if ( projVel >= -0.001f)
|
||||
{
|
||||
if ( inverseMass > 0 )
|
||||
{
|
||||
//float4 myforceOnVertex = -tangentialVel * frictionCoef * isolverdt * (1.0f / inverseMass);
|
||||
position += (-tangentialVel * frictionCoef) / (isolverdt);
|
||||
}
|
||||
}
|
||||
|
||||
// In case of no collision, this is the value of velocity
|
||||
velocity = (position - previousPosition) * velocityCoefficient * isolverdt;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_vertexVelocities[nodeID] = (float4)(velocity.xyz, 0.f);
|
||||
|
||||
// Update external force
|
||||
g_vertexForces[nodeID] = (float4)(forceOnVertex.xyz, 0.f);
|
||||
|
||||
g_vertexPositions[nodeID] = (float4)(position.xyz, 0.f);
|
||||
}
|
||||
|
||||
);
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
|
||||
|
||||
|
||||
MSTRINGIFY(
|
||||
|
||||
|
||||
float mydot3(float4 a, float4 b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
}
|
||||
|
||||
|
||||
__kernel void
|
||||
SolvePositionsFromLinksKernel(
|
||||
const int startLink,
|
||||
const int numLinks,
|
||||
const float kst,
|
||||
const float ti,
|
||||
__global int2 * g_linksVertexIndices,
|
||||
__global float * g_linksMassLSC,
|
||||
__global float * g_linksRestLengthSquared,
|
||||
__global float * g_verticesInverseMass,
|
||||
__global float4 * g_vertexPositions GUID_ARG)
|
||||
|
||||
{
|
||||
int linkID = get_global_id(0) + startLink;
|
||||
if( get_global_id(0) < numLinks )
|
||||
{
|
||||
float massLSC = g_linksMassLSC[linkID];
|
||||
float restLengthSquared = g_linksRestLengthSquared[linkID];
|
||||
|
||||
if( massLSC > 0.0f )
|
||||
{
|
||||
int2 nodeIndices = g_linksVertexIndices[linkID];
|
||||
int node0 = nodeIndices.x;
|
||||
int node1 = nodeIndices.y;
|
||||
|
||||
float4 position0 = g_vertexPositions[node0];
|
||||
float4 position1 = g_vertexPositions[node1];
|
||||
|
||||
float inverseMass0 = g_verticesInverseMass[node0];
|
||||
float inverseMass1 = g_verticesInverseMass[node1];
|
||||
|
||||
float4 del = position1 - position0;
|
||||
float len = mydot3(del, del);
|
||||
float k = ((restLengthSquared - len)/(massLSC*(restLengthSquared+len)))*kst;
|
||||
position0 = position0 - del*(k*inverseMass0);
|
||||
position1 = position1 + del*(k*inverseMass1);
|
||||
|
||||
g_vertexPositions[node0] = position0;
|
||||
g_vertexPositions[node1] = position1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
MSTRINGIFY(
|
||||
|
||||
float mydot3(float4 a, float4 b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
}
|
||||
|
||||
__kernel __attribute__((reqd_work_group_size(WAVEFRONT_BLOCK_MULTIPLIER*WAVEFRONT_SIZE, 1, 1)))
|
||||
void
|
||||
SolvePositionsFromLinksKernel(
|
||||
const int startWaveInBatch,
|
||||
const int numWaves,
|
||||
const float kst,
|
||||
const float ti,
|
||||
__global int2 *g_wavefrontBatchCountsVertexCounts,
|
||||
__global int *g_vertexAddressesPerWavefront,
|
||||
__global int2 * g_linksVertexIndices,
|
||||
__global float * g_linksMassLSC,
|
||||
__global float * g_linksRestLengthSquared,
|
||||
__global float * g_verticesInverseMass,
|
||||
__global float4 * g_vertexPositions,
|
||||
__local int2 *wavefrontBatchCountsVertexCounts,
|
||||
__local float4 *vertexPositionSharedData,
|
||||
__local float *vertexInverseMassSharedData)
|
||||
{
|
||||
const int laneInWavefront = (get_global_id(0) & (WAVEFRONT_SIZE-1));
|
||||
const int wavefront = startWaveInBatch + (get_global_id(0) / WAVEFRONT_SIZE);
|
||||
const int firstWavefrontInBlock = startWaveInBatch + get_group_id(0) * WAVEFRONT_BLOCK_MULTIPLIER;
|
||||
const int localWavefront = wavefront - firstWavefrontInBlock;
|
||||
|
||||
// Mask out in case there's a stray "wavefront" at the end that's been forced in through the multiplier
|
||||
if( wavefront < (startWaveInBatch + numWaves) )
|
||||
{
|
||||
// Load the batch counts for the wavefronts
|
||||
|
||||
int2 batchesAndVerticesWithinWavefront = g_wavefrontBatchCountsVertexCounts[wavefront];
|
||||
int batchesWithinWavefront = batchesAndVerticesWithinWavefront.x;
|
||||
int verticesUsedByWave = batchesAndVerticesWithinWavefront.y;
|
||||
|
||||
// Load the vertices for the wavefronts
|
||||
for( int vertex = laneInWavefront; vertex < verticesUsedByWave; vertex+=WAVEFRONT_SIZE )
|
||||
{
|
||||
int vertexAddress = g_vertexAddressesPerWavefront[wavefront*MAX_NUM_VERTICES_PER_WAVE + vertex];
|
||||
|
||||
vertexPositionSharedData[localWavefront*MAX_NUM_VERTICES_PER_WAVE + vertex] = g_vertexPositions[vertexAddress];
|
||||
vertexInverseMassSharedData[localWavefront*MAX_NUM_VERTICES_PER_WAVE + vertex] = g_verticesInverseMass[vertexAddress];
|
||||
}
|
||||
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
// Loop through the batches performing the solve on each in LDS
|
||||
int baseDataLocationForWave = WAVEFRONT_SIZE * wavefront * MAX_BATCHES_PER_WAVE;
|
||||
|
||||
//for( int batch = 0; batch < batchesWithinWavefront; ++batch )
|
||||
|
||||
int batch = 0;
|
||||
do
|
||||
{
|
||||
int baseDataLocation = baseDataLocationForWave + WAVEFRONT_SIZE * batch;
|
||||
int locationOfValue = baseDataLocation + laneInWavefront;
|
||||
|
||||
|
||||
// These loads should all be perfectly linear across the WF
|
||||
int2 localVertexIndices = g_linksVertexIndices[locationOfValue];
|
||||
float massLSC = g_linksMassLSC[locationOfValue];
|
||||
float restLengthSquared = g_linksRestLengthSquared[locationOfValue];
|
||||
|
||||
// LDS vertex addresses based on logical wavefront number in block and loaded index
|
||||
int vertexAddress0 = MAX_NUM_VERTICES_PER_WAVE * localWavefront + localVertexIndices.x;
|
||||
int vertexAddress1 = MAX_NUM_VERTICES_PER_WAVE * localWavefront + localVertexIndices.y;
|
||||
|
||||
float4 position0 = vertexPositionSharedData[vertexAddress0];
|
||||
float4 position1 = vertexPositionSharedData[vertexAddress1];
|
||||
|
||||
float inverseMass0 = vertexInverseMassSharedData[vertexAddress0];
|
||||
float inverseMass1 = vertexInverseMassSharedData[vertexAddress1];
|
||||
|
||||
float4 del = position1 - position0;
|
||||
float len = mydot3(del, del);
|
||||
|
||||
float k = 0;
|
||||
if( massLSC > 0.0f )
|
||||
{
|
||||
k = ((restLengthSquared - len)/(massLSC*(restLengthSquared+len)))*kst;
|
||||
}
|
||||
|
||||
position0 = position0 - del*(k*inverseMass0);
|
||||
position1 = position1 + del*(k*inverseMass1);
|
||||
|
||||
// Ensure compiler does not re-order memory operations
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
vertexPositionSharedData[vertexAddress0] = position0;
|
||||
vertexPositionSharedData[vertexAddress1] = position1;
|
||||
|
||||
// Ensure compiler does not re-order memory operations
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
|
||||
++batch;
|
||||
} while( batch < batchesWithinWavefront );
|
||||
|
||||
// Update the global memory vertices for the wavefronts
|
||||
for( int vertex = laneInWavefront; vertex < verticesUsedByWave; vertex+=WAVEFRONT_SIZE )
|
||||
{
|
||||
int vertexAddress = g_vertexAddressesPerWavefront[wavefront*MAX_NUM_VERTICES_PER_WAVE + vertex];
|
||||
|
||||
g_vertexPositions[vertexAddress] = (float4)(vertexPositionSharedData[localWavefront*MAX_NUM_VERTICES_PER_WAVE + vertex].xyz, 0.f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
);
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
/*#define float3 float4
|
||||
|
||||
float dot3(float3 a, float3 b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
}*/
|
||||
|
||||
__kernel void
|
||||
UpdateConstantsKernel(
|
||||
const int numLinks,
|
||||
__global int2 * g_linksVertexIndices,
|
||||
__global float4 * g_vertexPositions,
|
||||
__global float * g_vertexInverseMasses,
|
||||
__global float * g_linksMaterialLSC,
|
||||
__global float * g_linksMassLSC,
|
||||
__global float * g_linksRestLengthSquared,
|
||||
__global float * g_linksRestLengths)
|
||||
{
|
||||
int linkID = get_global_id(0);
|
||||
if( linkID < numLinks )
|
||||
{
|
||||
int2 nodeIndices = g_linksVertexIndices[linkID];
|
||||
int node0 = nodeIndices.x;
|
||||
int node1 = nodeIndices.y;
|
||||
float linearStiffnessCoefficient = g_linksMaterialLSC[ linkID ];
|
||||
|
||||
float3 position0 = g_vertexPositions[node0].xyz;
|
||||
float3 position1 = g_vertexPositions[node1].xyz;
|
||||
float inverseMass0 = g_vertexInverseMasses[node0];
|
||||
float inverseMass1 = g_vertexInverseMasses[node1];
|
||||
|
||||
float3 difference = position0 - position1;
|
||||
float length2 = dot(difference, difference);
|
||||
float length = sqrt(length2);
|
||||
|
||||
g_linksRestLengths[linkID] = length;
|
||||
g_linksMassLSC[linkID] = (inverseMass0 + inverseMass1)/linearStiffnessCoefficient;
|
||||
g_linksRestLengthSquared[linkID] = length*length;
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
__kernel void
|
||||
UpdateFixedVertexPositions(
|
||||
const uint numNodes,
|
||||
__global int * g_anchorIndex,
|
||||
__global float4 * g_vertexPositions,
|
||||
__global float4 * g_anchorPositions GUID_ARG)
|
||||
{
|
||||
unsigned int nodeID = get_global_id(0);
|
||||
|
||||
if( nodeID < numNodes )
|
||||
{
|
||||
int anchorIndex = g_anchorIndex[nodeID];
|
||||
float4 position = g_vertexPositions[nodeID];
|
||||
|
||||
if ( anchorIndex >= 0 )
|
||||
{
|
||||
float4 anchorPosition = g_anchorPositions[anchorIndex];
|
||||
g_vertexPositions[nodeID] = anchorPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
|
||||
__kernel void
|
||||
updateVelocitiesFromPositionsWithVelocitiesKernel(
|
||||
int numNodes,
|
||||
float isolverdt,
|
||||
__global float4 * g_vertexPositions,
|
||||
__global float4 * g_vertexPreviousPositions,
|
||||
__global int * g_vertexClothIndices,
|
||||
__global float *g_clothVelocityCorrectionCoefficients,
|
||||
__global float * g_clothDampingFactor,
|
||||
__global float4 * g_vertexVelocities,
|
||||
__global float4 * g_vertexForces GUID_ARG)
|
||||
{
|
||||
int nodeID = get_global_id(0);
|
||||
if( nodeID < numNodes )
|
||||
{
|
||||
float4 position = g_vertexPositions[nodeID];
|
||||
float4 previousPosition = g_vertexPreviousPositions[nodeID];
|
||||
float4 velocity = g_vertexVelocities[nodeID];
|
||||
int clothIndex = g_vertexClothIndices[nodeID];
|
||||
float velocityCorrectionCoefficient = g_clothVelocityCorrectionCoefficients[clothIndex];
|
||||
float dampingFactor = g_clothDampingFactor[clothIndex];
|
||||
float velocityCoefficient = (1.f - dampingFactor);
|
||||
|
||||
float4 difference = position - previousPosition;
|
||||
|
||||
velocity += difference*velocityCorrectionCoefficient*isolverdt;
|
||||
|
||||
// Damp the velocity
|
||||
velocity *= velocityCoefficient;
|
||||
|
||||
g_vertexVelocities[nodeID] = velocity;
|
||||
g_vertexForces[nodeID] = (float4)(0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
float length3(float4 a)
|
||||
{
|
||||
a.w = 0;
|
||||
return length(a);
|
||||
}
|
||||
|
||||
float4 normalize3(float4 a)
|
||||
{
|
||||
a.w = 0;
|
||||
return normalize(a);
|
||||
}
|
||||
|
||||
__kernel void
|
||||
ResetNormalsAndAreasKernel(
|
||||
const unsigned int numNodes,
|
||||
__global float4 * g_vertexNormals,
|
||||
__global float * g_vertexArea GUID_ARG)
|
||||
{
|
||||
if( get_global_id(0) < numNodes )
|
||||
{
|
||||
g_vertexNormals[get_global_id(0)] = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
g_vertexArea[get_global_id(0)] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__kernel void
|
||||
UpdateSoftBodiesKernel(
|
||||
const unsigned int startFace,
|
||||
const unsigned int numFaces,
|
||||
__global int4 * g_triangleVertexIndexSet,
|
||||
__global float4 * g_vertexPositions,
|
||||
__global float4 * g_vertexNormals,
|
||||
__global float * g_vertexArea,
|
||||
__global float4 * g_triangleNormals,
|
||||
__global float * g_triangleArea GUID_ARG)
|
||||
{
|
||||
int faceID = get_global_id(0) + startFace;
|
||||
if( get_global_id(0) < numFaces )
|
||||
{
|
||||
int4 triangleIndexSet = g_triangleVertexIndexSet[ faceID ];
|
||||
int nodeIndex0 = triangleIndexSet.x;
|
||||
int nodeIndex1 = triangleIndexSet.y;
|
||||
int nodeIndex2 = triangleIndexSet.z;
|
||||
|
||||
float4 node0 = g_vertexPositions[nodeIndex0];
|
||||
float4 node1 = g_vertexPositions[nodeIndex1];
|
||||
float4 node2 = g_vertexPositions[nodeIndex2];
|
||||
float4 nodeNormal0 = g_vertexNormals[nodeIndex0];
|
||||
float4 nodeNormal1 = g_vertexNormals[nodeIndex1];
|
||||
float4 nodeNormal2 = g_vertexNormals[nodeIndex2];
|
||||
float vertexArea0 = g_vertexArea[nodeIndex0];
|
||||
float vertexArea1 = g_vertexArea[nodeIndex1];
|
||||
float vertexArea2 = g_vertexArea[nodeIndex2];
|
||||
|
||||
float4 vector0 = node1 - node0;
|
||||
float4 vector1 = node2 - node0;
|
||||
|
||||
float4 faceNormal = cross(vector0, vector1);
|
||||
float triangleArea = length(faceNormal);
|
||||
|
||||
nodeNormal0 = nodeNormal0 + faceNormal;
|
||||
nodeNormal1 = nodeNormal1 + faceNormal;
|
||||
nodeNormal2 = nodeNormal2 + faceNormal;
|
||||
vertexArea0 = vertexArea0 + triangleArea;
|
||||
vertexArea1 = vertexArea1 + triangleArea;
|
||||
vertexArea2 = vertexArea2 + triangleArea;
|
||||
|
||||
g_triangleNormals[faceID] = normalize3(faceNormal);
|
||||
g_vertexNormals[nodeIndex0] = nodeNormal0;
|
||||
g_vertexNormals[nodeIndex1] = nodeNormal1;
|
||||
g_vertexNormals[nodeIndex2] = nodeNormal2;
|
||||
g_triangleArea[faceID] = triangleArea;
|
||||
g_vertexArea[nodeIndex0] = vertexArea0;
|
||||
g_vertexArea[nodeIndex1] = vertexArea1;
|
||||
g_vertexArea[nodeIndex2] = vertexArea2;
|
||||
}
|
||||
}
|
||||
|
||||
__kernel void
|
||||
NormalizeNormalsAndAreasKernel(
|
||||
const unsigned int numNodes,
|
||||
__global int * g_vertexTriangleCount,
|
||||
__global float4 * g_vertexNormals,
|
||||
__global float * g_vertexArea GUID_ARG)
|
||||
{
|
||||
if( get_global_id(0) < numNodes )
|
||||
{
|
||||
float4 normal = g_vertexNormals[get_global_id(0)];
|
||||
float area = g_vertexArea[get_global_id(0)];
|
||||
int numTriangles = g_vertexTriangleCount[get_global_id(0)];
|
||||
|
||||
float vectorLength = length3(normal);
|
||||
|
||||
g_vertexNormals[get_global_id(0)] = normalize3(normal);
|
||||
g_vertexArea[get_global_id(0)] = area/(float)(numTriangles);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
__kernel void
|
||||
updateVelocitiesFromPositionsWithoutVelocitiesKernel(
|
||||
const int numNodes,
|
||||
const float isolverdt,
|
||||
__global float4 * g_vertexPositions,
|
||||
__global float4 * g_vertexPreviousPositions,
|
||||
__global int * g_vertexClothIndices,
|
||||
__global float * g_clothDampingFactor,
|
||||
__global float4 * g_vertexVelocities,
|
||||
__global float4 * g_vertexForces GUID_ARG)
|
||||
|
||||
{
|
||||
int nodeID = get_global_id(0);
|
||||
if( nodeID < numNodes )
|
||||
{
|
||||
float4 position = g_vertexPositions[nodeID];
|
||||
float4 previousPosition = g_vertexPreviousPositions[nodeID];
|
||||
float4 velocity = g_vertexVelocities[nodeID];
|
||||
int clothIndex = g_vertexClothIndices[nodeID];
|
||||
float dampingFactor = g_clothDampingFactor[clothIndex];
|
||||
float velocityCoefficient = (1.f - dampingFactor);
|
||||
|
||||
float4 difference = position - previousPosition;
|
||||
|
||||
velocity = difference*velocityCoefficient*isolverdt;
|
||||
|
||||
g_vertexVelocities[nodeID] = velocity;
|
||||
g_vertexForces[nodeID] = (float4)(0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
|
||||
MSTRINGIFY(
|
||||
|
||||
|
||||
|
||||
|
||||
__kernel void
|
||||
UpdatePositionsFromVelocitiesKernel(
|
||||
const int numNodes,
|
||||
const float solverSDT,
|
||||
__global float4 * g_vertexVelocities,
|
||||
__global float4 * g_vertexPreviousPositions,
|
||||
__global float4 * g_vertexCurrentPosition GUID_ARG)
|
||||
{
|
||||
int vertexID = get_global_id(0);
|
||||
if( vertexID < numNodes )
|
||||
{
|
||||
float4 previousPosition = g_vertexPreviousPositions[vertexID];
|
||||
float4 velocity = g_vertexVelocities[vertexID];
|
||||
|
||||
float4 newPosition = previousPosition + velocity*solverSDT;
|
||||
|
||||
g_vertexCurrentPosition[vertexID] = newPosition;
|
||||
g_vertexPreviousPositions[vertexID] = newPosition;
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
MSTRINGIFY(
|
||||
|
||||
__kernel void
|
||||
VSolveLinksKernel(
|
||||
int startLink,
|
||||
int numLinks,
|
||||
float kst,
|
||||
__global int2 * g_linksVertexIndices,
|
||||
__global float * g_linksLengthRatio,
|
||||
__global float4 * g_linksCurrentLength,
|
||||
__global float * g_vertexInverseMass,
|
||||
__global float4 * g_vertexVelocity GUID_ARG)
|
||||
{
|
||||
int linkID = get_global_id(0) + startLink;
|
||||
if( get_global_id(0) < numLinks )
|
||||
{
|
||||
int2 nodeIndices = g_linksVertexIndices[linkID];
|
||||
int node0 = nodeIndices.x;
|
||||
int node1 = nodeIndices.y;
|
||||
|
||||
float linkLengthRatio = g_linksLengthRatio[linkID];
|
||||
float3 linkCurrentLength = g_linksCurrentLength[linkID].xyz;
|
||||
|
||||
float3 vertexVelocity0 = g_vertexVelocity[node0].xyz;
|
||||
float3 vertexVelocity1 = g_vertexVelocity[node1].xyz;
|
||||
|
||||
float vertexInverseMass0 = g_vertexInverseMass[node0];
|
||||
float vertexInverseMass1 = g_vertexInverseMass[node1];
|
||||
|
||||
float3 nodeDifference = vertexVelocity0 - vertexVelocity1;
|
||||
float dotResult = dot(linkCurrentLength, nodeDifference);
|
||||
float j = -dotResult*linkLengthRatio*kst;
|
||||
|
||||
float3 velocityChange0 = linkCurrentLength*(j*vertexInverseMass0);
|
||||
float3 velocityChange1 = linkCurrentLength*(j*vertexInverseMass1);
|
||||
|
||||
vertexVelocity0 += velocityChange0;
|
||||
vertexVelocity1 -= velocityChange1;
|
||||
|
||||
g_vertexVelocity[node0] = (float4)(vertexVelocity0, 0.f);
|
||||
g_vertexVelocity[node1] = (float4)(vertexVelocity1, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
Reference in New Issue
Block a user