|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <cuda.h> |
|
|
#include <cuda_runtime_api.h> |
|
|
|
|
|
#include <vector> |
|
|
#include <limits> |
|
|
#include <algorithm> |
|
|
|
|
|
#include "../../core/core.h" |
|
|
#include "../../core/maths.h" |
|
|
|
|
|
#include "../../include/NvFlex.h" |
|
|
#include "../../include/NvFlexExt.h" |
|
|
|
|
|
#define CudaCheck(x) { cudaError_t err = x; if (err != cudaSuccess) { printf("Cuda error: %d in %s at %s:%d\n", err, #x, __FILE__, __LINE__); assert(0); } } |
|
|
|
|
|
static const int kNumThreadsPerBlock = 256; |
|
|
|
|
|
struct NvFlexExtForceFieldCallback |
|
|
{ |
|
|
NvFlexExtForceFieldCallback(NvFlexSolver* solver) : mSolver(solver) |
|
|
{ |
|
|
|
|
|
mForceFieldsCpu = NULL; |
|
|
mForceFieldsGpu = NULL; |
|
|
mMaxForceFields = 0; |
|
|
mNumForceFields = 0; |
|
|
|
|
|
} |
|
|
|
|
|
~NvFlexExtForceFieldCallback() |
|
|
{ |
|
|
|
|
|
CudaCheck(cudaFreeHost(mForceFieldsCpu)); |
|
|
CudaCheck(cudaFree(mForceFieldsGpu)); |
|
|
} |
|
|
|
|
|
NvFlexExtForceField* mForceFieldsCpu; |
|
|
NvFlexExtForceField* mForceFieldsGpu; |
|
|
|
|
|
int mMaxForceFields; |
|
|
int mNumForceFields; |
|
|
|
|
|
NvFlexSolver* mSolver; |
|
|
}; |
|
|
|
|
|
NvFlexExtForceFieldCallback* NvFlexExtCreateForceFieldCallback(NvFlexSolver* solver) |
|
|
{ |
|
|
return new NvFlexExtForceFieldCallback(solver); |
|
|
} |
|
|
|
|
|
void NvFlexExtDestroyForceFieldCallback(NvFlexExtForceFieldCallback* callback) |
|
|
{ |
|
|
delete callback; |
|
|
} |
|
|
|
|
|
|
|
|
__global__ void UpdateForceFields(int numParticles, const Vec4* __restrict__ positions, Vec4* __restrict__ velocities, const NvFlexExtForceField* __restrict__ forceFields, int numForceFields, float dt) |
|
|
{ |
|
|
const int i = blockIdx.x*blockDim.x + threadIdx.x; |
|
|
|
|
|
for (int f = 0; f < numForceFields; f++) |
|
|
{ |
|
|
const NvFlexExtForceField& forceField = forceFields[f]; |
|
|
|
|
|
if (i < numParticles) |
|
|
{ |
|
|
const int index = i; |
|
|
|
|
|
Vec4 p = positions[index]; |
|
|
Vec3 v = Vec3(velocities[index]); |
|
|
|
|
|
Vec3 localPos = Vec3(p.x, p.y, p.z) - Vec3(forceField.mPosition[0], forceField.mPosition[1], forceField.mPosition[2]); |
|
|
|
|
|
float length = Length(localPos); |
|
|
if (length >= forceField.mRadius) |
|
|
{ |
|
|
continue; |
|
|
} |
|
|
|
|
|
Vec3 fieldDir; |
|
|
if (length > 0.0f) |
|
|
{ |
|
|
fieldDir = localPos / length; |
|
|
} |
|
|
else |
|
|
{ |
|
|
fieldDir = localPos; |
|
|
} |
|
|
|
|
|
|
|
|
float fieldStrength = forceField.mStrength; |
|
|
if (forceField.mLinearFalloff) |
|
|
{ |
|
|
fieldStrength *= (1.0f - (length / forceField.mRadius)); |
|
|
} |
|
|
|
|
|
|
|
|
Vec3 force = localPos * fieldStrength; |
|
|
|
|
|
float unitMultiplier; |
|
|
if (forceField.mMode == eNvFlexExtModeForce) |
|
|
{ |
|
|
unitMultiplier = dt * p.w; |
|
|
} |
|
|
else if (forceField.mMode == eNvFlexExtModeImpulse) |
|
|
{ |
|
|
unitMultiplier = p.w; |
|
|
} |
|
|
else if (forceField.mMode == eNvFlexExtModeVelocityChange) |
|
|
{ |
|
|
unitMultiplier = 1.0f; |
|
|
} |
|
|
|
|
|
Vec3 deltaVelocity = fieldDir * fieldStrength * unitMultiplier; |
|
|
velocities[index] = Vec4(v + deltaVelocity, 0.0f); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
void ApplyForceFieldsCallback(NvFlexSolverCallbackParams params) |
|
|
{ |
|
|
|
|
|
|
|
|
NvFlexExtForceFieldCallback* c = (NvFlexExtForceFieldCallback*)params.userData; |
|
|
|
|
|
if (params.numActive && c->mNumForceFields) |
|
|
{ |
|
|
const int kNumBlocks = (params.numActive+kNumThreadsPerBlock-1)/kNumThreadsPerBlock; |
|
|
|
|
|
UpdateForceFields<<<kNumBlocks, kNumThreadsPerBlock>>>( |
|
|
params.numActive, |
|
|
(Vec4*)params.particles, |
|
|
(Vec4*)params.velocities, |
|
|
c->mForceFieldsGpu, |
|
|
c->mNumForceFields, |
|
|
params.dt); |
|
|
} |
|
|
} |
|
|
|
|
|
void NvFlexExtSetForceFields(NvFlexExtForceFieldCallback* c, const NvFlexExtForceField* forceFields, int numForceFields) |
|
|
{ |
|
|
|
|
|
if (numForceFields > c->mMaxForceFields) |
|
|
{ |
|
|
CudaCheck(cudaFreeHost(c->mForceFieldsCpu)); |
|
|
CudaCheck(cudaMallocHost(&c->mForceFieldsCpu, sizeof(NvFlexExtForceField)*numForceFields)); |
|
|
|
|
|
CudaCheck(cudaFree(c->mForceFieldsGpu)); |
|
|
CudaCheck(cudaMalloc(&c->mForceFieldsGpu, sizeof(NvFlexExtForceField)*numForceFields)); |
|
|
|
|
|
|
|
|
c->mMaxForceFields = numForceFields; |
|
|
} |
|
|
c->mNumForceFields = numForceFields; |
|
|
|
|
|
if (numForceFields > 0) |
|
|
{ |
|
|
|
|
|
memcpy(c->mForceFieldsCpu, forceFields, numForceFields*sizeof(NvFlexExtForceField)); |
|
|
|
|
|
cudaMemcpyKind kind = cudaMemcpyHostToDevice; |
|
|
CudaCheck(cudaMemcpyAsync(c->mForceFieldsGpu, &c->mForceFieldsCpu[0], numForceFields*sizeof(NvFlexExtForceField), kind, 0)); |
|
|
} |
|
|
|
|
|
NvFlexSolverCallback callback; |
|
|
callback.function = ApplyForceFieldsCallback; |
|
|
callback.userData = c; |
|
|
|
|
|
|
|
|
NvFlexRegisterSolverCallback(c->mSolver, callback, eNvFlexStageUpdateEnd); |
|
|
} |
|
|
|