NvCloth: An Open Source Library Based on C++

In modern game development, virtual reality, and film effects, realistic cloth dynamics are one of the key elements to enhance immersion. NVIDIA’s NvCloth library, as a core component of the PhysX physics engine, provides developers with a high-performance, scalable cloth simulation solution.

1. Introduction to NvCloth

NvCloth is a low-level C++ API that allows developers to create cloth based on a particle-spring model. It supports CPU and GPU accelerated simulations, capable of handling complex physical effects such as collisions, wind, and gravity. As part of PhysX, NvCloth can seamlessly interact with other PhysX features (such as rigid body dynamics).

2. Core Concepts

Before writing code, it is important to understand several key concepts:

  • PxPhysics: The main physics context of PhysX.
  • PxCooking: Used to convert mesh data into collision shapes recognizable by PhysX.
  • NvCloth::Cloth: Represents a cloth object.
  • Particles: The cloth is composed of multiple particles (vertices), each with properties such as position and velocity.
  • Constraints: Constraints define the connections between particles (such as stretching and bending).

3. Code Practice: Creating a Floating Cloth

The following is a simplified C++ example demonstrating how to create and simulate a rectangular cloth using NvCloth.

Step 1: Initialize PhysX and NvCloth

#include "PxPhysicsAPI.h"
#include "NvCloth/Cloth.h"
#include "NvCloth/Factory.h"

using namespace physx;
using namespace nv::cloth;

// Global variables
PxPhysics* gPhysics = nullptr;
PxFoundation* gFoundation = nullptr;
Cloth* gCloth = nullptr;
Factory* gFactory = nullptr;

bool InitializePhysX()
{
    // 1. Create Foundation
    gFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gAllocator, gErrorCallback);
    if (!gFoundation) return false;

    // 2. Create Physics SDK
    gPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gFoundation, PxTolerancesScale());
    if (!gPhysics) return false;

    // 3. Initialize NvCloth Factory
    gFactory = NvClothCreateFactoryCPU(); // Use CPU simulation
    // Or GPU: gFactory = NvClothCreateFactoryCUDA(...);
    if (!gFactory) return false;

    return true;
}

Step 2: Create Cloth Mesh Data

void CreateClothMesh()
{
    // Define a simple 10x10 mesh cloth
    const int width = 10, height = 10;
    const float spacing = 0.1f;

    std::vector<Particle> particles;
    std::vector<uint32_t> indices;

    for (int y = 0; y < height; ++y)
    {
        for (int x = 0; x < width; ++x)
        {
            float px = x * spacing - (width * spacing) / 2.0f;
            float py = 2.0f; // Initial height
            float pz = y * spacing - (height * spacing) / 2.0f;

            particles.push_back({{px, py, pz}, {0.0f, 0.0f, 0.0f}}); // pos, vel
            indices.push_back(y * width + x);
        }
    }

    // Lock the top row of particles (like the top of a flag)
    std::vector<uint32_t> lockIndices;
    for (int x = 0; x < width; ++x)
    {
        lockIndices.push_back(x); // Top row indices
    }

    // Create cloth
    ClothDesc desc;
    desc.mNumParticles = static_cast<uint32_t>(particles.size());
    desc.mParticles = particles.data();
    desc.mNumIndices = static_cast<uint32_t>(indices.size());
    desc.mIndices = indices.data();
    desc.mPhaseConfigs = nullptr;
    desc.mNumPhaseConfigs = 0;
    desc.mRestvalues = nullptr;
    desc.mNumRestvalues = 0;
    desc.mFlags = 0;

    gCloth = gFactory->createCloth(desc);
    if (!gCloth) return;

    // Lock top particles
    gCloth->lockParticles(lockIndices.data(), static_cast<uint32_t>(lockIndices.size()));
}

Step 3: Set Simulation Parameters and Run

void SimulateCloth(float deltaTime)
{
    // Set gravity
    gCloth->setGravity({0.0f, -9.81f, 0.0f});

    // Set damping
    gCloth->setDamping(0.02f);

    // Update simulation
    gCloth->simulate(deltaTime);
    gCloth->fetchResults(); // Wait for simulation to complete

    // Get particle positions after simulation for rendering
    const ClothParticle* finalParticles = gCloth->getCurrentParticles();

    // Here you can pass finalParticles data to the rendering pipeline
    for (uint32_t i = 0; i < gCloth->getNumParticles(); ++i)
    {
        // PxVec3 renderPos(finalParticles[i].pos.x, finalParticles[i].pos.y, finalParticles[i].pos.z);
        // For updating vertex buffer
    }
}

Step 4: Main Loop Integration

int main()
{
    if (!InitializePhysX())
    {
        printf("Failed to initialize PhysX/NvCloth\n");
        return -1;
    }

    CreateClothMesh();

    float timeStep = 1.0f / 60.0f; // 60 FPS

    while (true) // Main loop
    {
        SimulateCloth(timeStep);

        // Render frame
        RenderFrame();

        // Handle input, sleep, etc...
        if (ShouldExit()) break;
    }

    // Clean up resources
    if (gCloth) gCloth->release();
    if (gPhysics) gPhysics->release();
    if (gFoundation) gFoundation->release();

    return 0;
}

4. How to Run This Code?

  1. Download PhysX SDK: Get the latest version from GitHub – NVIDIA PhysX.
  2. Compile SDK: Follow the official documentation to compile the PhysX and NvCloth libraries.
  3. Create Project: Create a C++ project in Visual Studio or another IDE.
  4. Link Libraries: Add the header and library paths for PhysX and NvCloth to your project.
  5. Compile and Run: Compile and run your program. You should see a piece of cloth fixed at the top, sagging and swaying slightly under the influence of gravity.

5. Advanced Features

  • GPU Acceleration: Use NvClothCreateFactoryCUDA() instead of the CPU factory for significantly improved performance.
  • Wind Simulation: Set wind speed and direction using setWind().
  • Colliders: Add colliders such as spheres and capsules in the scene for the cloth.
  • Self-Collision: Enable self-collision to prevent the cloth from penetrating itself.

6. Conclusion

NvCloth provides powerful low-level cloth simulation capabilities. Although using its API directly can be complex, understanding how it works is crucial for developing high-performance physics systems. For most applications, it is recommended to use it in conjunction with high-level engines like Unreal Engine or Unity, which encapsulate the complexities of NvCloth/PhysX and provide visual editing and more user-friendly interfaces.

Leave a Comment