您如何使用 Nvidia Flex 设置模拟?

问题描述

我已通读文档 https://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/flex/manual.html?ncid=afm-chs-44270&ranMID=44270&ranEAID=a1LgFw09t88&ranSiteID=a1LgFw09t88-TGVNs5HtsNwQmL1xZ5XT8A#particles

但我仍然无法获得有效的模拟。是否有任何我不知道的调试选项?

我从 https://github.com/NVIDIAGameWorks/FleX 获得了 Flex

这是我的代码

#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,eNvFlexBufferHost);
    phaseBuffer = NvFlexAllocBuffer(library,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,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,NULL);
        NvFlexGetVeLocities(solver,NULL);
        NvFlexGetPhases(solver,NULL);
    }
    
    NvFlexFreeBuffer(particleBuffer);
    NvFlexFreeBuffer(veLocityBuffer);
    NvFlexFreeBuffer(phaseBuffer);

    NvFlexDestroySolver(solver);
    NvFlexShutdown(library);

    return 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 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

现在我希望粒子开始向右下落。我不确定我加载到粒子缓冲区中的数据是否正确,我该如何检查?所有的文档都说是 [浮动x,浮动y,浮动z,inverse_mass]。我应该检查哪些参数?

我能找到的缓冲区是:

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

解决方法

你必须初始化所有的 Flex 参数,否则它很简单就行不通,我认为这是因为它们保存在一个结构中。

#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,eNvFlexBufferHost);
    phaseBuffer = NvFlexAllocBuffer(library,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,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,+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,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,NULL);
        NvFlexGetVelocities(solver,NULL);
        NvFlexGetPhases(solver,NULL);
    }

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

    NvFlexDestroySolver(solver);
    NvFlexShutdown(library);

    return 0;
}