/* * Copyright 1993-2007 NVIDIA Corporation. All rights reserved. * * NOTICE TO USER: * * This source code is subject to NVIDIA ownership rights under U.S. and * international Copyright laws. * * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE * OR PERFORMANCE OF THIS SOURCE CODE. * * U.S. Government End Users. This source code is a "commercial item" as * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of * "commercial computer software" and "commercial computer software * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) * and is provided to the U.S. Government only as a commercial end item. * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the * source code with only those rights set forth herein. */ /* Particle system example with collisions using uniform grid */ #include #include #include #include //#include #include #if defined(__APPLE__) || defined(MACOSX) #include #else #include #endif #include "LinearMath/btQuickprof.h" #include "particleSystem.h" #include "render_particles.h" #include "paramgl.h" // view params int ox, oy; int buttonState = 0; float camera_trans[] = {0, 0, -3}; float camera_rot[] = {0, 0, 0}; float camera_trans_lag[] = {0, 0, -3}; float camera_rot_lag[] = {0, 0, 0}; const float inertia = 0.1; ParticleRenderer::DisplayMode displayMode = ParticleRenderer::PARTICLE_SPHERES; int mode = 0; bool displayEnabled = true; bool bPause = false; bool displaySliders = false; bool wireframe = false; enum { M_VIEW = 0, M_MOVE }; uint numParticles = 0; uint3 gridSize; int numIterations = 0; // run until exit // simulation parameters float timestep = 0.5f; float damping = 1.0f; float gravity = 0.0003f; int iterations = 1; int ballr = 10; float collideSpring = 0.5f;; float collideDamping = 0.02f;; float collideShear = 0.1f; float collideAttraction = 0.0f; ParticleSystem *psystem = 0; // fps static int fpsCount = 0; static int fpsLimit = 1; unsigned int timer; ParticleRenderer *renderer = 0; float modelView[16]; ParamListGL *params; extern "C" void cudaInit(int argc, char **argv); void init(int numParticles, uint3 gridSize) { psystem = new ParticleSystem(numParticles, gridSize); psystem->reset(ParticleSystem::CONFIG_GRID); renderer = new ParticleRenderer; renderer->setParticleRadius(psystem->getParticleRadius()); renderer->setColorBuffer(psystem->getColorBuffer()); // CUT_SAFE_CALL(cutCreateTimer(&timer)); } void initGL() { glewInit(); if (!glewIsSupported("GL_VERSION_2_0 GL_VERSION_1_5 GL_ARB_multitexture GL_ARB_vertex_buffer_object")) { fprintf(stderr, "Required OpenGL extensions missing."); exit(-1); } glEnable(GL_DEPTH_TEST); glClearColor(0.25, 0.25, 0.25, 1.0); glutReportErrors(); } void display() { // update the simulation if (!bPause) { psystem->setIterations(iterations); psystem->setDamping(damping); psystem->setGravity(-gravity); psystem->setCollideSpring(collideSpring); psystem->setCollideDamping(collideDamping); psystem->setCollideShear(collideShear); psystem->setCollideAttraction(collideAttraction); psystem->update(timestep); renderer->setVertexBuffer(psystem->getCurrentReadBuffer(), psystem->getNumParticles()); } // render glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // view transform glMatrixMode(GL_MODELVIEW); glLoadIdentity(); for (int c = 0; c < 3; ++c) { camera_trans_lag[c] += (camera_trans[c] - camera_trans_lag[c]) * inertia; camera_rot_lag[c] += (camera_rot[c] - camera_rot_lag[c]) * inertia; } glTranslatef(camera_trans_lag[0], camera_trans_lag[1], camera_trans_lag[2]); glRotatef(camera_rot_lag[0], 1.0, 0.0, 0.0); glRotatef(camera_rot_lag[1], 0.0, 1.0, 0.0); glGetFloatv(GL_MODELVIEW_MATRIX, modelView); // cube glColor3f(1.0, 1.0, 1.0); glutWireCube(2.0); // collider glPushMatrix(); float4 p = psystem->getColliderPos(); glTranslatef(p.x, p.y, p.z); glColor3f(1.0, 0.0, 0.0); glutSolidSphere(psystem->getColliderRadius(), 20, 10); glPopMatrix(); if (displayEnabled) { renderer->display(displayMode); } if (displaySliders) { glDisable(GL_DEPTH_TEST); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); // invert color glEnable(GL_BLEND); params->Render(0, 0); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); } psystem->debugDraw(); glDisable(GL_DEPTH_TEST); float offsX = 10.f; float offsY = 10.f; renderer->showProfileInfo(offsX, offsY, 20.f); glEnable(GL_DEPTH_TEST); glutSwapBuffers(); { char fps[256]; //float ifps = 1.f / (cutGetAverageTimerValue(timer) / 1000.f); switch (psystem->getSimulationMode()) { case ParticleSystem::SIMULATION_CUDA: { sprintf(fps, "CUDA particles (%d particles)", numParticles); break; } case ParticleSystem::SIMULATION_BULLET_CPU: { sprintf(fps, "Bullet btCudaBroadphase (%d btSphereShapes)", numParticles); break; } default: { sprintf(fps, "Unknown simulation mode"); } } glutSetWindowTitle(fps); } glutReportErrors(); } void reshape(int w, int h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (float) w / (float) h, 0.1, 10.0); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, w, h); renderer->setWindowSize(w, h); renderer->setFOV(60.0); } void mouse(int button, int state, int x, int y) { int mods; if (state == GLUT_DOWN) buttonState |= 1<Mouse(x, y, button, state)) { glutPostRedisplay(); return; } } glutPostRedisplay(); } // transfrom vector by matrix void xform(float *v, float *r, GLfloat *m) { r[0] = v[0]*m[0] + v[1]*m[4] + v[2]*m[8] + m[12]; r[1] = v[0]*m[1] + v[1]*m[5] + v[2]*m[9] + m[13]; r[2] = v[0]*m[2] + v[1]*m[6] + v[2]*m[10] + m[14]; } // transform vector by transpose of matrix void ixform(float *v, float *r, GLfloat *m) { r[0] = v[0]*m[0] + v[1]*m[1] + v[2]*m[2]; r[1] = v[0]*m[4] + v[1]*m[5] + v[2]*m[6]; r[2] = v[0]*m[8] + v[1]*m[9] + v[2]*m[10]; } void ixformPoint(float *v, float *r, GLfloat *m) { float x[4]; x[0] = v[0] - m[12]; x[1] = v[1] - m[13]; x[2] = v[2] - m[14]; x[3] = 1.0f; ixform(x, r, m); } void motion(int x, int y) { float dx, dy; dx = x - ox; dy = y - oy; if (displaySliders) { if (params->Motion(x, y)) { ox = x; oy = y; glutPostRedisplay(); return; } } switch(mode) { case M_VIEW: if (buttonState == 3) { // left+middle = zoom camera_trans[2] += (dy / 100.0) * 0.5 * fabs(camera_trans[2]); } else if (buttonState & 2) { // middle = translate camera_trans[0] += dx / 100.0; camera_trans[1] -= dy / 100.0; } else if (buttonState & 1) { // left = rotate camera_rot[0] += dy / 5.0; camera_rot[1] += dx / 5.0; } break; case M_MOVE: { float translateSpeed = 0.003f; float4 p = psystem->getColliderPos(); if (buttonState==1) { float v[3], r[3]; v[0] = dx*translateSpeed; v[1] = -dy*translateSpeed; v[2] = 0.0f; ixform(v, r, modelView); p.x += r[0]; p.y += r[1]; p.z += r[2]; } else if (buttonState==2) { float v[3], r[3]; v[0] = 0.0f; v[1] = 0.0f; v[2] = dy*translateSpeed; ixform(v, r, modelView); p.x += r[0]; p.y += r[1]; p.z += r[2]; } psystem->setColliderPos(p); } break; } ox = x; oy = y; glutPostRedisplay(); } inline float frand() { return rand() / (float) RAND_MAX; } // commented out to remove unused parameter warnings in Linux void key(unsigned char key, int /*x*/, int /*y*/) { #ifndef BT_NO_PROFILE if (key >= 0x31 && key < 0x37) { int child = key-0x31; renderer->m_profileIterator->Enter_Child(child); } if (key==0x30) { renderer->m_profileIterator->Enter_Parent(); } #endif //BT_NO_PROFILE switch (key) { case ' ': bPause = !bPause; break; case 13: psystem->update(timestep); renderer->setVertexBuffer(psystem->getCurrentReadBuffer(), psystem->getNumParticles()); break; case '\033': case 'q': exit(0); break; case 'v': mode = M_VIEW; break; case 'm': mode = M_MOVE; break; case 'p': displayMode = (ParticleRenderer::DisplayMode) ((displayMode + 1) % ParticleRenderer::PARTICLE_NUM_MODES); break; case 'd': psystem->dumpGrid(); break; case 'u': psystem->dumpParticles(0, 1); break; case 'r': displayEnabled = !displayEnabled; break; case 'g': psystem->reset(ParticleSystem::CONFIG_GRID); break; case 'a': psystem->reset(ParticleSystem::CONFIG_RANDOM); break; case 'e': { // inject a sphere of particles float pr = psystem->getParticleRadius(); float tr = pr+(pr*2.0f)*ballr; float pos[4], vel[4]; pos[0] = -1.0 + tr + frand()*(2.0f - tr*2.0f); pos[1] = 1.0f - tr; pos[2] = -1.0 + tr + frand()*(2.0f - tr*2.0f); pos[3] = 0.0f; vel[0] = vel[1] = vel[2] = vel[3] = 0.0f; psystem->addSphere(0, pos, vel, ballr, pr*2.0f); } break; case 'b': { // shoot ball from camera float pr = psystem->getParticleRadius(); float vel[4], velw[4], pos[4], posw[4]; vel[0] = 0.0f; vel[1] = 0.0f; vel[2] = -0.05f; vel[3] = 0.0f; ixform(vel, velw, modelView); pos[0] = 0.0f; pos[1] = 0.0f; pos[2] = -2.5f; pos[3] = 1.0; ixformPoint(pos, posw, modelView); posw[3] = 0.0f; psystem->addSphere(0, posw, velw, ballr, pr*2.0f); } break; case 'w': wireframe = !wireframe; break; case 'h': displaySliders = !displaySliders; break; case 's': psystem->setSimulationMode((ParticleSystem::SimulationMode) ((psystem->getSimulationMode() + 1) % ParticleSystem::SIMULATION_NUM_MODES)); CProfileManager::CleanupMemory(); break; } glutPostRedisplay(); } void special(int k, int x, int y) { if (displaySliders) { params->Special(k, x, y); } } void idle(void) { glutPostRedisplay(); } void initParams() { // create a new parameter list params = new ParamListGL("misc"); params->AddParam(new Param("time step", timestep, 0.0, 1.0, 0.01, ×tep)); params->AddParam(new Param("iterations", iterations, 0, 10, 1, &iterations)); params->AddParam(new Param("damping", damping, 0.0, 1.0, 0.001, &damping)); params->AddParam(new Param("gravity", gravity, 0.0, 0.001, 0.0001, &gravity)); params->AddParam(new Param("ball r", ballr, 1, 20, 1, &ballr)); params->AddParam(new Param("collide spring", collideSpring, 0.0, 1.0, 0.001, &collideSpring)); params->AddParam(new Param("collide damping", collideDamping, 0.0, 0.1, 0.001, &collideDamping)); params->AddParam(new Param("collide shear", collideShear, 0.0, 0.1, 0.001, &collideShear)); params->AddParam(new Param("collide attract", collideAttraction, 0.0, 0.1, 0.001, &collideAttraction)); } void mainMenu(int i) { key((unsigned char) i, 0, 0); } void initMenus() { glutCreateMenu(mainMenu); glutAddMenuEntry("Reset block [g]", 'g'); glutAddMenuEntry("Reset random [a]", 'a'); glutAddMenuEntry("Add sphere [e]", 'e'); glutAddMenuEntry("Shoot ball [b]", 'b'); glutAddMenuEntry("View mode [v]", 'v'); glutAddMenuEntry("Move cursor mode [m]", 'm'); glutAddMenuEntry("Toggle point rendering [p]", 'p'); glutAddMenuEntry("Toggle Bullet simulation[s]", 's'); glutAddMenuEntry("Toggle animation [ ]", ' '); glutAddMenuEntry("Step animation [ret]", 13); glutAddMenuEntry("Toggle sliders [h]", 'h'); glutAddMenuEntry("Quit (esc)", '\033'); glutAttachMenu(GLUT_RIGHT_BUTTON); } //////////////////////////////////////////////////////////////////////////////// // Program main //////////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { // numParticles = 65536*2; // numParticles = 65536; // numParticles = 32768; // numParticles = 8192; // numParticles = 4096; numParticles = 2048; // numParticles = 1024; // numParticles = 256; // numParticles = 32; // numParticles = 2; uint gridDim = 64; numIterations = 0; gridSize.x = gridSize.y = gridSize.z = gridDim; printf("grid: %d x %d x %d = %d cells\n", gridSize.x, gridSize.y, gridSize.z, gridSize.x*gridSize.y*gridSize.z); cudaInit(argc, argv); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); glutInitWindowSize(640, 480); glutCreateWindow("CUDA particles"); initGL(); init(numParticles, gridSize); initParams(); initMenus(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMotionFunc(motion); glutKeyboardFunc(key); glutSpecialFunc(special); glutIdleFunc(idle); glutMainLoop(); if (psystem) delete psystem; return 0; }