From b79146c7fa2f4b0af85e6b1daac79b38512d451d Mon Sep 17 00:00:00 2001 From: erwin coumans Date: Tue, 3 Sep 2013 15:09:12 -0700 Subject: [PATCH] add simple place holder for cloth simulation --- .../CpuDemos/deformable/CpuSoftBodyDemo.cpp | 259 +++++++++++++++--- Demos3/CpuDemos/deformable/CpuSoftBodyDemo.h | 12 +- .../deformable/CpuSoftBodyDemoInternalData.h | 6 +- .../deformable/CpuSoftClothDemoInternalData.h | 31 +++ Demos3/CpuDemos/main_opengl3core.cpp | 2 +- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 7 +- 6 files changed, 271 insertions(+), 46 deletions(-) create mode 100644 Demos3/CpuDemos/deformable/CpuSoftClothDemoInternalData.h diff --git a/Demos3/CpuDemos/deformable/CpuSoftBodyDemo.cpp b/Demos3/CpuDemos/deformable/CpuSoftBodyDemo.cpp index b2c8da65f..a45e07f8c 100644 --- a/Demos3/CpuDemos/deformable/CpuSoftBodyDemo.cpp +++ b/Demos3/CpuDemos/deformable/CpuSoftBodyDemo.cpp @@ -12,12 +12,18 @@ #include "CpuSoftBodyDemoInternalData.h" #include "Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h" #include "stb_image/stb_image.h" +#include "CpuSoftClothDemoInternalData.h" static b3KeyboardCallback oldCallback = 0; extern bool gReset; +float clothWidth = 4; +float clothHeight= 4; - +int width = 64; +int height = 64; +int numPoints = width*height; +float clothMass = 100.f; @@ -92,6 +98,7 @@ void CpuSoftBodyDemo::exitPhysics() } +#include "Bullet3Common/shared/b3Float4.h" struct GraphicsVertex { @@ -100,44 +107,93 @@ struct GraphicsVertex float texcoord[2]; }; -void CpuSoftClothDemo::renderScene() +void CpuSoftClothDemo::computeForces() { - if (m_data->m_clothShapeIndex>=0 && m_data->m_clothVertices) + B3_PROFILE("computeForces"); + + b3Vector3 gravityAcceleration = b3MakeVector3(0,-9.8,0); + //f=m*a + for (int i=0;im_clothVertices; - int width = 256; - int height=256; - static float shift = 0.f; - shift+=0.01; - if (shift>B3_2_PI) - shift-=B3_2_PI; - - int numVertices = 0; - // Initial test data for rendering - for(int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) + float particleMass = m_clothData->m_particleMasses[i]; + + b3Vector3 particleMassVec = b3MakeVector3(particleMass,particleMass,particleMass,0); + m_clothData->m_forces[i] = gravityAcceleration*particleMass; + } + } + + GraphicsVertex* cpu_buffer = (GraphicsVertex*)m_data->m_clothVertices; + + + //add spring forces + for(int i=0;im_springs.size();i++) + { + + int indexA = m_clothData->m_springs[i].m_particleIndexA; + int indexB = m_clothData->m_springs[i].m_particleIndexB; + float restLength = m_clothData->m_springs[i].m_restLength; + const ClothMaterial& mat = m_clothData->m_materials[m_clothData->m_springs[i].m_material]; + + const b3Vector3& posA = (const b3Vector3&)cpu_buffer[indexA].pos; + const b3Vector3& posB = (const b3Vector3&)cpu_buffer[indexB].pos; + const b3Vector3& velA = m_clothData->m_velocities[indexA]; + const b3Vector3& velB = m_clothData->m_velocities[indexB]; + + b3Vector3 deltaP = posA-posB; + b3Vector3 deltaV = velA-velB; + float dist = deltaP.length(); + b3Vector3 deltaPNormalized = deltaP/dist; + + float spring = -mat.m_stiffness * (dist-restLength)*100000; + float damper = mat.m_damping * b3Dot(deltaV,deltaPNormalized)*100; + + b3Vector3 springForce = (spring+damper)*deltaPNormalized; + float particleMassA = m_clothData->m_particleMasses[indexA]; + float particleMassB = m_clothData->m_particleMasses[indexB]; + + //if (springForce.length()) + { + if (particleMassA) { - - double coord = b3Sin(x/5.0+shift)*0.01; - //coord = sin(y/); + m_clothData->m_forces[indexA] += springForce*particleMassA; + } - cpu_buffer[y*width+x].pos[0] = (x/((float)(width-1)))*1; - cpu_buffer[y*width+x].pos[1] = coord; - cpu_buffer[y*width+x].pos[2] = (y/((float)(height-1)))*1; - cpu_buffer[y*width+x].pos[3] = 0.f; - - cpu_buffer[y*width+x].normal[0] = 1; - cpu_buffer[y*width+x].normal[1] = 0; - cpu_buffer[y*width+x].normal[2] = 0; - cpu_buffer[y*width+x].texcoord[0] = 1*x/((float)(width-1)); - cpu_buffer[y*width+x].texcoord[1] = (1.f-4*y/((float)(height-1))); - numVertices++; + if (particleMassB) + { + m_clothData->m_forces[indexB] -= springForce*particleMassB; } } - - m_instancingRenderer->updateShape(m_data->m_clothShapeIndex,m_data->m_clothVertices); } +} + +void CpuSoftClothDemo::integrateEuler(float deltaTime) +{ + B3_PROFILE("integrateEuler"); + b3Vector3 deltaTimeVec = b3MakeVector3(deltaTime,deltaTime,deltaTime,0); + + GraphicsVertex* cpu_buffer = (GraphicsVertex*)m_data->m_clothVertices; + + for (int i=0;im_particleMasses[i]; + if (mass) + { + + + + b3Vector3 dv = (m_clothData->m_forces[i]/mass)*deltaTimeVec; + m_clothData->m_velocities[i]+= dv; + m_clothData->m_velocities[i]*=0.999; + + b3Vector3& pos = (b3Vector3&) cpu_buffer[i].pos; + pos += m_clothData->m_velocities[i]*deltaTimeVec; + } + } +} + +void CpuSoftClothDemo::renderScene() +{ m_instancingRenderer->renderScene(); } @@ -150,14 +206,37 @@ void CpuSoftBodyDemo::clientMoveAndDisplay() { GLint err = glGetError(); b3Assert(err==GL_NO_ERROR); + + + } +void CpuSoftClothDemo::clientMoveAndDisplay() +{ + if (m_data->m_clothShapeIndex>=0 && m_data->m_clothVertices) + { + + float deltaTime = 1./1000.;//1./60.f; + //float deltaTime = 1./60.f; + for (int i=0;i<10;i++) + { + computeForces(); + integrateEuler(deltaTime); + + } + m_instancingRenderer->updateShape(m_data->m_clothShapeIndex,m_data->m_clothVertices); + } +} + CpuSoftClothDemo::CpuSoftClothDemo() { + m_clothData = new CpuSoftClothDemoInternalData(); + } CpuSoftClothDemo::~CpuSoftClothDemo() { + delete m_clothData; } @@ -212,8 +291,6 @@ void CpuSoftClothDemo::setupScene(const ConstructionInfo& ci) b3Assert(err==GL_NO_ERROR); - int width = 256; - int height = 256; GraphicsVertex* cpu_buffer = new GraphicsVertex[width*height]; memset(cpu_buffer, 0, width*height*sizeof(GraphicsVertex)); @@ -225,12 +302,15 @@ void CpuSoftClothDemo::setupScene(const ConstructionInfo& ci) { for(int x = 0; x < width; x++) { - double coord = b3Sin(x/5.0);//*0.01; + double coord = b3Sin(x/5.0)*0.01+1; //coord = sin(y/); - cpu_buffer[y*width+x].pos[0] = (x/((float)(width-1)))*1; + float posX = (x/((float)(width-1)))*(clothWidth); + float posZ = ((y-height/2.f)/((float)(height-1)))*(clothHeight); + + cpu_buffer[y*width+x].pos[0] = posX; cpu_buffer[y*width+x].pos[1] = coord; - cpu_buffer[y*width+x].pos[2] = (y/((float)(height-1)))*1; + cpu_buffer[y*width+x].pos[2] = posZ; cpu_buffer[y*width+x].pos[3] = 0.f; cpu_buffer[y*width+x].normal[0] = 1; @@ -264,7 +344,8 @@ void CpuSoftClothDemo::setupScene(const ConstructionInfo& ci) indices[baseIndex+3] = x + 1 + y*width; indices[baseIndex+4] = x+(width+1) + y*width; indices[baseIndex+5] = x+width + y*width; - numIndices++; + numIndices+=6; + } } @@ -316,10 +397,112 @@ void CpuSoftClothDemo::setupScene(const ConstructionInfo& ci) float scaling[4] = {10,10,10,1}; ci.m_instancingRenderer->registerGraphicsInstance(shapeIndex,pos,orn,color,scaling); - ci.m_instancingRenderer->setCameraDistance(4); + ci.m_instancingRenderer->setCameraDistance(24); ci.m_instancingRenderer->setCameraTargetPosition(pos); err = glGetError(); b3Assert(err==GL_NO_ERROR); + + int numParticles = width*height; + + m_clothData->m_forces.resize(numParticles); + m_clothData->m_velocities.resize(numParticles); + m_clothData->m_particleMasses.resize(numParticles); + + + + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + float mass = clothMass/numParticles; + if (x==0 && y==(height-1)) + mass=0.f; + if (x==0 && y==0) + mass=0.f; + int index = x+width*y; + + m_clothData->m_particleMasses[index] = mass; + } + } + + + ClothMaterial mat; + mat.m_stiffness = 0.5; + mat.m_damping = -0.25; + + m_clothData->m_materials.push_back(mat); + + + //add springs + for (int x=0;xm_springs.push_back(spring); + + } + } + + for (int x=0;xm_springs.push_back(spring); + } + } + + for (int x=0;xm_springs.push_back(spring); + } + + { + ClothSpring spring; + int indexA = x+1+y*width; + int indexB = (x)+(y+1)*width; + spring.m_particleIndexA = indexA; + spring.m_particleIndexB = indexB; + spring.m_material = 0; + const b3Vector3& posA = (const b3Vector3&) cpu_buffer[indexA].pos; + const b3Vector3& posB = (const b3Vector3&) cpu_buffer[indexB].pos; + spring.m_restLength = (posA-posB).length(); + m_clothData->m_springs.push_back(spring); + } + + } + } + + } \ No newline at end of file diff --git a/Demos3/CpuDemos/deformable/CpuSoftBodyDemo.h b/Demos3/CpuDemos/deformable/CpuSoftBodyDemo.h index 0bdf2b428..a6dea2376 100644 --- a/Demos3/CpuDemos/deformable/CpuSoftBodyDemo.h +++ b/Demos3/CpuDemos/deformable/CpuSoftBodyDemo.h @@ -36,6 +36,8 @@ public: virtual void renderScene(); + + virtual void clientMoveAndDisplay(); @@ -43,8 +45,11 @@ public: class CpuSoftClothDemo : public CpuSoftBodyDemo { +protected: - public: + struct CpuSoftClothDemoInternalData* m_clothData; + +public: CpuSoftClothDemo(); virtual ~CpuSoftClothDemo(); @@ -59,6 +64,11 @@ class CpuSoftClothDemo : public CpuSoftBodyDemo return "CpuSoftCloth"; } + void computeForces(); + void integrateEuler(float deltaTime); + + virtual void clientMoveAndDisplay(); + static CpuDemo* MyCreateFunc() { CpuDemo* demo = new CpuSoftClothDemo; diff --git a/Demos3/CpuDemos/deformable/CpuSoftBodyDemoInternalData.h b/Demos3/CpuDemos/deformable/CpuSoftBodyDemoInternalData.h index f15e6b4ef..a3ac757a0 100644 --- a/Demos3/CpuDemos/deformable/CpuSoftBodyDemoInternalData.h +++ b/Demos3/CpuDemos/deformable/CpuSoftBodyDemoInternalData.h @@ -1,5 +1,5 @@ -#ifndef GPU_SOFTBODY_INTERNAL_DATA_H -#define GPU_SOFTBODY_INTERNAL_DATA_H +#ifndef CPU_SOFTBODY_INTERNAL_DATA_H +#define CPU_SOFTBODY_INTERNAL_DATA_H //#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" @@ -17,5 +17,5 @@ struct CpuSoftBodyDemoInternalData } }; -#endif//GPU_SOFTBODY_INTERNAL_DATA_H +#endif//CPU_SOFTBODY_INTERNAL_DATA_H diff --git a/Demos3/CpuDemos/deformable/CpuSoftClothDemoInternalData.h b/Demos3/CpuDemos/deformable/CpuSoftClothDemoInternalData.h new file mode 100644 index 000000000..851b92280 --- /dev/null +++ b/Demos3/CpuDemos/deformable/CpuSoftClothDemoInternalData.h @@ -0,0 +1,31 @@ +#ifndef CPU_SOFTCLOTH_INTERNAL_DATA_H +#define CPU_SOFTCLOTH_INTERNAL_DATA_H + +#include "Bullet3Common/b3AlignedObjectArray.h" + +struct ClothSpring +{ + int m_particleIndexA; + int m_particleIndexB; + float m_restLength; + int m_material; +}; + +struct ClothMaterial +{ + float m_stiffness; + float m_damping; +}; + +struct CpuSoftClothDemoInternalData +{ + b3AlignedObjectArray m_springs; + b3AlignedObjectArray m_materials; + b3AlignedObjectArray m_velocities; + b3AlignedObjectArray m_forces; + b3AlignedObjectArray m_particleMasses; + +}; + +#endif //CPU_SOFTCLOTH_INTERNAL_DATA_H + diff --git a/Demos3/CpuDemos/main_opengl3core.cpp b/Demos3/CpuDemos/main_opengl3core.cpp index 8d6af50e0..d214ead97 100644 --- a/Demos3/CpuDemos/main_opengl3core.cpp +++ b/Demos3/CpuDemos/main_opengl3core.cpp @@ -107,7 +107,7 @@ b3AlignedObjectArray demoNames; int selectedDemo = 0; CpuDemo::CreateFunc* allDemos[]= { - //CpuSoftClothDemo::MyCreateFunc, + CpuSoftClothDemo::MyCreateFunc, RigidBodyDemo::MyCreateFunc, RenderDemo::MyCreateFunc, EmptyDemo::MyCreateFunc, diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index e09a6b9fc..39d63045d 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -215,12 +215,12 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData } if (m_middleMouseButton) { - m_cameraTargetPosition += m_cameraUp * yDelta; + m_cameraTargetPosition += m_cameraUp * yDelta*0.1; b3Vector3 fwd = m_cameraTargetPosition-m_cameraPosition; b3Vector3 side = m_cameraUp.cross(fwd); side.normalize(); - m_cameraTargetPosition += side * xDelta; + m_cameraTargetPosition += side * xDelta*0.1; } if (m_rightMouseButton) @@ -1555,6 +1555,8 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) glBindTexture(GL_TEXTURE_2D, m_data->m_shadowTexture); glUniform1i(useShadow_shadowMap,1); glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); + //glDrawElementsInstanced(GL_LINE_LOOP, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); + break; } default: @@ -1565,7 +1567,6 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) } - //glDrawElementsInstanced(GL_LINE_LOOP, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); } } curOffset+= gfxObj->m_numGraphicsInstances;