How do you setup a simulation with Nvidia Flex?

430 views Asked by At

I've read through the docs https://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/flex/manual.html?ncid=afm-chs-44270&ranMID=44270&ranEAID=a1LgFw09t88&ranSiteID=a1LgFw09t88-TGVNs5HtsNwQmL1xZ5XT8A#particles

But I still can't get a working simulation. Are there any Debug options I dont't know about?

I got Flex from https://github.com/NVIDIAGameWorks/FleX

Here's my code:

#pragma once
#include "FlexPhysics.h"
#include "NvFlex.h"
#include "NvFlexExt.h"
#include <iostream>

NvFlexBuffer* particleBuffer;
NvFlexBuffer* velocityBuffer;
NvFlexBuffer* phaseBuffer;

struct Vec4struct {
    float x, y, z, w;
};

void MyErrorCallback(NvFlexErrorSeverity severity, const char* msg, const char* file, int line)
{
    std::cout << "Flex: %s - %s:%d\n" << msg << file << line << std::endl;
}
    
int n = 10000;

int main() {

    NvFlexLibrary* library = NvFlexInit(120, MyErrorCallback);

    // create new solver
    NvFlexSolverDesc solverDesc;
    NvFlexSetSolverDescDefaults(&solverDesc);
    solverDesc.maxParticles = n;
    solverDesc.maxDiffuseParticles = 0;

    NvFlexSolver* solver = NvFlexCreateSolver(library, &solverDesc);

    particleBuffer = NvFlexAllocBuffer(library, n, sizeof(Vec4struct), eNvFlexBufferHost);
    velocityBuffer = NvFlexAllocBuffer(library, n, sizeof(Vec4struct), eNvFlexBufferHost);
    phaseBuffer = NvFlexAllocBuffer(library, n, sizeof(int), eNvFlexBufferHost);

    //set params
    NvFlexParams p;
    p.gravity[0] = -10.0f;
    p.radius = 0.01f;
    p.drag = 0.1f;
    p.damping = 0.0f;
    NvFlexSetParams(solver, &p);

    //spawn particles
    int particle_count = 6;
    float particle_mass = 100;

    //map buffers
    Vec4struct* particles = (Vec4struct*)NvFlexMap(particleBuffer, eNvFlexMapWait);
    Vec4struct* velocities = (Vec4struct*)NvFlexMap(velocityBuffer, eNvFlexMapWait);
    int* phases = (int*)NvFlexMap(phaseBuffer, eNvFlexMapWait);

    for (int i = 0; i < particle_count; ++i)
    {
        particles[i] = { i * 5.0f,0,0, 1.0f / particle_mass };
        velocities[i] = { 0.0f,0.0f,0.0f};
        phases[i] = NvFlexMakePhase(0, 1);
    }

    //unmap buffers
    NvFlexUnmap(particleBuffer);
    NvFlexUnmap(velocityBuffer);
    NvFlexUnmap(phaseBuffer);

    NvFlexSetParticles(solver, particleBuffer, NULL);
    NvFlexSetVelocities(solver, velocityBuffer, NULL);
    NvFlexSetPhases(solver, phaseBuffer, NULL);

    float delta_time = 1 / 60.0f;

    while (true)
    {
        //map buffers
        Vec4struct* particles = (Vec4struct*)NvFlexMap(particleBuffer, eNvFlexMapWait);
        Vec4struct* velocities = (Vec4struct*)NvFlexMap(velocityBuffer, eNvFlexMapWait);
        int* phases = (int*)NvFlexMap(phaseBuffer, eNvFlexMapWait);

        //"draw" particles
        std::cout << "x:" << particles[0].x << " y:" << particles[0].y << " z:" << particles[0].z << std::endl;
        
        //unmap buffers
        NvFlexUnmap(particleBuffer);
        NvFlexUnmap(velocityBuffer);
        NvFlexUnmap(phaseBuffer);

        // set active count
        NvFlexSetActiveCount(solver, particle_count);

        // tick
        NvFlexUpdateSolver(solver, delta_time, 1, false);

        // read back (async)
        NvFlexGetParticles(solver, particleBuffer, NULL);
        NvFlexGetVelocities(solver, velocityBuffer, NULL);
        NvFlexGetPhases(solver, phaseBuffer, NULL);
    }
    
    NvFlexFreeBuffer(particleBuffer);
    NvFlexFreeBuffer(velocityBuffer);
    NvFlexFreeBuffer(phaseBuffer);

    NvFlexDestroySolver(solver);
    NvFlexShutdown(library);

    return 0;
}

Here's some of the Output:

x:0 y:0 z:0
x:0 y:0 z:0
x:0 y:0 z:0
x:0 y:0 z:0
x:0 y:0 z:0
x:0 y:0 z:0
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00274073 y:1.26542e+06 z:1.26542e+06
x:0.00550891 y:2.53083e+06 z:2.53083e+06
x:0.00550891 y:2.53083e+06 z:2.53083e+06
x:0.00550891 y:2.53083e+06 z:2.53083e+06
x:0.00550891 y:2.53083e+06 z:2.53083e+06
x:0.00550891 y:2.53083e+06 z:2.53083e+06
x:0.00550891 y:2.53083e+06 z:2.53083e+06
x:0.00550891 y:2.53083e+06 z:2.53083e+06
x:0.00550891 y:2.53083e+06 z:2.53083e+06
x:0.00550891 y:2.53083e+06 z:2.53083e+06

Now I'd expect the particles to start Falling to the right. Im not sure the data I load into the particlebuffer is correct how can I check that? All the docs say is [float x, float y, float z, inverse_mass]. What Parameters should I check?

And all I can find to the buffer is:

/**
 * Opaque type representing a data buffer, type and contents depends on usage, see NvFlexAllocBuffer()
 */
typedef struct NvFlexBuffer NvFlexBuffer;
1

There are 1 answers

0
ENR813 On

You Have to Initialize all the Flex Params or else it simple wont work, i think this is because they're saved in a struct.

#pragma once
#include "FlexPhysics.h"
#include "NvFlex.h"
#include "NvFlexExt.h"
#include <iostream>

NvFlexBuffer* particleBuffer;
NvFlexBuffer* velocityBuffer;
NvFlexBuffer* phaseBuffer;

struct Vec4struct {
    float x, y, z, w;
};

void MyErrorCallback(NvFlexErrorSeverity severity, const char* msg, const char* file, int line)
{
    std::cout << "Flex: %s - %s:%d\n" << msg << file << line << std::endl;
}

int n = 10000;

int main() {

    NvFlexLibrary* library = NvFlexInit(120, MyErrorCallback);

    // create new solver
    NvFlexSolverDesc solverDesc;
    NvFlexSetSolverDescDefaults(&solverDesc);
    solverDesc.maxParticles = n;
    solverDesc.maxDiffuseParticles = 0;

    NvFlexSolver* solver = NvFlexCreateSolver(library, &solverDesc);

    particleBuffer = NvFlexAllocBuffer(library, n, sizeof(Vec4struct), eNvFlexBufferHost);
    velocityBuffer = NvFlexAllocBuffer(library, n, sizeof(Vec4struct), eNvFlexBufferHost);
    phaseBuffer = NvFlexAllocBuffer(library, n, sizeof(int), eNvFlexBufferHost);

    //set params
    NvFlexParams p;

    int numIterations = 2;                  //!< Number of solver iterations to perform per-substep

    p.gravity[0] = 0;
    p.gravity[1] = -10.0f;
    p.gravity[2] = 0;                       //!< Constant acceleration applied to all particles
    p.radius = 0.01;                        //!< The maximum interaction radius for particles
    p.solidRestDistance = 0.005;            //!< The distance non-fluid particles attempt to maintain from each other, must be in the range (0, radius]
    p.fluidRestDistance = 0.001;            //!< The distance fluid particles are spaced at the rest density, must be in the range (0, radius], for fluids this should generally be 50-70% of mRadius, for rigids this can simply be the same as the particle radius

    // common params
    p.dynamicFriction = 1;              //!< Coefficient of friction used when colliding against shapes
    p.staticFriction = 1;               //!< Coefficient of static friction used when colliding against shapes
    p.particleFriction = 1;             //!< Coefficient of friction used when colliding particles
    p.restitution = 1;                  //!< Coefficient of restitution used when colliding against shapes, particle collisions are always inelastic
    p.adhesion = 1;                     //!< Controls how strongly particles stick to surfaces they hit, default 0.0, range [0.0, +inf]
    p.sleepThreshold = 1;               //!< Particles with a velocity magnitude < this threshold will be considered fixed

    p.maxSpeed = 1000;                      //!< The magnitude of particle velocity will be clamped to this value at the end of each step
    p.maxAcceleration = 1000;               //!< The magnitude of particle acceleration will be clamped to this value at the end of each step (limits max velocity change per-second), useful to avoid popping due to large interpenetrations

    p.shockPropagation = 0;             //!< Artificially decrease the mass of particles based on height from a fixed reference point, this makes stacks and piles converge faster
    p.dissipation = 1;                  //!< Damps particle velocity based on how many particle contacts it has
    p.damping = 10;                     //!< Viscous drag force, applies a force proportional, and opposite to the particle velocity

    // cloth params
    p.wind[0] = 0;
    p.wind[0] = 0;
    p.wind[0] = 0;                      //!< Constant acceleration applied to particles that belong to dynamic triangles, drag needs to be > 0 for wind to affect triangles
    p.drag = 1;                         //!< Drag force applied to particles belonging to dynamic triangles, proportional to velocity^2*area in the negative velocity direction
    p.lift = 1;                         //!< Lift force applied to particles belonging to dynamic triangles, proportional to velocity^2*area in the direction perpendicular to velocity and (if possible), parallel to the plane normal

    // fluid params
    p.cohesion = 0.025;                     //!< Control how strongly particles hold each other together, default: 0.025, range [0.0, +inf]
    p.surfaceTension = 0;               //!< Controls how strongly particles attempt to minimize surface area, default: 0.0, range: [0.0, +inf]    
    p.viscosity = 1;                    //!< Smoothes particle velocities using XSPH viscosity
    p.vorticityConfinement = 0;         //!< Increases vorticity by applying rotational forces to particles
    p.anisotropyScale = 0;              //!< Control how much anisotropy is present in resulting ellipsoids for rendering, if zero then anisotropy will not be calculated, see NvFlexGetAnisotropy()
    p.anisotropyMin = 0;                //!< Clamp the anisotropy scale to this fraction of the radius
    p.anisotropyMax = 0;                //!< Clamp the anisotropy scale to this fraction of the radius
    p.smoothing = 1;                    //!< Control the strength of Laplacian smoothing in particles for rendering, if zero then smoothed positions will not be calculated, see NvFlexGetSmoothParticles()
    p.solidPressure = 0;                //!< Add pressure from solid surfaces to particles
    p.freeSurfaceDrag = 0;              //!< Drag force applied to boundary fluid particles
    p.buoyancy = 0;                     //!< Gravity is scaled by this value for fluid particles

    // diffuse params
    p.diffuseThreshold = 0;             //!< Particles with kinetic energy + divergence above this threshold will spawn new diffuse particles
    p.diffuseBuoyancy = 0;              //!< Scales force opposing gravity that diffuse particles receive
    p.diffuseDrag = 0;                  //!< Scales force diffuse particles receive in direction of neighbor fluid particles
    p.diffuseBallistic = 0;             //!< The number of neighbors below which a diffuse particle is considered ballistic
    p.diffuseLifetime = 0;              //!< Time in seconds that a diffuse particle will live for after being spawned, particles will be spawned with a random lifetime in the range [0, diffuseLifetime]

    // collision params
    p.collisionDistance = 0.01;         //!< Distance particles maintain against shapes, note that for robust collision against triangle meshes this distance should be greater than zero
    p.particleCollisionMargin = 1;      //!< Increases the radius used during neighbor finding, this is useful if particles are expected to move significantly during a single step to ensure contacts aren't missed on subsequent iterations
    p.shapeCollisionMargin = 0;         //!< Increases the radius used during contact finding against kinematic shapes

    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 4; j++) {
            p.planes[i][j] = 0;
        }
    }                                       //!< Collision planes in the form ax + by + cz + d = 0
    p.numPlanes = 0;                        //!< Num collision planes

    p.relaxationMode = NvFlexRelaxationMode::eNvFlexRelaxationGlobal;   //!< How the relaxation is applied inside the solver
    p.relaxationFactor = 1;                                             //!< Control the convergence rate of the parallel solver, default: 1, values greater than 1 may lead to instability

    NvFlexSetParams(solver, &p);

    //spawn particles
    int particle_count = 6;
    float particle_mass = 100;

    //map buffers
    Vec4struct* particles = (Vec4struct*)NvFlexMap(particleBuffer, eNvFlexMapWait);
    Vec4struct* velocities = (Vec4struct*)NvFlexMap(velocityBuffer, eNvFlexMapWait);
    int* phases = (int*)NvFlexMap(phaseBuffer, eNvFlexMapWait);

    for (int i = 0; i < particle_count; ++i)
    {
        particles[i] = { i * 5.0f,0,0, 1.0f / particle_mass };
        velocities[i] = { 0.0f,0.0f,0.0f };
        phases[i] = NvFlexMakePhase(0, 1);
    }

    //unmap buffers
    NvFlexUnmap(particleBuffer);
    NvFlexUnmap(velocityBuffer);
    NvFlexUnmap(phaseBuffer);

    NvFlexSetParticles(solver, particleBuffer, NULL);
    NvFlexSetVelocities(solver, velocityBuffer, NULL);
    NvFlexSetPhases(solver, phaseBuffer, NULL);

    float delta_time = 1 / 60.0f;

    while (true)
    {
        //map buffers
        Vec4struct* particles = (Vec4struct*)NvFlexMap(particleBuffer, eNvFlexMapWait);
        Vec4struct* velocities = (Vec4struct*)NvFlexMap(velocityBuffer, eNvFlexMapWait);
        int* phases = (int*)NvFlexMap(phaseBuffer, eNvFlexMapWait);

        //"draw" particles
        std::cout << "x:" << particles[0].x << " y:" << particles[0].y << " z:" << particles[0].z << std::endl;

        //unmap buffers
        NvFlexUnmap(particleBuffer);
        NvFlexUnmap(velocityBuffer);
        NvFlexUnmap(phaseBuffer);

        // set active count
        NvFlexSetActiveCount(solver, particle_count);

        // tick
        NvFlexUpdateSolver(solver, delta_time, 1, false);

        // read back (async)
        NvFlexGetParticles(solver, particleBuffer, NULL);
        NvFlexGetVelocities(solver, velocityBuffer, NULL);
        NvFlexGetPhases(solver, phaseBuffer, NULL);
    }

    NvFlexFreeBuffer(particleBuffer);
    NvFlexFreeBuffer(velocityBuffer);
    NvFlexFreeBuffer(phaseBuffer);

    NvFlexDestroySolver(solver);
    NvFlexShutdown(library);

    return 0;
}