|
|
#pragma once |
|
|
|
|
|
#include <iostream> |
|
|
#include <cstdlib> |
|
|
#include <cstdio> |
|
|
#include <cstring> |
|
|
|
|
|
#include <pybind11/pybind11.h> |
|
|
#include <pybind11/numpy.h> |
|
|
|
|
|
namespace py = pybind11; |
|
|
|
|
|
#include "include/NvFlex.h" |
|
|
#include "include/NvFlexExt.h" |
|
|
#include "include/NvFlexDevice.h" |
|
|
|
|
|
#include "core/maths.h" |
|
|
#include "core/types.h" |
|
|
#include "core/platform.h" |
|
|
#include "core/mesh.h" |
|
|
#include "core/voxelize.h" |
|
|
#include "core/sdf.h" |
|
|
#include "core/pfm.h" |
|
|
#include "core/tga.h" |
|
|
#include "core/perlin.h" |
|
|
#include "core/convex.h" |
|
|
#include "core/cloth.h" |
|
|
|
|
|
#include "external/SDL2-2.0.4/include/SDL.h" |
|
|
|
|
|
#include "shaders.h" |
|
|
#include "imgui.h" |
|
|
#include "shadersDemoContext.h" |
|
|
|
|
|
#include "bindings/utils/utils.h" |
|
|
|
|
|
|
|
|
void InitRenderHeadless(const RenderInitOptions& options, int width, int height); |
|
|
|
|
|
SDL_Window *g_window; |
|
|
unsigned int g_windowId; |
|
|
|
|
|
#define SDL_CONTROLLER_BUTTON_LEFT_TRIGGER (SDL_CONTROLLER_BUTTON_MAX + 1) |
|
|
#define SDL_CONTROLLER_BUTTON_RIGHT_TRIGGER (SDL_CONTROLLER_BUTTON_MAX + 2) |
|
|
|
|
|
int GetKeyFromGameControllerButton(SDL_GameControllerButton button) { |
|
|
switch (button) { |
|
|
case SDL_CONTROLLER_BUTTON_DPAD_UP: { |
|
|
return SDLK_q; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: { |
|
|
return SDLK_z; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: { |
|
|
return SDLK_h; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: { |
|
|
return -1; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_START: { |
|
|
return SDLK_RETURN; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_BACK: { |
|
|
return SDLK_ESCAPE; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: { |
|
|
return SDLK_UP; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: { |
|
|
return SDLK_DOWN; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_A: { |
|
|
return SDLK_g; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_B: { |
|
|
return SDLK_p; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_X: { |
|
|
return SDLK_r; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_Y: { |
|
|
return SDLK_o; |
|
|
} |
|
|
case SDL_CONTROLLER_BUTTON_RIGHT_TRIGGER: { |
|
|
return SDLK_SPACE; |
|
|
} |
|
|
default: { |
|
|
return -1; |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 |
|
|
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 |
|
|
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 |
|
|
|
|
|
int deadzones[3] = { |
|
|
XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, |
|
|
XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, |
|
|
XINPUT_GAMEPAD_TRIGGER_THRESHOLD}; |
|
|
|
|
|
inline float joyAxisFilter(int value, int stick) { |
|
|
|
|
|
if (value < -deadzones[stick]) |
|
|
return (value + deadzones[stick]) / (32768.0f - deadzones[stick]); |
|
|
else if (value > deadzones[stick]) |
|
|
return (value - deadzones[stick]) / (32768.0f - deadzones[stick]); |
|
|
else |
|
|
return 0.0f; |
|
|
} |
|
|
|
|
|
SDL_GameController *g_gamecontroller = nullptr; |
|
|
|
|
|
using namespace std; |
|
|
|
|
|
int g_screenWidth = 720; |
|
|
int g_screenHeight = 720; |
|
|
int g_msaaSamples = 0; |
|
|
|
|
|
int g_numSubsteps; |
|
|
|
|
|
|
|
|
int g_device = -1; |
|
|
char g_deviceName[256]; |
|
|
bool g_vsync = true; |
|
|
|
|
|
|
|
|
bool g_headless = true; |
|
|
bool g_render = true; |
|
|
|
|
|
bool g_benchmark = false; |
|
|
bool g_extensions = true; |
|
|
bool g_teamCity = false; |
|
|
bool g_interop = true; |
|
|
bool g_d3d12 = false; |
|
|
bool g_useAsyncCompute = true; |
|
|
bool g_increaseGfxLoadForAsyncComputeTesting = false; |
|
|
int g_graphics = 0; |
|
|
|
|
|
FluidRenderer *g_fluidRenderer; |
|
|
FluidRenderBuffers *g_fluidRenderBuffers; |
|
|
DiffuseRenderBuffers *g_diffuseRenderBuffers; |
|
|
|
|
|
NvFlexSolver *g_solver; |
|
|
NvFlexSolverDesc g_solverDesc; |
|
|
NvFlexLibrary *g_flexLib; |
|
|
NvFlexParams g_params; |
|
|
NvFlexTimers g_timers; |
|
|
int g_numDetailTimers; |
|
|
NvFlexDetailTimer *g_detailTimers; |
|
|
|
|
|
int g_maxDiffuseParticles; |
|
|
int g_maxNeighborsPerParticle; |
|
|
int g_numExtraParticles; |
|
|
int g_numExtraMultiplier = 1; |
|
|
int g_maxContactsPerParticle; |
|
|
int g_clothOnly = 0; |
|
|
|
|
|
|
|
|
Mesh *g_mesh; |
|
|
vector<int> g_meshSkinIndices; |
|
|
vector<float> g_meshSkinWeights; |
|
|
vector<Point3> g_meshRestPositions; |
|
|
const int g_numSkinWeights = 4; |
|
|
|
|
|
|
|
|
std::map<NvFlexConvexMeshId, GpuMesh *> g_convexes; |
|
|
std::map<NvFlexTriangleMeshId, GpuMesh *> g_meshes; |
|
|
std::map<NvFlexDistanceFieldId, GpuMesh *> g_fields; |
|
|
|
|
|
|
|
|
bool g_shapesChanged = false; |
|
|
|
|
|
|
|
|
Colour g_colors[] = { |
|
|
Colour(0.000f, 0.500f, 1.000f), |
|
|
Colour(0.875f, 0.782f, 0.051f), |
|
|
Colour(0.800f, 0.100f, 0.100f), |
|
|
Colour(0.673f, 0.111f, 0.000f), |
|
|
Colour(0.612f, 0.194f, 0.394f), |
|
|
Colour(0.0f, 1.f, 0.0f), |
|
|
Colour(0.797f, 0.354f, 0.000f), |
|
|
Colour(0.092f, 0.465f, 0.820f) |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct SimBuffers { |
|
|
NvFlexVector<Vec4> positions; |
|
|
NvFlexVector<Vec4> restPositions; |
|
|
NvFlexVector<Vec3> velocities; |
|
|
NvFlexVector<int> phases; |
|
|
NvFlexVector<float> densities; |
|
|
NvFlexVector<Vec4> anisotropy1; |
|
|
NvFlexVector<Vec4> anisotropy2; |
|
|
NvFlexVector<Vec4> anisotropy3; |
|
|
NvFlexVector<Vec4> normals; |
|
|
NvFlexVector<Vec4> smoothPositions; |
|
|
NvFlexVector<Vec4> diffusePositions; |
|
|
NvFlexVector<Vec4> diffuseVelocities; |
|
|
NvFlexVector<int> diffuseCount; |
|
|
|
|
|
NvFlexVector<int> activeIndices; |
|
|
|
|
|
|
|
|
NvFlexVector<NvFlexCollisionGeometry> shapeGeometry; |
|
|
NvFlexVector<Vec4> shapePositions; |
|
|
NvFlexVector<Quat> shapeRotations; |
|
|
NvFlexVector<Vec4> shapePrevPositions; |
|
|
NvFlexVector<Quat> shapePrevRotations; |
|
|
NvFlexVector<int> shapeFlags; |
|
|
|
|
|
|
|
|
NvFlexVector<int> rigidOffsets; |
|
|
NvFlexVector<int> rigidIndices; |
|
|
NvFlexVector<int> rigidMeshSize; |
|
|
NvFlexVector<float> rigidCoefficients; |
|
|
NvFlexVector<float> rigidPlasticThresholds; |
|
|
NvFlexVector<float> rigidPlasticCreeps; |
|
|
NvFlexVector<Quat> rigidRotations; |
|
|
NvFlexVector<Vec3> rigidTranslations; |
|
|
NvFlexVector<Vec3> rigidLocalPositions; |
|
|
NvFlexVector<Vec4> rigidLocalNormals; |
|
|
|
|
|
|
|
|
NvFlexVector<int> inflatableTriOffsets; |
|
|
NvFlexVector<int> inflatableTriCounts; |
|
|
NvFlexVector<float> inflatableVolumes; |
|
|
NvFlexVector<float> inflatableCoefficients; |
|
|
NvFlexVector<float> inflatablePressures; |
|
|
|
|
|
|
|
|
NvFlexVector<int> springIndices; |
|
|
NvFlexVector<float> springLengths; |
|
|
NvFlexVector<float> springStiffness; |
|
|
|
|
|
NvFlexVector<int> triangles; |
|
|
NvFlexVector<Vec3> triangleNormals; |
|
|
NvFlexVector<Vec3> uvs; |
|
|
|
|
|
SimBuffers(NvFlexLibrary *l) : |
|
|
positions(l), restPositions(l), velocities(l), phases(l), densities(l), |
|
|
anisotropy1(l), anisotropy2(l), anisotropy3(l), normals(l), smoothPositions(l), |
|
|
diffusePositions(l), diffuseVelocities(l), diffuseCount(l), activeIndices(l), |
|
|
shapeGeometry(l), shapePositions(l), shapeRotations(l), shapePrevPositions(l), |
|
|
shapePrevRotations(l), shapeFlags(l), rigidOffsets(l), rigidIndices(l), rigidMeshSize(l), |
|
|
rigidCoefficients(l), rigidPlasticThresholds(l), rigidPlasticCreeps(l), rigidRotations(l), |
|
|
rigidTranslations(l), |
|
|
rigidLocalPositions(l), rigidLocalNormals(l), inflatableTriOffsets(l), |
|
|
inflatableTriCounts(l), inflatableVolumes(l), inflatableCoefficients(l), |
|
|
inflatablePressures(l), springIndices(l), springLengths(l), |
|
|
springStiffness(l), triangles(l), triangleNormals(l), uvs(l) {} |
|
|
}; |
|
|
|
|
|
SimBuffers *g_buffers; |
|
|
|
|
|
void MapBuffers(SimBuffers *buffers) { |
|
|
buffers->positions.map(); |
|
|
buffers->restPositions.map(); |
|
|
buffers->velocities.map(); |
|
|
buffers->phases.map(); |
|
|
buffers->densities.map(); |
|
|
buffers->anisotropy1.map(); |
|
|
buffers->anisotropy2.map(); |
|
|
buffers->anisotropy3.map(); |
|
|
buffers->normals.map(); |
|
|
buffers->diffusePositions.map(); |
|
|
buffers->diffuseVelocities.map(); |
|
|
buffers->diffuseCount.map(); |
|
|
buffers->smoothPositions.map(); |
|
|
buffers->activeIndices.map(); |
|
|
|
|
|
|
|
|
buffers->shapeGeometry.map(); |
|
|
buffers->shapePositions.map(); |
|
|
buffers->shapeRotations.map(); |
|
|
buffers->shapePrevPositions.map(); |
|
|
buffers->shapePrevRotations.map(); |
|
|
buffers->shapeFlags.map(); |
|
|
|
|
|
buffers->rigidOffsets.map(); |
|
|
buffers->rigidIndices.map(); |
|
|
buffers->rigidMeshSize.map(); |
|
|
buffers->rigidCoefficients.map(); |
|
|
buffers->rigidPlasticThresholds.map(); |
|
|
buffers->rigidPlasticCreeps.map(); |
|
|
buffers->rigidRotations.map(); |
|
|
buffers->rigidTranslations.map(); |
|
|
buffers->rigidLocalPositions.map(); |
|
|
buffers->rigidLocalNormals.map(); |
|
|
|
|
|
buffers->springIndices.map(); |
|
|
buffers->springLengths.map(); |
|
|
buffers->springStiffness.map(); |
|
|
|
|
|
|
|
|
buffers->inflatableTriOffsets.map(); |
|
|
buffers->inflatableTriCounts.map(); |
|
|
buffers->inflatableVolumes.map(); |
|
|
buffers->inflatableCoefficients.map(); |
|
|
buffers->inflatablePressures.map(); |
|
|
|
|
|
buffers->triangles.map(); |
|
|
buffers->triangleNormals.map(); |
|
|
buffers->uvs.map(); |
|
|
} |
|
|
|
|
|
void UnmapBuffers(SimBuffers *buffers) { |
|
|
|
|
|
buffers->positions.unmap(); |
|
|
buffers->restPositions.unmap(); |
|
|
buffers->velocities.unmap(); |
|
|
buffers->phases.unmap(); |
|
|
buffers->densities.unmap(); |
|
|
buffers->anisotropy1.unmap(); |
|
|
buffers->anisotropy2.unmap(); |
|
|
buffers->anisotropy3.unmap(); |
|
|
buffers->normals.unmap(); |
|
|
buffers->diffusePositions.unmap(); |
|
|
buffers->diffuseVelocities.unmap(); |
|
|
buffers->diffuseCount.unmap(); |
|
|
buffers->smoothPositions.unmap(); |
|
|
buffers->activeIndices.unmap(); |
|
|
|
|
|
|
|
|
buffers->shapeGeometry.unmap(); |
|
|
buffers->shapePositions.unmap(); |
|
|
buffers->shapeRotations.unmap(); |
|
|
buffers->shapePrevPositions.unmap(); |
|
|
buffers->shapePrevRotations.unmap(); |
|
|
buffers->shapeFlags.unmap(); |
|
|
|
|
|
|
|
|
buffers->rigidOffsets.unmap(); |
|
|
buffers->rigidIndices.unmap(); |
|
|
buffers->rigidMeshSize.unmap(); |
|
|
buffers->rigidCoefficients.unmap(); |
|
|
buffers->rigidPlasticThresholds.unmap(); |
|
|
buffers->rigidPlasticCreeps.unmap(); |
|
|
buffers->rigidRotations.unmap(); |
|
|
buffers->rigidTranslations.unmap(); |
|
|
buffers->rigidLocalPositions.unmap(); |
|
|
buffers->rigidLocalNormals.unmap(); |
|
|
|
|
|
|
|
|
buffers->springIndices.unmap(); |
|
|
buffers->springLengths.unmap(); |
|
|
buffers->springStiffness.unmap(); |
|
|
|
|
|
|
|
|
buffers->inflatableTriOffsets.unmap(); |
|
|
buffers->inflatableTriCounts.unmap(); |
|
|
buffers->inflatableVolumes.unmap(); |
|
|
buffers->inflatableCoefficients.unmap(); |
|
|
buffers->inflatablePressures.unmap(); |
|
|
|
|
|
|
|
|
buffers->triangles.unmap(); |
|
|
buffers->triangleNormals.unmap(); |
|
|
buffers->uvs.unmap(); |
|
|
|
|
|
} |
|
|
|
|
|
SimBuffers *AllocBuffers(NvFlexLibrary *lib) { |
|
|
return new SimBuffers(lib); |
|
|
} |
|
|
|
|
|
void DestroyBuffers(SimBuffers *buffers) { |
|
|
|
|
|
buffers->positions.destroy(); |
|
|
buffers->restPositions.destroy(); |
|
|
buffers->velocities.destroy(); |
|
|
buffers->phases.destroy(); |
|
|
buffers->densities.destroy(); |
|
|
buffers->anisotropy1.destroy(); |
|
|
buffers->anisotropy2.destroy(); |
|
|
buffers->anisotropy3.destroy(); |
|
|
buffers->normals.destroy(); |
|
|
buffers->diffusePositions.destroy(); |
|
|
buffers->diffuseVelocities.destroy(); |
|
|
buffers->diffuseCount.destroy(); |
|
|
buffers->smoothPositions.destroy(); |
|
|
buffers->activeIndices.destroy(); |
|
|
|
|
|
|
|
|
buffers->shapeGeometry.destroy(); |
|
|
buffers->shapePositions.destroy(); |
|
|
buffers->shapeRotations.destroy(); |
|
|
buffers->shapePrevPositions.destroy(); |
|
|
buffers->shapePrevRotations.destroy(); |
|
|
buffers->shapeFlags.destroy(); |
|
|
|
|
|
|
|
|
buffers->rigidOffsets.destroy(); |
|
|
buffers->rigidIndices.destroy(); |
|
|
buffers->rigidMeshSize.destroy(); |
|
|
buffers->rigidCoefficients.destroy(); |
|
|
buffers->rigidPlasticThresholds.destroy(); |
|
|
buffers->rigidPlasticCreeps.destroy(); |
|
|
buffers->rigidRotations.destroy(); |
|
|
buffers->rigidTranslations.destroy(); |
|
|
buffers->rigidLocalPositions.destroy(); |
|
|
buffers->rigidLocalNormals.destroy(); |
|
|
|
|
|
|
|
|
buffers->springIndices.destroy(); |
|
|
buffers->springLengths.destroy(); |
|
|
buffers->springStiffness.destroy(); |
|
|
|
|
|
|
|
|
buffers->inflatableTriOffsets.destroy(); |
|
|
buffers->inflatableTriCounts.destroy(); |
|
|
buffers->inflatableVolumes.destroy(); |
|
|
buffers->inflatableCoefficients.destroy(); |
|
|
buffers->inflatablePressures.destroy(); |
|
|
|
|
|
|
|
|
buffers->triangles.destroy(); |
|
|
buffers->triangleNormals.destroy(); |
|
|
buffers->uvs.destroy(); |
|
|
|
|
|
delete buffers; |
|
|
} |
|
|
|
|
|
Vec3 g_camPos(6.0f, 8.0f, 18.0f); |
|
|
Vec3 g_camAngle(0.0f, -DegToRad(20.0f), 0.0f); |
|
|
Vec3 g_camVel(0.0f); |
|
|
Vec3 g_camSmoothVel(0.0f); |
|
|
|
|
|
float g_camSpeed; |
|
|
float g_camNear; |
|
|
float g_camFar; |
|
|
|
|
|
Vec3 g_lightPos; |
|
|
Vec3 g_lightDir; |
|
|
Vec3 g_lightTarget; |
|
|
|
|
|
bool g_pause = false; |
|
|
bool g_step = false; |
|
|
bool g_capture = false; |
|
|
bool g_showHelp = true; |
|
|
bool g_tweakPanel = false; |
|
|
bool g_fullscreen = false; |
|
|
bool g_wireframe = false; |
|
|
bool g_debug = false; |
|
|
|
|
|
bool g_emit = false; |
|
|
bool g_warmup = false; |
|
|
|
|
|
float g_windTime = 0.0f; |
|
|
float g_windFrequency = 0.0f; |
|
|
float g_windStrength = 0.0f; |
|
|
|
|
|
bool g_wavePool = false; |
|
|
float g_waveTime = 0.0f; |
|
|
float g_wavePlane; |
|
|
float g_waveFrequency = 1.5f; |
|
|
float g_waveAmplitude = 1.0f; |
|
|
float g_waveFloorTilt = 0.0f; |
|
|
|
|
|
Vec3 g_shape_color=Vec3(0.9); |
|
|
Vec3 g_sceneLower; |
|
|
Vec3 g_sceneUpper; |
|
|
|
|
|
float g_blur; |
|
|
float g_ior; |
|
|
bool g_drawEllipsoids; |
|
|
bool g_drawPoints; |
|
|
bool g_drawMesh; |
|
|
bool g_drawCloth; |
|
|
float g_expandCloth; |
|
|
|
|
|
bool g_drawOpaque; |
|
|
int g_drawSprings; |
|
|
bool g_drawBases = false; |
|
|
bool g_drawContacts = false; |
|
|
bool g_drawNormals = false; |
|
|
bool g_drawDiffuse; |
|
|
bool g_drawShapeGrid = false; |
|
|
bool g_drawDensity = false; |
|
|
bool g_drawRopes; |
|
|
float g_pointScale; |
|
|
float g_ropeScale; |
|
|
float g_drawPlaneBias; |
|
|
|
|
|
float g_diffuseScale; |
|
|
float g_diffuseMotionScale; |
|
|
bool g_diffuseShadow; |
|
|
float g_diffuseInscatter; |
|
|
float g_diffuseOutscatter; |
|
|
|
|
|
float g_dt = 1.0f / 240.0f; |
|
|
float g_realdt; |
|
|
|
|
|
float g_waitTime; |
|
|
float g_updateTime; |
|
|
float g_renderTime; |
|
|
|
|
|
float g_simLatency; |
|
|
|
|
|
int g_scene = 0; |
|
|
int g_selectedScene = g_scene; |
|
|
int g_levelScroll; |
|
|
bool g_resetScene = false; |
|
|
|
|
|
int g_frame = 0; |
|
|
int g_numSolidParticles = 0; |
|
|
|
|
|
int g_mouseParticle = -1; |
|
|
float g_mouseT = 0.0f; |
|
|
Vec3 g_mousePos; |
|
|
float g_mouseMass; |
|
|
bool g_mousePicked = false; |
|
|
|
|
|
|
|
|
int g_lastx; |
|
|
int g_lasty; |
|
|
int g_lastb = -1; |
|
|
|
|
|
bool g_profile = false; |
|
|
bool g_outputAllFrameTimes = false; |
|
|
bool g_asyncComputeBenchmark = false; |
|
|
|
|
|
ShadowMap *g_shadowMap; |
|
|
|
|
|
Vec4 g_fluidColor; |
|
|
Vec4 g_diffuseColor; |
|
|
Vec3 g_meshColor; |
|
|
Vec3 g_clearColor; |
|
|
float g_lightDistance; |
|
|
float g_fogDistance; |
|
|
|
|
|
FILE *g_ffmpeg; |
|
|
|
|
|
void DrawShapes(); |
|
|
|
|
|
class Scene; |
|
|
|
|
|
vector<Scene *> g_scenes; |
|
|
|
|
|
struct Emitter { |
|
|
Emitter() : mSpeed(0.0f), mEnabled(false), mLeftOver(0.0f), mWidth(8) {} |
|
|
|
|
|
Vec3 mPos; |
|
|
Vec3 mDir; |
|
|
Vec3 mRight; |
|
|
float mSpeed; |
|
|
bool mEnabled; |
|
|
float mLeftOver; |
|
|
int mWidth; |
|
|
}; |
|
|
|
|
|
vector<Emitter> g_emitters(1); |
|
|
|
|
|
struct Rope { |
|
|
std::vector<int> mIndices; |
|
|
}; |
|
|
|
|
|
vector<Rope> g_ropes; |
|
|
|
|
|
inline float sqr(float x) { return x * x; } |
|
|
|
|
|
#include "helpers.h" |
|
|
#include "scenes.h" |
|
|
#include "benchmark.h" |
|
|
|
|
|
#include <iostream> |
|
|
using namespace std; |
|
|
|
|
|
void Init(int scene, py::array_t<float> scene_params, bool centerCamera = true, int thread_idx = 0) { |
|
|
RandInit(); |
|
|
if (g_solver) { |
|
|
if (g_buffers) |
|
|
DestroyBuffers(g_buffers); |
|
|
|
|
|
if (g_render) { |
|
|
DestroyFluidRenderBuffers(g_fluidRenderBuffers); |
|
|
DestroyDiffuseRenderBuffers(g_diffuseRenderBuffers); |
|
|
} |
|
|
|
|
|
for (auto &iter : g_meshes) { |
|
|
NvFlexDestroyTriangleMesh(g_flexLib, iter.first); |
|
|
DestroyGpuMesh(iter.second); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (auto &iter : g_fields) { |
|
|
NvFlexDestroyDistanceField(g_flexLib, iter.first); |
|
|
DestroyGpuMesh(iter.second); |
|
|
} |
|
|
|
|
|
for (auto &iter : g_convexes) { |
|
|
NvFlexDestroyConvexMesh(g_flexLib, iter.first); |
|
|
DestroyGpuMesh(iter.second); |
|
|
} |
|
|
|
|
|
g_fields.clear(); |
|
|
g_meshes.clear(); |
|
|
g_convexes.clear(); |
|
|
|
|
|
NvFlexDestroySolver(g_solver); |
|
|
g_solver = nullptr; |
|
|
} |
|
|
|
|
|
|
|
|
g_buffers = AllocBuffers(g_flexLib); |
|
|
|
|
|
|
|
|
MapBuffers(g_buffers); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
g_buffers->positions.resize(0); |
|
|
g_buffers->velocities.resize(0); |
|
|
g_buffers->phases.resize(0); |
|
|
|
|
|
g_buffers->rigidOffsets.resize(0); |
|
|
g_buffers->rigidIndices.resize(0); |
|
|
g_buffers->rigidMeshSize.resize(0); |
|
|
g_buffers->rigidRotations.resize(0); |
|
|
g_buffers->rigidTranslations.resize(0); |
|
|
g_buffers->rigidCoefficients.resize(0); |
|
|
g_buffers->rigidPlasticThresholds.resize(0); |
|
|
g_buffers->rigidPlasticCreeps.resize(0); |
|
|
g_buffers->rigidLocalPositions.resize(0); |
|
|
g_buffers->rigidLocalNormals.resize(0); |
|
|
|
|
|
g_buffers->springIndices.resize(0); |
|
|
g_buffers->springLengths.resize(0); |
|
|
g_buffers->springStiffness.resize(0); |
|
|
g_buffers->triangles.resize(0); |
|
|
g_buffers->triangleNormals.resize(0); |
|
|
g_buffers->uvs.resize(0); |
|
|
|
|
|
g_meshSkinIndices.resize(0); |
|
|
g_meshSkinWeights.resize(0); |
|
|
|
|
|
g_emitters.resize(1); |
|
|
g_emitters[0].mEnabled = false; |
|
|
g_emitters[0].mSpeed = 1.0f; |
|
|
g_emitters[0].mLeftOver = 0.0f; |
|
|
g_emitters[0].mWidth = 8; |
|
|
|
|
|
g_buffers->shapeGeometry.resize(0); |
|
|
g_buffers->shapePositions.resize(0); |
|
|
g_buffers->shapeRotations.resize(0); |
|
|
g_buffers->shapePrevPositions.resize(0); |
|
|
g_buffers->shapePrevRotations.resize(0); |
|
|
g_buffers->shapeFlags.resize(0); |
|
|
|
|
|
g_ropes.resize(0); |
|
|
|
|
|
|
|
|
delete g_mesh; |
|
|
g_mesh = NULL; |
|
|
|
|
|
g_frame = 0; |
|
|
g_pause = false; |
|
|
|
|
|
g_dt = 1.0f / 100.0f; |
|
|
g_waveTime = 0.0f; |
|
|
g_windTime = 0.0f; |
|
|
g_windStrength = 1.0f; |
|
|
|
|
|
g_blur = 1.0f; |
|
|
g_fluidColor = Vec4(0.1f, 0.4f, 0.8f, 1.0f); |
|
|
g_meshColor = Vec3(0.9f, 0.9f, 0.9f); |
|
|
g_drawEllipsoids = false; |
|
|
g_drawPoints = true; |
|
|
g_drawCloth = true; |
|
|
g_expandCloth = 0.0f; |
|
|
|
|
|
g_drawOpaque = false; |
|
|
g_drawSprings = false; |
|
|
g_drawDiffuse = false; |
|
|
g_drawMesh = true; |
|
|
g_drawRopes = true; |
|
|
g_drawDensity = false; |
|
|
g_ior = 1.0f; |
|
|
g_lightDistance = 10.0f; |
|
|
g_fogDistance = 0.005f; |
|
|
|
|
|
g_camSpeed = 0.075f; |
|
|
g_camNear = 0.01f; |
|
|
g_camFar = 1000.0f; |
|
|
|
|
|
g_pointScale = 1.0f; |
|
|
g_ropeScale = 1.0f; |
|
|
g_drawPlaneBias = 0.0f; |
|
|
|
|
|
|
|
|
g_params.gravity[0] = 0.0f; |
|
|
g_params.gravity[1] = -9.8f; |
|
|
g_params.gravity[2] = 0.0f; |
|
|
|
|
|
g_params.wind[0] = 0.0f; |
|
|
g_params.wind[1] = 0.0f; |
|
|
g_params.wind[2] = 0.0f; |
|
|
|
|
|
g_params.radius = 0.15f; |
|
|
g_params.viscosity = 0.0f; |
|
|
g_params.dynamicFriction = 0.0f; |
|
|
g_params.staticFriction = 0.0f; |
|
|
g_params.particleFriction = 0.0f; |
|
|
g_params.freeSurfaceDrag = 0.0f; |
|
|
g_params.drag = 0.0f; |
|
|
g_params.lift = 0.0f; |
|
|
g_params.numIterations = 3; |
|
|
g_params.fluidRestDistance = 0.0f; |
|
|
g_params.solidRestDistance = 0.0f; |
|
|
|
|
|
g_params.anisotropyScale = 1.0f; |
|
|
g_params.anisotropyMin = 0.1f; |
|
|
g_params.anisotropyMax = 2.0f; |
|
|
g_params.smoothing = 1.0f; |
|
|
|
|
|
g_params.dissipation = 0.0f; |
|
|
g_params.damping = 0.0f; |
|
|
g_params.particleCollisionMargin = 0.0f; |
|
|
g_params.shapeCollisionMargin = 0.0f; |
|
|
g_params.collisionDistance = 0.0f; |
|
|
g_params.sleepThreshold = 0.0f; |
|
|
g_params.shockPropagation = 0.0f; |
|
|
g_params.restitution = 0.0f; |
|
|
|
|
|
g_params.maxSpeed = FLT_MAX; |
|
|
g_params.maxAcceleration = 100.0f; |
|
|
|
|
|
g_params.relaxationMode = eNvFlexRelaxationLocal; |
|
|
g_params.relaxationFactor = 1.0f; |
|
|
g_params.solidPressure = 1.0f; |
|
|
g_params.adhesion = 0.0f; |
|
|
g_params.cohesion = 0.025f; |
|
|
g_params.surfaceTension = 0.0f; |
|
|
g_params.vorticityConfinement = 0.0f; |
|
|
g_params.buoyancy = 1.0f; |
|
|
g_params.diffuseThreshold = 100.0f; |
|
|
g_params.diffuseBuoyancy = 1.0f; |
|
|
g_params.diffuseDrag = 0.8f; |
|
|
g_params.diffuseBallistic = 16; |
|
|
g_params.diffuseLifetime = 2.0f; |
|
|
|
|
|
g_numSubsteps = 20; |
|
|
|
|
|
|
|
|
g_params.numPlanes = 1; |
|
|
|
|
|
g_diffuseScale = 0.5f; |
|
|
g_diffuseColor = 1.0f; |
|
|
g_diffuseMotionScale = 1.0f; |
|
|
g_diffuseShadow = false; |
|
|
g_diffuseInscatter = 0.8f; |
|
|
g_diffuseOutscatter = 0.53f; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
g_numSolidParticles = 0; |
|
|
|
|
|
g_waveFrequency = 1.5f; |
|
|
g_waveAmplitude = 1.5f; |
|
|
g_waveFloorTilt = 0.0f; |
|
|
g_emit = false; |
|
|
g_warmup = false; |
|
|
|
|
|
g_mouseParticle = -1; |
|
|
|
|
|
g_maxDiffuseParticles = 0; |
|
|
g_maxNeighborsPerParticle = 96; |
|
|
g_numExtraParticles = 0; |
|
|
g_maxContactsPerParticle = 6; |
|
|
|
|
|
g_sceneLower = FLT_MAX; |
|
|
g_sceneUpper = -FLT_MAX; |
|
|
|
|
|
|
|
|
NvFlexSetSolverDescDefaults(&g_solverDesc); |
|
|
|
|
|
|
|
|
|
|
|
StartGpuWork(); |
|
|
|
|
|
|
|
|
g_scenes[g_scene]->Initialize(scene_params, thread_idx); |
|
|
EndGpuWork(); |
|
|
|
|
|
uint32_t numParticles = g_buffers->positions.size(); |
|
|
uint32_t maxParticles = numParticles + g_numExtraParticles * g_numExtraMultiplier; |
|
|
|
|
|
if (g_params.solidRestDistance == 0.0f) |
|
|
g_params.solidRestDistance = g_params.radius; |
|
|
|
|
|
|
|
|
if (g_params.fluidRestDistance > 0.0f) |
|
|
g_params.solidRestDistance = g_params.fluidRestDistance; |
|
|
|
|
|
|
|
|
if (g_params.collisionDistance == 0.0f) |
|
|
g_params.collisionDistance = Max(g_params.solidRestDistance, g_params.fluidRestDistance) * 0.5f; |
|
|
|
|
|
|
|
|
if (g_params.particleFriction == 0.0f) |
|
|
g_params.particleFriction = g_params.dynamicFriction * 0.1f; |
|
|
|
|
|
|
|
|
if (g_params.shapeCollisionMargin == 0.0f) |
|
|
g_params.shapeCollisionMargin = g_params.collisionDistance * 0.5f; |
|
|
|
|
|
|
|
|
Vec3 particleLower, particleUpper; |
|
|
GetParticleBounds(particleLower, particleUpper); |
|
|
|
|
|
|
|
|
Vec3 shapeLower, shapeUpper; |
|
|
GetShapeBounds(shapeLower, shapeUpper); |
|
|
|
|
|
|
|
|
g_sceneLower = Min(Min(g_sceneLower, particleLower), shapeLower); |
|
|
g_sceneUpper = Max(Max(g_sceneUpper, particleUpper), shapeUpper); |
|
|
|
|
|
g_sceneLower -= g_params.collisionDistance; |
|
|
g_sceneUpper += g_params.collisionDistance; |
|
|
|
|
|
|
|
|
Vec3 up = Normalize(Vec3(-g_waveFloorTilt, 1.0f, 0.0f)); |
|
|
|
|
|
(Vec4 &) g_params.planes[0] = Vec4(up.x, up.y, up.z, 0.0f); |
|
|
(Vec4 &) g_params.planes[1] = Vec4(0.0f, 0.0f, 1.0f, -g_sceneLower.z); |
|
|
(Vec4 &) g_params.planes[2] = Vec4(1.0f, 0.0f, 0.0f, -g_sceneLower.x); |
|
|
(Vec4 &) g_params.planes[3] = Vec4(-1.0f, 0.0f, 0.0f, g_sceneUpper.x); |
|
|
(Vec4 &) g_params.planes[4] = Vec4(0.0f, 0.0f, -1.0f, g_sceneUpper.z); |
|
|
(Vec4 &) g_params.planes[5] = Vec4(0.0f, -1.0f, 0.0f, g_sceneUpper.y); |
|
|
|
|
|
g_wavePlane = g_params.planes[2][3]; |
|
|
|
|
|
g_buffers->diffusePositions.resize(g_maxDiffuseParticles); |
|
|
g_buffers->diffuseVelocities.resize(g_maxDiffuseParticles); |
|
|
g_buffers->diffuseCount.resize(1, 0); |
|
|
|
|
|
|
|
|
g_buffers->smoothPositions.resize(maxParticles); |
|
|
|
|
|
g_buffers->normals.resize(0); |
|
|
g_buffers->normals.resize(maxParticles); |
|
|
|
|
|
|
|
|
int numTris = g_buffers->triangles.size() / 3; |
|
|
for (int i = 0; i < numTris; ++i) { |
|
|
Vec3 v0 = Vec3(g_buffers->positions[g_buffers->triangles[i * 3 + 0]]); |
|
|
Vec3 v1 = Vec3(g_buffers->positions[g_buffers->triangles[i * 3 + 1]]); |
|
|
Vec3 v2 = Vec3(g_buffers->positions[g_buffers->triangles[i * 3 + 2]]); |
|
|
|
|
|
Vec3 n = Cross(v1 - v0, v2 - v0); |
|
|
|
|
|
g_buffers->normals[g_buffers->triangles[i * 3 + 0]] += Vec4(n, 0.0f); |
|
|
g_buffers->normals[g_buffers->triangles[i * 3 + 1]] += Vec4(n, 0.0f); |
|
|
g_buffers->normals[g_buffers->triangles[i * 3 + 2]] += Vec4(n, 0.0f); |
|
|
} |
|
|
|
|
|
for (int i = 0; i < int(maxParticles); ++i) |
|
|
g_buffers->normals[i] = Vec4(SafeNormalize(Vec3(g_buffers->normals[i]), Vec3(0.0f, 1.0f, 0.0f)), 0.0f); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (g_mesh) { |
|
|
g_meshRestPositions = g_mesh->m_positions; |
|
|
} else { |
|
|
g_meshRestPositions.resize(0); |
|
|
} |
|
|
|
|
|
g_solverDesc.maxParticles = maxParticles; |
|
|
g_solverDesc.maxDiffuseParticles = g_maxDiffuseParticles; |
|
|
g_solverDesc.maxNeighborsPerParticle = g_maxNeighborsPerParticle; |
|
|
g_solverDesc.maxContactsPerParticle = g_maxContactsPerParticle; |
|
|
|
|
|
|
|
|
g_solver = NvFlexCreateSolver(g_flexLib, &g_solverDesc); |
|
|
|
|
|
|
|
|
g_scenes[g_scene]->PostInitialize(); |
|
|
|
|
|
|
|
|
if (centerCamera) { |
|
|
g_camPos = Vec3((g_sceneLower.x + g_sceneUpper.x) * 0.5f, min(g_sceneUpper.y * 1.25f, 6.0f), |
|
|
g_sceneUpper.z + min(g_sceneUpper.y, 6.0f) * 2.0f); |
|
|
g_camAngle = Vec3(0.0f, -DegToRad(15.0f), 0.0f); |
|
|
|
|
|
|
|
|
g_scenes[g_scene]->CenterCamera(); |
|
|
} |
|
|
|
|
|
|
|
|
g_buffers->activeIndices.resize(g_buffers->positions.size()); |
|
|
for (int i = 0; i < g_buffers->activeIndices.size(); ++i) |
|
|
g_buffers->activeIndices[i] = i; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
g_buffers->positions.resize(maxParticles); |
|
|
g_buffers->velocities.resize(maxParticles); |
|
|
g_buffers->phases.resize(maxParticles); |
|
|
|
|
|
g_buffers->densities.resize(maxParticles); |
|
|
g_buffers->anisotropy1.resize(maxParticles); |
|
|
g_buffers->anisotropy2.resize(maxParticles); |
|
|
g_buffers->anisotropy3.resize(maxParticles); |
|
|
|
|
|
|
|
|
g_buffers->restPositions.resize(g_buffers->positions.size()); |
|
|
for (int i = 0; i < g_buffers->positions.size(); ++i) |
|
|
g_buffers->restPositions[i] = g_buffers->positions[i]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (g_buffers->rigidOffsets.size()) { |
|
|
assert(g_buffers->rigidOffsets.size() > 1); |
|
|
|
|
|
const int numRigids = g_buffers->rigidOffsets.size() - 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (g_buffers->rigidTranslations.size() == 0) { |
|
|
g_buffers->rigidTranslations.resize(g_buffers->rigidOffsets.size() - 1, Vec3()); |
|
|
CalculateRigidCentersOfMass(&g_buffers->positions[0], g_buffers->positions.size(), |
|
|
&g_buffers->rigidOffsets[0], &g_buffers->rigidTranslations[0], |
|
|
&g_buffers->rigidIndices[0], numRigids); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
g_buffers->rigidLocalPositions.resize(g_buffers->rigidOffsets.back()); |
|
|
CalculateRigidLocalPositions(&g_buffers->positions[0], &g_buffers->rigidOffsets[0], |
|
|
&g_buffers->rigidTranslations[0], &g_buffers->rigidIndices[0], numRigids, |
|
|
&g_buffers->rigidLocalPositions[0]); |
|
|
|
|
|
|
|
|
g_buffers->rigidRotations.resize(g_buffers->rigidOffsets.size() - 1, Quat()); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UnmapBuffers(g_buffers); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NvFlexCopyDesc copyDesc; |
|
|
copyDesc.dstOffset = 0; |
|
|
copyDesc.srcOffset = 0; |
|
|
copyDesc.elementCount = numParticles; |
|
|
|
|
|
NvFlexSetParams(g_solver, &g_params); |
|
|
NvFlexSetParticles(g_solver, g_buffers->positions.buffer, ©Desc); |
|
|
NvFlexSetVelocities(g_solver, g_buffers->velocities.buffer, ©Desc); |
|
|
NvFlexSetNormals(g_solver, g_buffers->normals.buffer, ©Desc); |
|
|
NvFlexSetPhases(g_solver, g_buffers->phases.buffer, ©Desc); |
|
|
NvFlexSetRestParticles(g_solver, g_buffers->restPositions.buffer, ©Desc); |
|
|
|
|
|
NvFlexSetActive(g_solver, g_buffers->activeIndices.buffer, ©Desc); |
|
|
NvFlexSetActiveCount(g_solver, numParticles); |
|
|
|
|
|
|
|
|
if (g_buffers->springIndices.size()) { |
|
|
assert((g_buffers->springIndices.size() & 1) == 0); |
|
|
assert((g_buffers->springIndices.size() / 2) == g_buffers->springLengths.size()); |
|
|
|
|
|
NvFlexSetSprings(g_solver, g_buffers->springIndices.buffer, g_buffers->springLengths.buffer, |
|
|
g_buffers->springStiffness.buffer, g_buffers->springLengths.size()); |
|
|
} |
|
|
|
|
|
|
|
|
if (g_buffers->rigidOffsets.size()) { |
|
|
NvFlexSetRigids(g_solver, g_buffers->rigidOffsets.buffer, g_buffers->rigidIndices.buffer, |
|
|
g_buffers->rigidLocalPositions.buffer, g_buffers->rigidLocalNormals.buffer, |
|
|
g_buffers->rigidCoefficients.buffer, g_buffers->rigidPlasticThresholds.buffer, |
|
|
g_buffers->rigidPlasticCreeps.buffer, g_buffers->rigidRotations.buffer, |
|
|
g_buffers->rigidTranslations.buffer, g_buffers->rigidOffsets.size() - 1, |
|
|
g_buffers->rigidIndices.size()); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (g_buffers->inflatableTriOffsets.size()) { |
|
|
NvFlexSetInflatables(g_solver, g_buffers->inflatableTriOffsets.buffer, g_buffers->inflatableTriCounts.buffer, |
|
|
g_buffers->inflatableVolumes.buffer, g_buffers->inflatablePressures.buffer, |
|
|
g_buffers->inflatableCoefficients.buffer, g_buffers->inflatableTriOffsets.size()); |
|
|
} |
|
|
|
|
|
|
|
|
if (g_buffers->triangles.size()) { |
|
|
NvFlexSetDynamicTriangles(g_solver, g_buffers->triangles.buffer, g_buffers->triangleNormals.buffer, |
|
|
g_buffers->triangles.size() / 3); |
|
|
} |
|
|
|
|
|
|
|
|
if (g_buffers->shapeFlags.size()) { |
|
|
NvFlexSetShapes( |
|
|
g_solver, |
|
|
g_buffers->shapeGeometry.buffer, |
|
|
g_buffers->shapePositions.buffer, |
|
|
g_buffers->shapeRotations.buffer, |
|
|
g_buffers->shapePrevPositions.buffer, |
|
|
g_buffers->shapePrevRotations.buffer, |
|
|
g_buffers->shapeFlags.buffer, |
|
|
int(g_buffers->shapeFlags.size())); |
|
|
} |
|
|
|
|
|
|
|
|
if (g_render) { |
|
|
g_fluidRenderBuffers = CreateFluidRenderBuffers(maxParticles, g_interop); |
|
|
g_diffuseRenderBuffers = CreateDiffuseRenderBuffers(g_maxDiffuseParticles, g_interop); |
|
|
} |
|
|
|
|
|
|
|
|
if (g_warmup) { |
|
|
printf("Warming up sim..\n"); |
|
|
|
|
|
|
|
|
NvFlexParams copy = g_params; |
|
|
copy.numIterations = 4; |
|
|
|
|
|
NvFlexSetParams(g_solver, ©); |
|
|
|
|
|
const int kWarmupIterations = 100; |
|
|
|
|
|
for (int i = 0; i < kWarmupIterations; ++i) { |
|
|
NvFlexUpdateSolver(g_solver, 0.0001f, 1, false); |
|
|
NvFlexSetVelocities(g_solver, g_buffers->velocities.buffer, NULL); |
|
|
} |
|
|
|
|
|
|
|
|
NvFlexGetParticles(g_solver, g_buffers->positions.buffer, NULL); |
|
|
NvFlexGetSmoothParticles(g_solver, g_buffers->smoothPositions.buffer, NULL); |
|
|
NvFlexGetAnisotropy(g_solver, g_buffers->anisotropy1.buffer, g_buffers->anisotropy2.buffer, |
|
|
g_buffers->anisotropy3.buffer, NULL); |
|
|
|
|
|
printf("Finished warm up.\n"); |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Shutdown() { |
|
|
|
|
|
DestroyBuffers(g_buffers); |
|
|
|
|
|
for (auto &iter : g_meshes) { |
|
|
NvFlexDestroyTriangleMesh(g_flexLib, iter.first); |
|
|
DestroyGpuMesh(iter.second); |
|
|
} |
|
|
|
|
|
for (auto &iter : g_fields) { |
|
|
NvFlexDestroyDistanceField(g_flexLib, iter.first); |
|
|
DestroyGpuMesh(iter.second); |
|
|
} |
|
|
|
|
|
for (auto &iter : g_convexes) { |
|
|
NvFlexDestroyConvexMesh(g_flexLib, iter.first); |
|
|
DestroyGpuMesh(iter.second); |
|
|
} |
|
|
|
|
|
g_fields.clear(); |
|
|
g_meshes.clear(); |
|
|
|
|
|
NvFlexDestroySolver(g_solver); |
|
|
NvFlexShutdown(g_flexLib); |
|
|
} |
|
|
|
|
|
void UpdateEmitters() { |
|
|
float spin = DegToRad(15.0f); |
|
|
|
|
|
const Vec3 forward(-sinf(g_camAngle.x + spin) * cosf(g_camAngle.y), sinf(g_camAngle.y), |
|
|
-cosf(g_camAngle.x + spin) * cosf(g_camAngle.y)); |
|
|
const Vec3 right(Normalize(Cross(forward, Vec3(0.0f, 1.0f, 0.0f)))); |
|
|
|
|
|
g_emitters[0].mDir = Normalize(forward + Vec3(0.0, 0.4f, 0.0f)); |
|
|
g_emitters[0].mRight = right; |
|
|
g_emitters[0].mPos = g_camPos + forward * 1.f + Vec3(0.0f, 0.2f, 0.0f) + right * 0.65f; |
|
|
|
|
|
|
|
|
if (g_emit) { |
|
|
int activeCount = NvFlexGetActiveCount(g_solver); |
|
|
|
|
|
size_t e = 0; |
|
|
|
|
|
|
|
|
if (g_camSmoothVel.z >= 0.025f) |
|
|
e = 1; |
|
|
|
|
|
for (; e < g_emitters.size(); ++e) { |
|
|
if (!g_emitters[e].mEnabled) |
|
|
continue; |
|
|
|
|
|
Vec3 emitterDir = g_emitters[e].mDir; |
|
|
Vec3 emitterRight = g_emitters[e].mRight; |
|
|
Vec3 emitterPos = g_emitters[e].mPos; |
|
|
|
|
|
float r = g_params.fluidRestDistance; |
|
|
int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid); |
|
|
|
|
|
float numParticles = (g_emitters[e].mSpeed / r) * g_dt; |
|
|
|
|
|
|
|
|
auto n = int(numParticles + g_emitters[e].mLeftOver); |
|
|
|
|
|
if (n) |
|
|
g_emitters[e].mLeftOver = (numParticles + g_emitters[e].mLeftOver) - n; |
|
|
else |
|
|
g_emitters[e].mLeftOver += numParticles; |
|
|
|
|
|
|
|
|
for (int k = 0; k < n; ++k) { |
|
|
int emitterWidth = g_emitters[e].mWidth; |
|
|
int numParticles = emitterWidth * emitterWidth; |
|
|
for (int i = 0; i < numParticles; ++i) { |
|
|
float x = float(i % emitterWidth) - float(emitterWidth / 2); |
|
|
float y = float((i / emitterWidth) % emitterWidth) - float(emitterWidth / 2); |
|
|
|
|
|
if ((sqr(x) + sqr(y)) <= (emitterWidth / 2) * (emitterWidth / 2)) { |
|
|
Vec3 up = Normalize(Cross(emitterDir, emitterRight)); |
|
|
Vec3 offset = r * (emitterRight * x + up * y) + float(k) * emitterDir * r; |
|
|
|
|
|
if (activeCount < g_buffers->positions.size()) { |
|
|
g_buffers->positions[activeCount] = Vec4(emitterPos + offset, 1.0f); |
|
|
g_buffers->velocities[activeCount] = emitterDir * g_emitters[e].mSpeed; |
|
|
g_buffers->phases[activeCount] = phase; |
|
|
|
|
|
g_buffers->activeIndices.push_back(activeCount); |
|
|
|
|
|
activeCount++; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
void UpdateCamera() { |
|
|
Vec3 forward(-sinf(g_camAngle.x) * cosf(g_camAngle.y), sinf(g_camAngle.y), |
|
|
-cosf(g_camAngle.x) * cosf(g_camAngle.y)); |
|
|
Vec3 right(Normalize(Cross(forward, Vec3(0.0f, 1.0f, 0.0f)))); |
|
|
|
|
|
g_camSmoothVel = Lerp(g_camSmoothVel, g_camVel, 0.1f); |
|
|
g_camPos += (forward * g_camSmoothVel.z + right * g_camSmoothVel.x + Cross(right, forward) * g_camSmoothVel.y); |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
void UpdateMouse() { |
|
|
|
|
|
if (g_lastb == -1) { |
|
|
if (g_mouseParticle != -1) { |
|
|
|
|
|
g_buffers->positions[g_mouseParticle].w = g_mouseMass; |
|
|
|
|
|
|
|
|
g_mouseParticle = -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (g_mousePicked) { |
|
|
assert(g_mouseParticle == -1); |
|
|
|
|
|
Vec3 origin, dir; |
|
|
GetViewRay(g_lastx, g_screenHeight - g_lasty, origin, dir); |
|
|
|
|
|
const int numActive = NvFlexGetActiveCount(g_solver); |
|
|
|
|
|
g_mouseParticle = PickParticle(origin, dir, &g_buffers->positions[0], &g_buffers->phases[0], numActive, |
|
|
g_params.radius * 0.8f, g_mouseT); |
|
|
|
|
|
if (g_mouseParticle != -1) { |
|
|
printf("picked: %d, mass: %f v: %f %f %f\n", g_mouseParticle, g_buffers->positions[g_mouseParticle].w, |
|
|
g_buffers->velocities[g_mouseParticle].x, g_buffers->velocities[g_mouseParticle].y, |
|
|
g_buffers->velocities[g_mouseParticle].z); |
|
|
|
|
|
g_mousePos = origin + dir * g_mouseT; |
|
|
g_mouseMass = g_buffers->positions[g_mouseParticle].w; |
|
|
g_buffers->positions[g_mouseParticle].w = 0.0f; |
|
|
} |
|
|
|
|
|
g_mousePicked = false; |
|
|
} |
|
|
|
|
|
|
|
|
if (g_mouseParticle != -1) { |
|
|
Vec3 p = Lerp(Vec3(g_buffers->positions[g_mouseParticle]), g_mousePos, 0.8f); |
|
|
Vec3 delta = p - Vec3(g_buffers->positions[g_mouseParticle]); |
|
|
|
|
|
g_buffers->positions[g_mouseParticle].x = p.x; |
|
|
g_buffers->positions[g_mouseParticle].y = p.y; |
|
|
g_buffers->positions[g_mouseParticle].z = p.z; |
|
|
|
|
|
g_buffers->velocities[g_mouseParticle].x = delta.x / g_dt; |
|
|
g_buffers->velocities[g_mouseParticle].y = delta.y / g_dt; |
|
|
g_buffers->velocities[g_mouseParticle].z = delta.z / g_dt; |
|
|
} |
|
|
} |
|
|
|
|
|
void UpdateWind() { |
|
|
g_windTime += g_dt; |
|
|
|
|
|
const Vec3 kWindDir = Vec3(3.0f, 15.0f, 0.0f); |
|
|
const float kNoise = Perlin1D(g_windTime * g_windFrequency, 10, 0.25f); |
|
|
Vec3 wind = g_windStrength * kWindDir * Vec3(kNoise, fabsf(kNoise), 0.0f); |
|
|
|
|
|
g_params.wind[0] = wind.x; |
|
|
g_params.wind[1] = wind.y; |
|
|
g_params.wind[2] = wind.z; |
|
|
|
|
|
if (g_wavePool) { |
|
|
g_waveTime += g_dt; |
|
|
g_params.planes[2][3] = |
|
|
g_wavePlane + (sinf(float(g_waveTime) * g_waveFrequency - kPi * 0.5f) * 0.5f + 0.5f) * g_waveAmplitude; |
|
|
} |
|
|
} |
|
|
|
|
|
void SyncScene() { |
|
|
|
|
|
g_scenes[g_scene]->Sync(); |
|
|
} |
|
|
|
|
|
void UpdateScene(py::array_t<float> update_params) { |
|
|
|
|
|
g_scenes[g_scene]->Update(update_params); |
|
|
} |
|
|
|
|
|
void RenderScene() { |
|
|
const int numParticles = NvFlexGetActiveCount(g_solver); |
|
|
const int numDiffuse = g_buffers->diffuseCount[0]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (numParticles) { |
|
|
if (g_interop) { |
|
|
|
|
|
UpdateFluidRenderBuffers(g_fluidRenderBuffers, g_solver, g_drawEllipsoids, g_drawDensity); |
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
if (g_drawEllipsoids) { |
|
|
|
|
|
UpdateFluidRenderBuffers(g_fluidRenderBuffers, |
|
|
&g_buffers->smoothPositions[0], |
|
|
(g_drawDensity) ? &g_buffers->densities[0] : (float *) &g_buffers->phases[0], |
|
|
&g_buffers->anisotropy1[0], |
|
|
&g_buffers->anisotropy2[0], |
|
|
&g_buffers->anisotropy3[0], |
|
|
g_buffers->positions.size(), |
|
|
&g_buffers->activeIndices[0], |
|
|
numParticles); |
|
|
} else { |
|
|
|
|
|
UpdateFluidRenderBuffers(g_fluidRenderBuffers, |
|
|
&g_buffers->positions[0], |
|
|
(float *) &g_buffers->phases[0], |
|
|
nullptr, nullptr, nullptr, |
|
|
g_buffers->positions.size(), |
|
|
&g_buffers->activeIndices[0], |
|
|
numParticles); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
GraphicsTimerBegin(); |
|
|
|
|
|
if (numDiffuse) { |
|
|
if (g_interop) { |
|
|
|
|
|
UpdateDiffuseRenderBuffers(g_diffuseRenderBuffers, g_solver); |
|
|
} else { |
|
|
|
|
|
UpdateDiffuseRenderBuffers(g_diffuseRenderBuffers, |
|
|
&g_buffers->diffusePositions[0], |
|
|
&g_buffers->diffuseVelocities[0], |
|
|
numDiffuse); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float fov = kPi / 4.0f; |
|
|
float aspect = float(g_screenWidth) / g_screenHeight; |
|
|
|
|
|
Matrix44 proj = ProjectionMatrix(RadToDeg(fov), aspect, g_camNear, g_camFar); |
|
|
Matrix44 view = RotationMatrix(-g_camAngle.x, Vec3(0.0f, 1.0f, 0.0f)) * |
|
|
RotationMatrix(-g_camAngle.y, Vec3(cosf(-g_camAngle.x), 0.0f, sinf(-g_camAngle.x))) * |
|
|
TranslationMatrix(-Point3(g_camPos)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
g_sceneLower = Min(g_sceneLower, Vec3(-2.0f, 0.0f, -2.0f)); |
|
|
g_sceneUpper = Max(g_sceneUpper, Vec3(2.0f, 2.0f, 2.0f)); |
|
|
|
|
|
Vec3 sceneExtents = g_sceneUpper - g_sceneLower; |
|
|
Vec3 sceneCenter = 0.5f * (g_sceneUpper + g_sceneLower); |
|
|
|
|
|
g_lightDir = Normalize(Vec3(5.0f, 15.0f, 7.5f)); |
|
|
g_lightPos = sceneCenter + g_lightDir * Length(sceneExtents) * g_lightDistance; |
|
|
g_lightTarget = sceneCenter; |
|
|
|
|
|
|
|
|
float lightFov = 2.0f * atanf(Length(g_sceneUpper - sceneCenter) / Length(g_lightPos - sceneCenter)); |
|
|
|
|
|
|
|
|
lightFov = Clamp(lightFov, DegToRad(25.0f), DegToRad(65.0f)); |
|
|
|
|
|
Matrix44 lightPerspective = ProjectionMatrix(RadToDeg(lightFov), 1.0f, 1.0f, 1000.0f); |
|
|
Matrix44 lightView = LookAtMatrix(Point3(g_lightPos), Point3(g_lightTarget)); |
|
|
Matrix44 lightTransform = lightPerspective * lightView; |
|
|
|
|
|
|
|
|
float radius = Max(g_params.solidRestDistance, g_params.fluidRestDistance) * 0.5f * g_pointScale; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (g_meshSkinIndices.size()) |
|
|
SkinMesh(); |
|
|
|
|
|
|
|
|
ShadowBegin(g_shadowMap); |
|
|
|
|
|
|
|
|
|
|
|
SetView(lightView, lightPerspective); |
|
|
SetCullMode(false); |
|
|
|
|
|
|
|
|
g_scenes[g_scene]->Draw(1); |
|
|
|
|
|
if (g_drawMesh && !g_clothOnly) |
|
|
DrawMesh(g_mesh, g_meshColor); |
|
|
|
|
|
|
|
|
if (!g_clothOnly) |
|
|
DrawShapes(); |
|
|
|
|
|
|
|
|
if (g_drawCloth && g_buffers->triangles.size()) { |
|
|
DrawCloth(&g_buffers->positions[0], &g_buffers->normals[0], g_buffers->uvs.size() ? &g_buffers->uvs[0].x : NULL, |
|
|
&g_buffers->triangles[0], g_buffers->triangles.size() / 3, g_buffers->positions.size(), 3, |
|
|
g_expandCloth); |
|
|
} |
|
|
|
|
|
if (g_drawRopes && !g_clothOnly) { |
|
|
for (size_t i = 0; i < g_ropes.size(); ++i) |
|
|
DrawRope(&g_buffers->positions[0], &g_ropes[i].mIndices[0], g_ropes[i].mIndices.size(), |
|
|
radius * g_ropeScale, i); |
|
|
} |
|
|
|
|
|
|
|
|
int shadowParticles = numParticles; |
|
|
int shadowParticlesOffset = 0; |
|
|
|
|
|
if (!g_drawPoints) { |
|
|
shadowParticles = 0; |
|
|
|
|
|
if (g_drawEllipsoids) { |
|
|
shadowParticles = numParticles - g_numSolidParticles; |
|
|
shadowParticlesOffset = g_numSolidParticles; |
|
|
} |
|
|
} else { |
|
|
int offset = g_drawMesh ? g_numSolidParticles : 0; |
|
|
|
|
|
shadowParticles = numParticles - offset; |
|
|
shadowParticlesOffset = offset; |
|
|
} |
|
|
|
|
|
if (g_buffers->activeIndices.size()) |
|
|
DrawPoints(g_fluidRenderBuffers, shadowParticles, shadowParticlesOffset, radius, 2048, 1.0f, lightFov, |
|
|
g_lightPos, g_lightTarget, lightTransform, g_shadowMap, g_drawDensity); |
|
|
|
|
|
ShadowEnd(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BindSolidShader(g_lightPos, g_lightTarget, lightTransform, g_shadowMap, 0.0f, Vec4(g_clearColor, g_fogDistance)); |
|
|
|
|
|
SetView(view, proj); |
|
|
SetCullMode(true); |
|
|
|
|
|
|
|
|
|
|
|
int passes = g_increaseGfxLoadForAsyncComputeTesting ? 50 : 1; |
|
|
|
|
|
for (int i = 0; i != passes; i++) { |
|
|
if (g_clothOnly){ |
|
|
if (g_drawCloth && g_buffers->triangles.size()) |
|
|
DrawCloth(&g_buffers->positions[0], &g_buffers->normals[0], |
|
|
g_buffers->uvs.size() ? &g_buffers->uvs[0].x : nullptr, &g_buffers->triangles[0], |
|
|
g_buffers->triangles.size() / 3, g_buffers->positions.size(), 3, g_expandCloth); |
|
|
} else |
|
|
{ |
|
|
DrawPlanes((Vec4 *) g_params.planes, g_params.numPlanes, g_drawPlaneBias); |
|
|
|
|
|
if (g_drawMesh) |
|
|
DrawMesh(g_mesh, g_meshColor); |
|
|
|
|
|
|
|
|
DrawShapes(); |
|
|
|
|
|
if (g_drawCloth && g_buffers->triangles.size()) |
|
|
DrawCloth(&g_buffers->positions[0], &g_buffers->normals[0], |
|
|
g_buffers->uvs.size() ? &g_buffers->uvs[0].x : nullptr, &g_buffers->triangles[0], |
|
|
g_buffers->triangles.size() / 3, g_buffers->positions.size(), 3, g_expandCloth); |
|
|
|
|
|
if (g_drawRopes) { |
|
|
for (size_t i = 0; i < g_ropes.size(); ++i) |
|
|
DrawRope(&g_buffers->positions[0], &g_ropes[i].mIndices[0], g_ropes[i].mIndices.size(), |
|
|
g_params.radius * 0.5f * g_ropeScale, i); |
|
|
} |
|
|
} |
|
|
|
|
|
g_scenes[g_scene]->Draw(0); |
|
|
} |
|
|
UnbindSolidShader(); |
|
|
|
|
|
|
|
|
|
|
|
if (g_drawDiffuse) |
|
|
RenderDiffuse(g_fluidRenderer, g_diffuseRenderBuffers, numDiffuse, radius * g_diffuseScale, |
|
|
float(g_screenWidth), aspect, fov, g_diffuseColor, g_lightPos, g_lightTarget, lightTransform, |
|
|
g_shadowMap, g_diffuseMotionScale, g_diffuseInscatter, g_diffuseOutscatter, g_diffuseShadow, |
|
|
false); |
|
|
|
|
|
|
|
|
if (g_drawEllipsoids) { |
|
|
|
|
|
if (g_numSolidParticles && g_drawPoints) |
|
|
DrawPoints(g_fluidRenderBuffers, g_numSolidParticles, 0, radius, float(g_screenWidth), aspect, fov, |
|
|
g_lightPos, g_lightTarget, lightTransform, g_shadowMap, g_drawDensity); |
|
|
|
|
|
|
|
|
|
|
|
RenderEllipsoids(g_fluidRenderer, g_fluidRenderBuffers, numParticles - g_numSolidParticles, g_numSolidParticles, |
|
|
radius, float(g_screenWidth), aspect, fov, g_lightPos, g_lightTarget, lightTransform, |
|
|
g_shadowMap, g_fluidColor, g_blur, g_ior, g_drawOpaque); |
|
|
|
|
|
|
|
|
|
|
|
if (g_drawDiffuse) |
|
|
RenderDiffuse(g_fluidRenderer, g_diffuseRenderBuffers, numDiffuse, radius * g_diffuseScale, |
|
|
float(g_screenWidth), aspect, fov, g_diffuseColor, g_lightPos, g_lightTarget, lightTransform, |
|
|
g_shadowMap, g_diffuseMotionScale, g_diffuseInscatter, g_diffuseOutscatter, g_diffuseShadow, |
|
|
true); |
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
if (g_drawPoints) { |
|
|
int offset = g_drawMesh ? g_numSolidParticles : 0; |
|
|
|
|
|
if (g_buffers->activeIndices.size()) |
|
|
DrawPoints(g_fluidRenderBuffers, numParticles - offset, offset, radius, float(g_screenWidth), aspect, |
|
|
fov, g_lightPos, g_lightTarget, lightTransform, g_shadowMap, g_drawDensity); |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
GraphicsTimerEnd(); |
|
|
|
|
|
} |
|
|
|
|
|
void RenderDebug() { |
|
|
if (g_mouseParticle != -1) { |
|
|
|
|
|
BeginLines(); |
|
|
DrawLine(g_mousePos, Vec3(g_buffers->positions[g_mouseParticle]), Vec4(1.0f)); |
|
|
EndLines(); |
|
|
} |
|
|
|
|
|
|
|
|
if (g_drawSprings) { |
|
|
Vec4 color; |
|
|
|
|
|
if (g_drawSprings == 1) { |
|
|
|
|
|
color = Vec4(0.0f, 0.0f, 1.0f, 0.8f); |
|
|
} |
|
|
if (g_drawSprings == 2) { |
|
|
|
|
|
color = Vec4(0.0f, 1.0f, 0.0f, 0.8f); |
|
|
} |
|
|
|
|
|
BeginLines(); |
|
|
|
|
|
int start = 0; |
|
|
|
|
|
for (int i = start; i < g_buffers->springLengths.size(); ++i) { |
|
|
if (g_drawSprings == 1 && g_buffers->springStiffness[i] < 0.0f) |
|
|
continue; |
|
|
if (g_drawSprings == 2 && g_buffers->springStiffness[i] > 0.0f) |
|
|
continue; |
|
|
|
|
|
int a = g_buffers->springIndices[i * 2]; |
|
|
int b = g_buffers->springIndices[i * 2 + 1]; |
|
|
|
|
|
DrawLine(Vec3(g_buffers->positions[a]), Vec3(g_buffers->positions[b]), color); |
|
|
} |
|
|
|
|
|
EndLines(); |
|
|
} |
|
|
|
|
|
|
|
|
if (g_drawContacts) { |
|
|
const int maxContactsPerParticle = 6; |
|
|
|
|
|
NvFlexVector<Vec4> contactPlanes(g_flexLib, g_buffers->positions.size() * maxContactsPerParticle); |
|
|
NvFlexVector<Vec4> contactVelocities(g_flexLib, g_buffers->positions.size() * maxContactsPerParticle); |
|
|
NvFlexVector<int> contactIndices(g_flexLib, g_buffers->positions.size()); |
|
|
NvFlexVector<unsigned int> contactCounts(g_flexLib, g_buffers->positions.size()); |
|
|
|
|
|
NvFlexGetContacts(g_solver, contactPlanes.buffer, contactVelocities.buffer, contactIndices.buffer, |
|
|
contactCounts.buffer); |
|
|
|
|
|
|
|
|
contactPlanes.map(); |
|
|
contactVelocities.map(); |
|
|
contactIndices.map(); |
|
|
contactCounts.map(); |
|
|
|
|
|
BeginLines(); |
|
|
|
|
|
for (int i = 0; i < int(g_buffers->activeIndices.size()); ++i) { |
|
|
const int contactIndex = contactIndices[g_buffers->activeIndices[i]]; |
|
|
const unsigned int count = contactCounts[contactIndex]; |
|
|
|
|
|
const float scale = 0.1f; |
|
|
|
|
|
for (unsigned int c = 0; c < count; ++c) { |
|
|
Vec4 plane = contactPlanes[contactIndex * maxContactsPerParticle + c]; |
|
|
|
|
|
DrawLine(Vec3(g_buffers->positions[g_buffers->activeIndices[i]]), |
|
|
Vec3(g_buffers->positions[g_buffers->activeIndices[i]]) + Vec3(plane) * scale, |
|
|
Vec4(0.0f, 1.0f, 0.0f, 0.0f)); |
|
|
} |
|
|
} |
|
|
|
|
|
EndLines(); |
|
|
} |
|
|
|
|
|
if (g_drawBases) { |
|
|
for (int i = 0; i < int(g_buffers->rigidRotations.size()); ++i) { |
|
|
BeginLines(); |
|
|
|
|
|
float size = 0.1f; |
|
|
|
|
|
for (int b = 0; b < 3; ++b) { |
|
|
Vec3 color(0.0f, 0.0f, 0.0f); |
|
|
|
|
|
if (b == 0) |
|
|
color.x = 1.0f; |
|
|
else if (b == 1) |
|
|
color.y = 1.0f; |
|
|
else |
|
|
color.z = 1.0f; |
|
|
|
|
|
Matrix33 frame(g_buffers->rigidRotations[i]); |
|
|
|
|
|
DrawLine(Vec3(g_buffers->rigidTranslations[i]), |
|
|
Vec3(g_buffers->rigidTranslations[i] + frame.cols[b] * size), |
|
|
Vec4(color, 0.0f)); |
|
|
} |
|
|
|
|
|
EndLines(); |
|
|
} |
|
|
} |
|
|
|
|
|
if (g_drawNormals) { |
|
|
NvFlexGetNormals(g_solver, g_buffers->normals.buffer, nullptr); |
|
|
|
|
|
BeginLines(); |
|
|
|
|
|
for (int i = 0; i < g_buffers->normals.size(); ++i) { |
|
|
DrawLine(Vec3(g_buffers->positions[i]), |
|
|
Vec3(g_buffers->positions[i] - g_buffers->normals[i] * g_buffers->normals[i].w), |
|
|
Vec4(0.0f, 1.0f, 0.0f, 0.0f)); |
|
|
} |
|
|
|
|
|
EndLines(); |
|
|
} |
|
|
} |
|
|
|
|
|
void DrawShapes() { |
|
|
for (int i = 0; i < g_buffers->shapeFlags.size(); ++i) { |
|
|
|
|
|
const int flags = g_buffers->shapeFlags[i]; |
|
|
|
|
|
|
|
|
auto type = int(flags & eNvFlexShapeFlagTypeMask); |
|
|
|
|
|
|
|
|
Vec3 color = g_shape_color; |
|
|
|
|
|
if (flags & eNvFlexShapeFlagTrigger) { |
|
|
|
|
|
color = Vec3(1.0f, 0.0f, 0.0f); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const Quat rotation = g_buffers->shapePrevRotations[i]; |
|
|
const Vec3 position = Vec3(g_buffers->shapePrevPositions[i]); |
|
|
|
|
|
NvFlexCollisionGeometry geo = g_buffers->shapeGeometry[i]; |
|
|
|
|
|
if (type == eNvFlexShapeSphere) { |
|
|
Mesh *sphere = CreateSphere(20, 20, geo.sphere.radius); |
|
|
|
|
|
Matrix44 xform = TranslationMatrix(Point3(position)) * RotationMatrix(Quat(rotation)); |
|
|
sphere->Transform(xform); |
|
|
|
|
|
DrawMesh(sphere, Vec3(color)); |
|
|
|
|
|
delete sphere; |
|
|
} else if (type == eNvFlexShapeCapsule) { |
|
|
Mesh *capsule = CreateCapsule(10, 20, geo.capsule.radius, geo.capsule.halfHeight); |
|
|
|
|
|
|
|
|
Matrix44 xform = TranslationMatrix(Point3(position)) * RotationMatrix(Quat(rotation)) * |
|
|
RotationMatrix(DegToRad(-90.0f), Vec3(0.0f, 0.0f, 1.0f)); |
|
|
capsule->Transform(xform); |
|
|
|
|
|
DrawMesh(capsule, Vec3(color)); |
|
|
|
|
|
delete capsule; |
|
|
} else if (type == eNvFlexShapeBox) { |
|
|
Mesh *box = CreateCubeMesh(); |
|
|
|
|
|
Matrix44 xform = TranslationMatrix(Point3(position)) * RotationMatrix(Quat(rotation)) * |
|
|
ScaleMatrix(Vec3(geo.box.halfExtents) * 2.0f); |
|
|
box->Transform(xform); |
|
|
|
|
|
DrawMesh(box, Vec3(color)); |
|
|
delete box; |
|
|
} else if (type == eNvFlexShapeConvexMesh) { |
|
|
if (g_convexes.find(geo.convexMesh.mesh) != g_convexes.end()) { |
|
|
GpuMesh *m = g_convexes[geo.convexMesh.mesh]; |
|
|
|
|
|
if (m) { |
|
|
Matrix44 xform = TranslationMatrix(Point3(g_buffers->shapePositions[i])) * |
|
|
RotationMatrix(Quat(g_buffers->shapeRotations[i])) * |
|
|
ScaleMatrix(geo.convexMesh.scale); |
|
|
DrawGpuMesh(m, xform, Vec3(color)); |
|
|
} |
|
|
} |
|
|
} else if (type == eNvFlexShapeTriangleMesh) { |
|
|
if (g_meshes.find(geo.triMesh.mesh) != g_meshes.end()) { |
|
|
GpuMesh *m = g_meshes[geo.triMesh.mesh]; |
|
|
|
|
|
if (m) { |
|
|
Matrix44 xform = TranslationMatrix(Point3(position)) * RotationMatrix(Quat(rotation)) * |
|
|
ScaleMatrix(geo.triMesh.scale); |
|
|
DrawGpuMesh(m, xform, Vec3(color)); |
|
|
} |
|
|
} |
|
|
} else if (type == eNvFlexShapeSDF) { |
|
|
if (g_fields.find(geo.sdf.field) != g_fields.end()) { |
|
|
GpuMesh *m = g_fields[geo.sdf.field]; |
|
|
|
|
|
if (m) { |
|
|
Matrix44 xform = TranslationMatrix(Point3(position)) * RotationMatrix(Quat(rotation)) * |
|
|
ScaleMatrix(geo.sdf.scale); |
|
|
DrawGpuMesh(m, xform, Vec3(color)); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
SetFillMode(g_wireframe); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int DoUI() { |
|
|
|
|
|
int newScene = -1; |
|
|
|
|
|
if (g_showHelp) { |
|
|
const int numParticles = NvFlexGetActiveCount(g_solver); |
|
|
const int numDiffuse = g_buffers->diffuseCount[0]; |
|
|
|
|
|
int x = g_screenWidth - 200; |
|
|
int y = g_screenHeight - 23; |
|
|
|
|
|
|
|
|
unsigned char button = 0; |
|
|
if (g_lastb == SDL_BUTTON_LEFT) |
|
|
button = IMGUI_MBUT_LEFT; |
|
|
else if (g_lastb == SDL_BUTTON_RIGHT) |
|
|
button = IMGUI_MBUT_RIGHT; |
|
|
|
|
|
imguiBeginFrame(g_lastx, g_screenHeight - g_lasty, button, 0); |
|
|
|
|
|
x += 180; |
|
|
|
|
|
int fontHeight = 13; |
|
|
|
|
|
if (g_profile) { |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Frame: %d", g_frame); |
|
|
y -= fontHeight * 2; |
|
|
|
|
|
if (!g_ffmpeg) { |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Frame Time: %.2fms", g_realdt * 1000.0f); |
|
|
y -= fontHeight * 2; |
|
|
|
|
|
|
|
|
if (!g_profile) { |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Sim Time (CPU): %.2fms", |
|
|
g_updateTime * 1000.0f); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(0.97f, 0.59f, 0.27f), IMGUI_ALIGN_RIGHT, "Sim Latency (GPU): %.2fms", |
|
|
g_simLatency); |
|
|
y -= fontHeight * 2; |
|
|
|
|
|
BenchmarkUpdateGraph(); |
|
|
} else { |
|
|
y -= fontHeight * 3; |
|
|
} |
|
|
} |
|
|
|
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Particle Count: %d", numParticles); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Diffuse Count: %d", numDiffuse); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Rigid Count: %d", |
|
|
g_buffers->rigidOffsets.size() > 0 ? g_buffers->rigidOffsets.size() - 1 : 0); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Spring Count: %d", g_buffers->springLengths.size()); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Num Substeps: %d", g_numSubsteps); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Num Iterations: %d", g_params.numIterations); |
|
|
y -= fontHeight * 2; |
|
|
|
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Device: %s", g_deviceName); |
|
|
y -= fontHeight * 2; |
|
|
} |
|
|
|
|
|
if (g_profile) { |
|
|
DrawImguiString(x, y, Vec3(0.97f, 0.59f, 0.27f), IMGUI_ALIGN_RIGHT, "Total GPU Sim Latency: %.2fms", |
|
|
g_timers.total); |
|
|
y -= fontHeight * 2; |
|
|
|
|
|
DrawImguiString(x, y, Vec3(0.0f, 1.0f, 0.0f), IMGUI_ALIGN_RIGHT, "GPU Latencies"); |
|
|
y -= fontHeight; |
|
|
|
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Predict: %.2fms", g_timers.predict); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Create Cell Indices: %.2fms", |
|
|
g_timers.createCellIndices); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Sort Cell Indices: %.2fms", g_timers.sortCellIndices); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Reorder: %.2fms", g_timers.reorder); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "CreateGrid: %.2fms", g_timers.createGrid); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Collide Particles: %.2fms", |
|
|
g_timers.collideParticles); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Collide Shapes: %.2fms", g_timers.collideShapes); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Collide Triangles: %.2fms", |
|
|
g_timers.collideTriangles); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Calculate Density: %.2fms", |
|
|
g_timers.calculateDensity); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Solve Densities: %.2fms", g_timers.solveDensities); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Solve Velocities: %.2fms", g_timers.solveVelocities); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Solve Rigids: %.2fms", g_timers.solveShapes); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Solve Springs: %.2fms", g_timers.solveSprings); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Solve Inflatables: %.2fms", |
|
|
g_timers.solveInflatables); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Solve Contacts: %.2fms", g_timers.solveContacts); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Apply Deltas: %.2fms", g_timers.applyDeltas); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Finalize: %.2fms", g_timers.finalize); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Update Triangles: %.2fms", g_timers.updateTriangles); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Update Normals: %.2fms", g_timers.updateNormals); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Update Bounds: %.2fms", g_timers.updateBounds); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Calculate Anisotropy: %.2fms", |
|
|
g_timers.calculateAnisotropy); |
|
|
y -= fontHeight; |
|
|
DrawImguiString(x, y, Vec3(1.0f), IMGUI_ALIGN_RIGHT, "Update Diffuse: %.2fms", g_timers.updateDiffuse); |
|
|
y -= fontHeight * 2; |
|
|
} |
|
|
|
|
|
x -= 180; |
|
|
|
|
|
int uiOffset = 250; |
|
|
int uiBorder = 20; |
|
|
int uiWidth = 200; |
|
|
int uiHeight = g_screenHeight - uiOffset - uiBorder * 3; |
|
|
int uiLeft = uiBorder; |
|
|
|
|
|
if (g_tweakPanel) |
|
|
imguiBeginScrollArea("Scene", uiLeft, g_screenHeight - uiBorder - uiOffset, uiWidth, uiOffset, |
|
|
&g_levelScroll); |
|
|
else |
|
|
imguiBeginScrollArea("Scene", uiLeft, uiBorder, uiWidth, g_screenHeight - uiBorder - uiBorder, |
|
|
&g_levelScroll); |
|
|
|
|
|
for (int i = 0; i < int(g_scenes.size()); ++i) { |
|
|
unsigned int color = g_scene == i ? imguiRGBA(255, 151, 61, 255) : imguiRGBA(255, 255, 255, 200); |
|
|
if (imguiItem(g_scenes[i]->GetName(), true, color)) { |
|
|
newScene = i; |
|
|
} |
|
|
} |
|
|
|
|
|
imguiEndScrollArea(); |
|
|
|
|
|
if (g_tweakPanel) { |
|
|
static int scroll = 0; |
|
|
|
|
|
imguiBeginScrollArea("Options", uiLeft, g_screenHeight - uiBorder - uiHeight - uiOffset - uiBorder, uiWidth, |
|
|
uiHeight, &scroll); |
|
|
imguiSeparatorLine(); |
|
|
|
|
|
|
|
|
imguiLabel("Global"); |
|
|
if (imguiCheck("Emit particles", g_emit)) |
|
|
g_emit = !g_emit; |
|
|
|
|
|
if (imguiCheck("Pause", g_pause)) |
|
|
g_pause = !g_pause; |
|
|
|
|
|
imguiSeparatorLine(); |
|
|
|
|
|
if (imguiCheck("Wireframe", g_wireframe)) |
|
|
g_wireframe = !g_wireframe; |
|
|
|
|
|
if (imguiCheck("Draw Points", g_drawPoints)) |
|
|
g_drawPoints = !g_drawPoints; |
|
|
|
|
|
if (imguiCheck("Draw Fluid", g_drawEllipsoids)) |
|
|
g_drawEllipsoids = !g_drawEllipsoids; |
|
|
|
|
|
if (imguiCheck("Draw Mesh", g_drawMesh)) { |
|
|
g_drawMesh = !g_drawMesh; |
|
|
g_drawRopes = !g_drawRopes; |
|
|
} |
|
|
|
|
|
if (imguiCheck("Draw Basis", g_drawBases)) |
|
|
g_drawBases = !g_drawBases; |
|
|
|
|
|
if (imguiCheck("Draw Springs", bool(g_drawSprings != 0))) |
|
|
g_drawSprings = (g_drawSprings) ? 0 : 1; |
|
|
|
|
|
if (imguiCheck("Draw Contacts", g_drawContacts)) |
|
|
g_drawContacts = !g_drawContacts; |
|
|
|
|
|
imguiSeparatorLine(); |
|
|
|
|
|
|
|
|
g_scenes[g_scene]->DoGui(); |
|
|
|
|
|
if (imguiButton("Reset Scene")) |
|
|
g_resetScene = true; |
|
|
|
|
|
imguiSeparatorLine(); |
|
|
|
|
|
auto n = float(g_numSubsteps); |
|
|
if (imguiSlider("Num Substeps", &n, 1, 10, 1)) |
|
|
g_numSubsteps = int(n); |
|
|
|
|
|
n = float(g_params.numIterations); |
|
|
if (imguiSlider("Num Iterations", &n, 1, 20, 1)) |
|
|
g_params.numIterations = int(n); |
|
|
|
|
|
imguiSeparatorLine(); |
|
|
imguiSlider("Gravity X", &g_params.gravity[0], -50.0f, 50.0f, 1.0f); |
|
|
imguiSlider("Gravity Y", &g_params.gravity[1], -50.0f, 50.0f, 1.0f); |
|
|
imguiSlider("Gravity Z", &g_params.gravity[2], -50.0f, 50.0f, 1.0f); |
|
|
|
|
|
imguiSeparatorLine(); |
|
|
imguiSlider("Radius", &g_params.radius, 0.01f, 0.5f, 0.01f); |
|
|
imguiSlider("Solid Radius", &g_params.solidRestDistance, 0.0f, 0.5f, 0.001f); |
|
|
imguiSlider("Fluid Radius", &g_params.fluidRestDistance, 0.0f, 0.5f, 0.001f); |
|
|
|
|
|
|
|
|
imguiSeparatorLine(); |
|
|
imguiSlider("Dynamic Friction", &g_params.dynamicFriction, 0.0f, 1.0f, 0.01f); |
|
|
imguiSlider("Static Friction", &g_params.staticFriction, 0.0f, 1.0f, 0.01f); |
|
|
imguiSlider("Particle Friction", &g_params.particleFriction, 0.0f, 1.0f, 0.01f); |
|
|
imguiSlider("Restitution", &g_params.restitution, 0.0f, 1.0f, 0.01f); |
|
|
imguiSlider("SleepThreshold", &g_params.sleepThreshold, 0.0f, 1.0f, 0.01f); |
|
|
imguiSlider("Shock Propagation", &g_params.shockPropagation, 0.0f, 10.0f, 0.01f); |
|
|
imguiSlider("Damping", &g_params.damping, 0.0f, 10.0f, 0.01f); |
|
|
imguiSlider("Dissipation", &g_params.dissipation, 0.0f, 0.01f, 0.0001f); |
|
|
imguiSlider("SOR", &g_params.relaxationFactor, 0.0f, 5.0f, 0.01f); |
|
|
|
|
|
imguiSlider("Collision Distance", &g_params.collisionDistance, 0.0f, 0.5f, 0.001f); |
|
|
imguiSlider("Collision Margin", &g_params.shapeCollisionMargin, 0.0f, 5.0f, 0.01f); |
|
|
|
|
|
|
|
|
imguiSeparatorLine(); |
|
|
imguiSlider("Wind", &g_windStrength, -1.0f, 1.0f, 0.01f); |
|
|
imguiSlider("Drag", &g_params.drag, 0.0f, 1.0f, 0.01f); |
|
|
imguiSlider("Lift", &g_params.lift, 0.0f, 1.0f, 0.01f); |
|
|
imguiSeparatorLine(); |
|
|
|
|
|
|
|
|
imguiSlider("Adhesion", &g_params.adhesion, 0.0f, 10.0f, 0.01f); |
|
|
imguiSlider("Cohesion", &g_params.cohesion, 0.0f, 0.2f, 0.0001f); |
|
|
imguiSlider("Surface Tension", &g_params.surfaceTension, 0.0f, 50.0f, 0.01f); |
|
|
imguiSlider("Viscosity", &g_params.viscosity, 0.0f, 120.0f, 0.01f); |
|
|
imguiSlider("Vorticicty Confinement", &g_params.vorticityConfinement, 0.0f, 120.0f, 0.1f); |
|
|
imguiSlider("Solid Pressure", &g_params.solidPressure, 0.0f, 1.0f, 0.01f); |
|
|
imguiSlider("Surface Drag", &g_params.freeSurfaceDrag, 0.0f, 1.0f, 0.01f); |
|
|
imguiSlider("Buoyancy", &g_params.buoyancy, -1.0f, 1.0f, 0.01f); |
|
|
|
|
|
imguiSeparatorLine(); |
|
|
imguiSlider("Anisotropy Scale", &g_params.anisotropyScale, 0.0f, 30.0f, 0.01f); |
|
|
imguiSlider("Smoothing", &g_params.smoothing, 0.0f, 1.0f, 0.01f); |
|
|
|
|
|
|
|
|
imguiSeparatorLine(); |
|
|
imguiSlider("Diffuse Threshold", &g_params.diffuseThreshold, 0.0f, 1000.0f, 1.0f); |
|
|
imguiSlider("Diffuse Buoyancy", &g_params.diffuseBuoyancy, 0.0f, 2.0f, 0.01f); |
|
|
imguiSlider("Diffuse Drag", &g_params.diffuseDrag, 0.0f, 2.0f, 0.01f); |
|
|
imguiSlider("Diffuse Scale", &g_diffuseScale, 0.0f, 1.5f, 0.01f); |
|
|
imguiSlider("Diffuse Alpha", &g_diffuseColor.w, 0.0f, 3.0f, 0.01f); |
|
|
imguiSlider("Diffuse Inscatter", &g_diffuseInscatter, 0.0f, 2.0f, 0.01f); |
|
|
imguiSlider("Diffuse Outscatter", &g_diffuseOutscatter, 0.0f, 2.0f, 0.01f); |
|
|
imguiSlider("Diffuse Motion Blur", &g_diffuseMotionScale, 0.0f, 5.0f, 0.1f); |
|
|
|
|
|
n = float(g_params.diffuseBallistic); |
|
|
if (imguiSlider("Diffuse Ballistic", &n, 1, 40, 1)) |
|
|
g_params.diffuseBallistic = int(n); |
|
|
|
|
|
imguiEndScrollArea(); |
|
|
} |
|
|
|
|
|
imguiEndFrame(); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
return newScene; |
|
|
} |
|
|
|
|
|
void UpdateFrame(py::array_t<float> update_params) { |
|
|
if (!g_headless) { |
|
|
static double lastTime; |
|
|
|
|
|
|
|
|
double frameBeginTime = GetSeconds(); |
|
|
|
|
|
g_realdt = float(frameBeginTime - lastTime); |
|
|
lastTime = frameBeginTime; |
|
|
|
|
|
|
|
|
double currentTime = frameBeginTime; |
|
|
static double lastJoyTime = currentTime; |
|
|
|
|
|
if (g_gamecontroller && currentTime - lastJoyTime > g_dt) { |
|
|
lastJoyTime = currentTime; |
|
|
|
|
|
int leftStickX = SDL_GameControllerGetAxis(g_gamecontroller, SDL_CONTROLLER_AXIS_LEFTX); |
|
|
int leftStickY = SDL_GameControllerGetAxis(g_gamecontroller, SDL_CONTROLLER_AXIS_LEFTY); |
|
|
int rightStickX = SDL_GameControllerGetAxis(g_gamecontroller, SDL_CONTROLLER_AXIS_RIGHTX); |
|
|
int rightStickY = SDL_GameControllerGetAxis(g_gamecontroller, SDL_CONTROLLER_AXIS_RIGHTY); |
|
|
int leftTrigger = SDL_GameControllerGetAxis(g_gamecontroller, SDL_CONTROLLER_AXIS_TRIGGERLEFT); |
|
|
int rightTrigger = SDL_GameControllerGetAxis(g_gamecontroller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); |
|
|
|
|
|
Vec2 leftStick(joyAxisFilter(leftStickX, 0), joyAxisFilter(leftStickY, 0)); |
|
|
Vec2 rightStick(joyAxisFilter(rightStickX, 1), joyAxisFilter(rightStickY, 1)); |
|
|
Vec2 trigger(leftTrigger / 32768.0f, rightTrigger / 32768.0f); |
|
|
|
|
|
if (leftStick.x != 0.0f || leftStick.y != 0.0f || |
|
|
rightStick.x != 0.0f || rightStick.y != 0.0f) { |
|
|
|
|
|
g_camVel.z = -4 * g_camSpeed * leftStick.y; |
|
|
g_camVel.x = 4 * g_camSpeed * leftStick.x; |
|
|
|
|
|
|
|
|
g_camAngle.x -= rightStick.x * 0.05f; |
|
|
g_camAngle.y -= rightStick.y * 0.05f; |
|
|
} |
|
|
|
|
|
|
|
|
static bool bLeftStick = false; |
|
|
|
|
|
if ((leftStick.x != 0.0f || leftStick.y != 0.0f) && !bLeftStick) { |
|
|
bLeftStick = true; |
|
|
} else if ((leftStick.x == 0.0f && leftStick.y == 0.0f) && bLeftStick) { |
|
|
bLeftStick = false; |
|
|
g_camVel.z = -4 * g_camSpeed * leftStick.y; |
|
|
g_camVel.x = 4 * g_camSpeed * leftStick.x; |
|
|
} |
|
|
|
|
|
|
|
|
void ControllerButtonEvent(SDL_ControllerButtonEvent event); |
|
|
|
|
|
static bool bLeftTrigger = false; |
|
|
static bool bRightTrigger = false; |
|
|
SDL_ControllerButtonEvent e; |
|
|
|
|
|
if (!bLeftTrigger && trigger.x > 0.0f) { |
|
|
e.type = SDL_CONTROLLERBUTTONDOWN; |
|
|
e.button = SDL_CONTROLLER_BUTTON_LEFT_TRIGGER; |
|
|
ControllerButtonEvent(e); |
|
|
bLeftTrigger = true; |
|
|
} else if (bLeftTrigger && trigger.x == 0.0f) { |
|
|
e.type = SDL_CONTROLLERBUTTONUP; |
|
|
e.button = SDL_CONTROLLER_BUTTON_LEFT_TRIGGER; |
|
|
ControllerButtonEvent(e); |
|
|
bLeftTrigger = false; |
|
|
} |
|
|
|
|
|
if (!bRightTrigger && trigger.y > 0.0f) { |
|
|
e.type = SDL_CONTROLLERBUTTONDOWN; |
|
|
e.button = SDL_CONTROLLER_BUTTON_RIGHT_TRIGGER; |
|
|
ControllerButtonEvent(e); |
|
|
bRightTrigger = true; |
|
|
} else if (bRightTrigger && trigger.y == 0.0f) { |
|
|
e.type = SDL_CONTROLLERBUTTONDOWN; |
|
|
e.button = SDL_CONTROLLER_BUTTON_RIGHT_TRIGGER; |
|
|
ControllerButtonEvent(e); |
|
|
bRightTrigger = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double waitBeginTime = GetSeconds(); |
|
|
|
|
|
MapBuffers(g_buffers); |
|
|
|
|
|
double waitEndTime = GetSeconds(); |
|
|
|
|
|
float newSimLatency = 0.0f; |
|
|
float newGfxLatency = 0.0f; |
|
|
|
|
|
if (!g_headless) |
|
|
{ |
|
|
|
|
|
newSimLatency = NvFlexGetDeviceLatency(g_solver, &g_GpuTimers.computeBegin, &g_GpuTimers.computeEnd, &g_GpuTimers.computeFreq); |
|
|
newGfxLatency = RendererGetDeviceTimestamps(&g_GpuTimers.renderBegin, &g_GpuTimers.renderEnd, &g_GpuTimers.renderFreq); |
|
|
(void)newGfxLatency; |
|
|
|
|
|
UpdateCamera(); |
|
|
|
|
|
if (!g_pause || g_step) |
|
|
{ |
|
|
UpdateEmitters(); |
|
|
UpdateMouse(); |
|
|
UpdateWind(); |
|
|
UpdateScene(update_params); |
|
|
} |
|
|
|
|
|
} |
|
|
else |
|
|
{ |
|
|
if (g_render) { |
|
|
UpdateCamera(); |
|
|
} |
|
|
|
|
|
UpdateEmitters(); |
|
|
|
|
|
UpdateWind(); |
|
|
|
|
|
UpdateScene(update_params); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int newScene = -1; |
|
|
double renderBeginTime = GetSeconds(); |
|
|
|
|
|
if (g_render) { |
|
|
|
|
|
|
|
|
if (g_profile && (!g_pause || g_step)) { |
|
|
if (g_benchmark) { |
|
|
g_numDetailTimers = NvFlexGetDetailTimers(g_solver, &g_detailTimers); |
|
|
} else { |
|
|
memset(&g_timers, 0, sizeof(g_timers)); |
|
|
NvFlexGetTimers(g_solver, &g_timers); |
|
|
} |
|
|
} |
|
|
|
|
|
StartFrame(Vec4(g_clearColor, 1.0f)); |
|
|
|
|
|
|
|
|
|
|
|
RenderScene(); |
|
|
RenderDebug(); |
|
|
|
|
|
|
|
|
|
|
|
if (!g_headless) { |
|
|
newScene = DoUI(); |
|
|
} |
|
|
|
|
|
EndFrame(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!g_useAsyncCompute) |
|
|
NvFlexComputeWaitForGraphics(g_flexLib); |
|
|
} |
|
|
|
|
|
UnmapBuffers(g_buffers); |
|
|
|
|
|
|
|
|
if (!g_headless) { |
|
|
|
|
|
if (g_mouseParticle != -1) { |
|
|
Vec3 origin, dir; |
|
|
GetViewRay(g_lastx, g_screenHeight - g_lasty, origin, dir); |
|
|
|
|
|
g_mousePos = origin + dir*g_mouseT; |
|
|
} |
|
|
} |
|
|
|
|
|
if (g_render) { |
|
|
if (g_capture) { |
|
|
TgaImage img; |
|
|
img.m_width = g_screenWidth; |
|
|
img.m_height = g_screenHeight; |
|
|
img.m_data = new uint32_t[g_screenWidth * g_screenHeight]; |
|
|
|
|
|
ReadFrame((int *) img.m_data, g_screenWidth, g_screenHeight); |
|
|
TgaSave(g_ffmpeg, img, false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
delete[] img.m_data; |
|
|
} |
|
|
} |
|
|
|
|
|
double renderEndTime = GetSeconds(); |
|
|
|
|
|
|
|
|
if (g_resetScene) { |
|
|
|
|
|
g_resetScene = false; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double updateBeginTime = GetSeconds(); |
|
|
|
|
|
|
|
|
NvFlexSetParticles(g_solver, g_buffers->positions.buffer, nullptr); |
|
|
NvFlexSetVelocities(g_solver, g_buffers->velocities.buffer, nullptr); |
|
|
NvFlexSetPhases(g_solver, g_buffers->phases.buffer, nullptr); |
|
|
NvFlexSetActive(g_solver, g_buffers->activeIndices.buffer, nullptr); |
|
|
|
|
|
NvFlexSetActiveCount(g_solver, g_buffers->activeIndices.size()); |
|
|
|
|
|
|
|
|
SyncScene(); |
|
|
|
|
|
if (g_shapesChanged) { |
|
|
NvFlexSetShapes( |
|
|
g_solver, |
|
|
g_buffers->shapeGeometry.buffer, |
|
|
g_buffers->shapePositions.buffer, |
|
|
g_buffers->shapeRotations.buffer, |
|
|
g_buffers->shapePrevPositions.buffer, |
|
|
g_buffers->shapePrevRotations.buffer, |
|
|
g_buffers->shapeFlags.buffer, |
|
|
int(g_buffers->shapeFlags.size())); |
|
|
|
|
|
g_shapesChanged = false; |
|
|
} |
|
|
|
|
|
if (!g_pause || g_step) { |
|
|
|
|
|
NvFlexSetParams(g_solver, &g_params); |
|
|
NvFlexUpdateSolver(g_solver, g_dt, g_numSubsteps, g_profile); |
|
|
|
|
|
g_frame++; |
|
|
g_step = false; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NvFlexGetParticles(g_solver, g_buffers->positions.buffer, nullptr); |
|
|
NvFlexGetVelocities(g_solver, g_buffers->velocities.buffer, nullptr); |
|
|
NvFlexGetNormals(g_solver, g_buffers->normals.buffer, nullptr); |
|
|
|
|
|
|
|
|
if (g_buffers->triangles.size()) |
|
|
NvFlexGetDynamicTriangles(g_solver, g_buffers->triangles.buffer, g_buffers->triangleNormals.buffer, |
|
|
g_buffers->triangles.size() / 3); |
|
|
|
|
|
|
|
|
if (g_buffers->rigidOffsets.size()) |
|
|
NvFlexGetRigids(g_solver, g_buffers->rigidOffsets.buffer, g_buffers->rigidIndices.buffer, |
|
|
g_buffers->rigidLocalPositions.buffer, nullptr, nullptr, nullptr, nullptr, |
|
|
g_buffers->rigidRotations.buffer, g_buffers->rigidTranslations.buffer); |
|
|
|
|
|
if (!g_interop && g_render) { |
|
|
|
|
|
if (g_drawEllipsoids) { |
|
|
NvFlexGetSmoothParticles(g_solver, g_buffers->smoothPositions.buffer, nullptr); |
|
|
NvFlexGetAnisotropy(g_solver, g_buffers->anisotropy1.buffer, g_buffers->anisotropy2.buffer, |
|
|
g_buffers->anisotropy3.buffer, NULL); |
|
|
} |
|
|
|
|
|
|
|
|
if (g_drawDensity) |
|
|
NvFlexGetDensities(g_solver, g_buffers->densities.buffer, nullptr); |
|
|
|
|
|
if (GetNumDiffuseRenderParticles(g_diffuseRenderBuffers)) { |
|
|
NvFlexGetDiffuseParticles(g_solver, g_buffers->diffusePositions.buffer, g_buffers->diffuseVelocities.buffer, |
|
|
g_buffers->diffuseCount.buffer); |
|
|
} |
|
|
} else if (g_render) { |
|
|
|
|
|
NvFlexGetDiffuseParticles(g_solver, nullptr, nullptr, g_buffers->diffuseCount.buffer); |
|
|
} |
|
|
|
|
|
double updateEndTime = GetSeconds(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto newUpdateTime = float(updateEndTime - updateBeginTime); |
|
|
auto newRenderTime = float(renderEndTime - renderBeginTime); |
|
|
auto newWaitTime = float(waitBeginTime - waitEndTime); |
|
|
|
|
|
|
|
|
const float timerSmoothing = 0.05f; |
|
|
|
|
|
g_updateTime = (g_updateTime == 0.0f) ? newUpdateTime : Lerp(g_updateTime, newUpdateTime, timerSmoothing); |
|
|
g_renderTime = (g_renderTime == 0.0f) ? newRenderTime : Lerp(g_renderTime, newRenderTime, timerSmoothing); |
|
|
g_waitTime = (g_waitTime == 0.0f) ? newWaitTime : Lerp(g_waitTime, newWaitTime, timerSmoothing); |
|
|
g_simLatency = (g_simLatency == 0.0f) ? newSimLatency : Lerp(g_simLatency, newSimLatency, timerSmoothing); |
|
|
|
|
|
if (g_benchmark) newScene = BenchmarkUpdate(); |
|
|
|
|
|
|
|
|
|
|
|
if (!g_headless) |
|
|
{ |
|
|
PresentFrame(g_vsync); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (newScene != -1) { |
|
|
g_scene = newScene; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
void ReshapeWindow(int width, int height) { |
|
|
if (!g_benchmark) |
|
|
printf("Reshaping\n"); |
|
|
|
|
|
ReshapeRender(g_window); |
|
|
|
|
|
if (!g_fluidRenderer || (width != g_screenWidth || height != g_screenHeight)) { |
|
|
if (g_fluidRenderer) |
|
|
DestroyFluidRenderer(g_fluidRenderer); |
|
|
g_fluidRenderer = CreateFluidRenderer(width, height); |
|
|
} |
|
|
|
|
|
g_screenWidth = width; |
|
|
g_screenHeight = height; |
|
|
} |
|
|
|
|
|
void InputArrowKeysDown(int key, int x, int y) { |
|
|
switch (key) { |
|
|
case SDLK_DOWN: { |
|
|
if (g_selectedScene < int(g_scenes.size()) - 1) |
|
|
g_selectedScene++; |
|
|
|
|
|
|
|
|
g_levelScroll = max((g_selectedScene - 4) * 24, 0); |
|
|
break; |
|
|
} |
|
|
case SDLK_UP: { |
|
|
if (g_selectedScene > 0) |
|
|
g_selectedScene--; |
|
|
|
|
|
|
|
|
g_levelScroll = max((g_selectedScene - 4) * 24, 0); |
|
|
break; |
|
|
} |
|
|
case SDLK_LEFT: { |
|
|
if (g_scene > 0) |
|
|
--g_scene; |
|
|
|
|
|
|
|
|
|
|
|
g_levelScroll = max((g_scene - 4) * 24, 0); |
|
|
break; |
|
|
} |
|
|
case SDLK_RIGHT: { |
|
|
if (g_scene < int(g_scenes.size()) - 1) |
|
|
++g_scene; |
|
|
|
|
|
|
|
|
|
|
|
g_levelScroll = max((g_scene - 4) * 24, 0); |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
void InputArrowKeysUp(int key, int x, int y) { |
|
|
} |
|
|
|
|
|
bool InputKeyboardDown(unsigned char key, int x, int y) { |
|
|
if (key > '0' && key <= '9') { |
|
|
g_scene = key - '0' - 1; |
|
|
|
|
|
return false; |
|
|
} |
|
|
|
|
|
float kSpeed = g_camSpeed; |
|
|
|
|
|
switch (key) { |
|
|
case 'w': { |
|
|
g_camVel.z = kSpeed; |
|
|
break; |
|
|
} |
|
|
case 's': { |
|
|
g_camVel.z = -kSpeed; |
|
|
break; |
|
|
} |
|
|
case 'a': { |
|
|
g_camVel.x = -kSpeed; |
|
|
break; |
|
|
} |
|
|
case 'd': { |
|
|
g_camVel.x = kSpeed; |
|
|
break; |
|
|
} |
|
|
case 'q': { |
|
|
g_camVel.y = kSpeed; |
|
|
break; |
|
|
} |
|
|
case 'z': { |
|
|
|
|
|
g_camVel.y = -kSpeed; |
|
|
break; |
|
|
} |
|
|
case 'r': { |
|
|
g_resetScene = true; |
|
|
break; |
|
|
} |
|
|
case 'y': { |
|
|
g_wavePool = !g_wavePool; |
|
|
break; |
|
|
} |
|
|
case 'p': { |
|
|
g_pause = !g_pause; |
|
|
break; |
|
|
} |
|
|
case 'o': { |
|
|
g_step = true; |
|
|
break; |
|
|
} |
|
|
case 'h': { |
|
|
g_showHelp = !g_showHelp; |
|
|
break; |
|
|
} |
|
|
case 'e': { |
|
|
g_drawEllipsoids = !g_drawEllipsoids; |
|
|
break; |
|
|
} |
|
|
case 't': { |
|
|
g_drawOpaque = !g_drawOpaque; |
|
|
break; |
|
|
} |
|
|
case 'v': { |
|
|
g_drawPoints = !g_drawPoints; |
|
|
break; |
|
|
} |
|
|
case 'f': { |
|
|
g_drawSprings = (g_drawSprings + 1) % 3; |
|
|
break; |
|
|
} |
|
|
case 'i': { |
|
|
g_drawDiffuse = !g_drawDiffuse; |
|
|
break; |
|
|
} |
|
|
case 'm': { |
|
|
g_drawMesh = !g_drawMesh; |
|
|
break; |
|
|
} |
|
|
case 'n': { |
|
|
g_drawRopes = !g_drawRopes; |
|
|
break; |
|
|
} |
|
|
case 'j': { |
|
|
g_windTime = 0.0f; |
|
|
g_windStrength = 1.5f; |
|
|
g_windFrequency = 0.2f; |
|
|
break; |
|
|
} |
|
|
case '.': { |
|
|
g_profile = !g_profile; |
|
|
break; |
|
|
} |
|
|
case 'g': { |
|
|
if (g_params.gravity[1] != 0.0f) |
|
|
g_params.gravity[1] = 0.0f; |
|
|
else |
|
|
g_params.gravity[1] = -9.8f; |
|
|
|
|
|
break; |
|
|
} |
|
|
case '-': { |
|
|
if (g_params.numPlanes) |
|
|
g_params.numPlanes--; |
|
|
|
|
|
break; |
|
|
} |
|
|
case ' ': { |
|
|
g_emit = !g_emit; |
|
|
break; |
|
|
} |
|
|
case ';': { |
|
|
g_debug = !g_debug; |
|
|
break; |
|
|
} |
|
|
case 13: { |
|
|
g_scene = g_selectedScene; |
|
|
|
|
|
break; |
|
|
} |
|
|
case 27: { |
|
|
|
|
|
return true; |
|
|
} |
|
|
}; |
|
|
|
|
|
g_scenes[g_scene]->KeyDown(key); |
|
|
|
|
|
return false; |
|
|
} |
|
|
|
|
|
void InputKeyboardUp(unsigned char key, int x, int y) { |
|
|
switch (key) { |
|
|
case 'w': |
|
|
case 's': { |
|
|
g_camVel.z = 0.0f; |
|
|
break; |
|
|
} |
|
|
case 'a': |
|
|
case 'd': { |
|
|
g_camVel.x = 0.0f; |
|
|
break; |
|
|
} |
|
|
case 'q': |
|
|
case 'z': { |
|
|
g_camVel.y = 0.0f; |
|
|
break; |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
void MouseFunc(int b, int state, int x, int y) { |
|
|
switch (state) { |
|
|
case SDL_RELEASED: { |
|
|
g_lastx = x; |
|
|
g_lasty = y; |
|
|
g_lastb = -1; |
|
|
|
|
|
break; |
|
|
} |
|
|
case SDL_PRESSED: { |
|
|
g_lastx = x; |
|
|
g_lasty = y; |
|
|
g_lastb = b; |
|
|
if ((SDL_GetModState() & KMOD_LSHIFT) && g_lastb == SDL_BUTTON_LEFT) { |
|
|
|
|
|
g_mousePicked = true; |
|
|
} |
|
|
break; |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
void MousePassiveMotionFunc(int x, int y) { |
|
|
g_lastx = x; |
|
|
g_lasty = y; |
|
|
} |
|
|
|
|
|
void MouseMotionFunc(unsigned state, int x, int y) { |
|
|
auto dx = float(x - g_lastx); |
|
|
auto dy = float(y - g_lasty); |
|
|
|
|
|
g_lastx = x; |
|
|
g_lasty = y; |
|
|
|
|
|
if (state & SDL_BUTTON_RMASK) { |
|
|
const float kSensitivity = DegToRad(0.1f); |
|
|
const float kMaxDelta = FLT_MAX; |
|
|
|
|
|
g_camAngle.x -= Clamp(dx * kSensitivity, -kMaxDelta, kMaxDelta); |
|
|
g_camAngle.y -= Clamp(dy * kSensitivity, -kMaxDelta, kMaxDelta); |
|
|
} |
|
|
} |
|
|
|
|
|
bool g_Error = false; |
|
|
|
|
|
void ErrorCallback(NvFlexErrorSeverity severity, const char *msg, const char *file, int line) { |
|
|
printf("Flex: %s - %s:%d\n", msg, file, line); |
|
|
g_Error = (severity == eNvFlexLogError); |
|
|
|
|
|
} |
|
|
|
|
|
void ControllerButtonEvent(SDL_ControllerButtonEvent event) { |
|
|
|
|
|
if (event.type == SDL_CONTROLLERBUTTONDOWN) { |
|
|
InputKeyboardDown(GetKeyFromGameControllerButton(SDL_GameControllerButton(event.button)), 0, 0); |
|
|
InputArrowKeysDown(GetKeyFromGameControllerButton(SDL_GameControllerButton(event.button)), 0, 0); |
|
|
|
|
|
if (event.button == SDL_CONTROLLER_BUTTON_LEFT_TRIGGER) { |
|
|
|
|
|
g_lastx = g_screenWidth / 2; |
|
|
g_lasty = g_screenHeight / 2; |
|
|
g_lastb = 1; |
|
|
|
|
|
|
|
|
g_mousePicked = true; |
|
|
} |
|
|
} else { |
|
|
InputKeyboardUp(GetKeyFromGameControllerButton(SDL_GameControllerButton(event.button)), 0, 0); |
|
|
InputArrowKeysUp(GetKeyFromGameControllerButton(SDL_GameControllerButton(event.button)), 0, 0); |
|
|
|
|
|
if (event.button == SDL_CONTROLLER_BUTTON_LEFT_TRIGGER) { |
|
|
|
|
|
g_lastx = g_screenWidth / 2; |
|
|
g_lasty = g_screenHeight / 2; |
|
|
g_lastb = -1; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
void ControllerDeviceUpdate() { |
|
|
if (SDL_NumJoysticks() > 0) { |
|
|
SDL_JoystickEventState(SDL_ENABLE); |
|
|
if (SDL_IsGameController(0)) { |
|
|
g_gamecontroller = SDL_GameControllerOpen(0); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
void SDLInit(const char *title) { |
|
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < |
|
|
0) |
|
|
printf("Unable to initialize SDL"); |
|
|
|
|
|
unsigned int flags = SDL_WINDOW_RESIZABLE; |
|
|
|
|
|
if (g_graphics == 0) { |
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
|
|
flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL; |
|
|
} |
|
|
|
|
|
g_window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, |
|
|
g_screenWidth, g_screenHeight, flags); |
|
|
|
|
|
g_windowId = SDL_GetWindowID(g_window); |
|
|
} |
|
|
|
|
|
|