From 2aad8419b7dad9fd24505ddc910a29311a9e4c7a Mon Sep 17 00:00:00 2001 From: erwin coumans Date: Wed, 10 Jul 2013 00:21:23 -0700 Subject: [PATCH] add support for picking, using point 2 point constraint allow to remove constraints by unique id added tiny wavefront loader, plan to use this instead of existing slow wavefront loader --- Demos3/GpuDemos/GpuDemo.h | 8 + Demos3/GpuDemos/main_opengl3core.cpp | 22 +- .../GpuDemos/raytrace/RaytracedShadowDemo.cpp | 4 +- .../GpuDemos/rigidbody/GpuRigidBodyDemo.cpp | 180 +++++ Demos3/GpuDemos/rigidbody/GpuRigidBodyDemo.h | 5 + .../rigidbody/GpuRigidBodyDemoInternalData.h | 18 +- Demos3/Wavefront/tiny_obj_loader.cpp | 654 ++++++++++++++++++ Demos3/Wavefront/tiny_obj_loader.h | 60 ++ btgui/OpenGLWindow/GLInstancingRenderer.cpp | 9 + btgui/OpenGLWindow/GLInstancingRenderer.h | 3 +- src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp | 4 +- src/Bullet3OpenCL/Raycast/b3RaycastInfo.h | 2 +- .../RigidBody/b3GpuGenericConstraint.h | 3 +- .../RigidBody/b3GpuPgsJacobiSolver.cpp | 7 +- .../RigidBody/b3GpuPgsJacobiSolver.h | 1 + .../RigidBody/b3GpuRigidBodyPipeline.cpp | 36 +- .../RigidBody/b3GpuRigidBodyPipeline.h | 1 + .../b3GpuRigidBodyPipelineInternalData.h | 2 +- 18 files changed, 1005 insertions(+), 14 deletions(-) create mode 100644 Demos3/Wavefront/tiny_obj_loader.cpp create mode 100644 Demos3/Wavefront/tiny_obj_loader.h diff --git a/Demos3/GpuDemos/GpuDemo.h b/Demos3/GpuDemos/GpuDemo.h index 9da95daaf..9095383f6 100644 --- a/Demos3/GpuDemos/GpuDemo.h +++ b/Demos3/GpuDemos/GpuDemo.h @@ -74,6 +74,14 @@ public: struct GpuDemoInternalData* getInternalData(); + virtual bool mouseMoveCallback(float x,float y) + { + return false; + } + virtual bool mouseButtonCallback(int button, int state, float x, float y) + { + return false; + } }; #endif diff --git a/Demos3/GpuDemos/main_opengl3core.cpp b/Demos3/GpuDemos/main_opengl3core.cpp index 13eff96b6..c25f9a89e 100644 --- a/Demos3/GpuDemos/main_opengl3core.cpp +++ b/Demos3/GpuDemos/main_opengl3core.cpp @@ -187,13 +187,21 @@ void MyButtonCallback(int buttonId, int state) } } + +GpuDemo* sDemo = 0; + static void MyMouseMoveCallback( float x, float y) { if (gui) { bool handled = gui ->mouseMoveCallback(x,y); if (!handled) - b3DefaultMouseMoveCallback(x,y); + { + if (sDemo) + handled = sDemo->mouseMoveCallback(x,y); + if (!handled) + b3DefaultMouseMoveCallback(x,y); + } } } static void MyMouseButtonCallback(int button, int state, float x, float y) @@ -202,7 +210,14 @@ static void MyMouseButtonCallback(int button, int state, float x, float y) { bool handled = gui->mouseButtonCallback(button,state,x,y); if (!handled) - b3DefaultMouseButtonCallback(button,state,x,y); + { + //try picking first + if (sDemo) + handled = sDemo->mouseButtonCallback(button,state,x,y); + + if (!handled) + b3DefaultMouseButtonCallback(button,state,x,y); + } } } @@ -647,6 +662,7 @@ int main(int argc, char* argv[]) { GpuDemo* demo = allDemos[selectedDemo](); + sDemo = demo; // demo->myinit(); bool useGpu = false; @@ -919,6 +935,8 @@ int main(int argc, char* argv[]) delete ci.m_instancingRenderer; delete demo; + sDemo = 0; + if (detailsFile) { fclose(detailsFile); diff --git a/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp b/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp index f3590fbde..d30c14d9c 100644 --- a/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp +++ b/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp @@ -335,7 +335,7 @@ void GpuRaytraceScene::renderScene2() shadowRays[i].m_from = hits[i].m_hitPoint; shadowRays[i].m_to = lightPos; shadowHits[i].m_hitFraction=1.f; - shadowHits[i].m_hitResult2 = hits[i].m_hitResult0; + shadowHits[i].m_hitBody = hits[i].m_hitBody; } else { shadowRays[i].m_from.setValue(0,0,0); @@ -377,7 +377,7 @@ void GpuRaytraceScene::renderScene2() m_raytraceData->m_texels[(i)*3+1] = 128+128.f*hits[i].m_hitNormal.y; m_raytraceData->m_texels[(i)*3+2] = 128+128.f*hits[i].m_hitNormal.z; - if (hits[i].m_hitResult0==0) + if (hits[i].m_hitBody==0) { m_raytraceData->m_texels[(i)*3+0] = 255; m_raytraceData->m_texels[(i)*3+1] = 255; diff --git a/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemo.cpp b/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemo.cpp index 408aaad1e..3af00f2af 100644 --- a/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemo.cpp +++ b/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemo.cpp @@ -14,6 +14,7 @@ #include "Bullet3OpenCL/RigidBody/b3Config.h" #include "GpuRigidBodyDemoInternalData.h" #include "Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3RigidBodyCL.h" static b3KeyboardCallback oldCallback = 0; extern bool gReset; @@ -130,6 +131,7 @@ void GpuRigidBodyDemo::initPhysics(const ConstructionInfo& ci) } + m_instancingRenderer->writeTransforms(); @@ -165,6 +167,7 @@ void GpuRigidBodyDemo::clientMoveAndDisplay() { bool animate=true; int numObjects= m_data->m_rigidBodyPipeline->getNumBodies(); + //printf("numObjects=%d\n",numObjects); if (numObjects > m_instancingRenderer->getInstanceCapacity()) { static bool once = true; @@ -242,3 +245,180 @@ void GpuRigidBodyDemo::clientMoveAndDisplay() } } + +b3Vector3 GpuRigidBodyDemo::getRayTo(int x,int y) +{ + if (!m_instancingRenderer) + return b3Vector3(0,0,0); + + float top = 1.f; + float bottom = -1.f; + float nearPlane = 1.f; + float tanFov = (top-bottom)*0.5f / nearPlane; + float fov = b3Scalar(2.0) * b3Atan(tanFov); + + b3Vector3 camPos,camTarget; + m_instancingRenderer->getCameraPosition(camPos); + m_instancingRenderer->getCameraTargetPosition(camTarget); + + b3Vector3 rayFrom = camPos; + b3Vector3 rayForward = (camTarget-camPos); + rayForward.normalize(); + float farPlane = 10000.f; + rayForward*= farPlane; + + b3Vector3 rightOffset; + b3Vector3 m_cameraUp(0,1,0); + b3Vector3 vertical = m_cameraUp; + + b3Vector3 hor; + hor = rayForward.cross(vertical); + hor.normalize(); + vertical = hor.cross(rayForward); + vertical.normalize(); + + float tanfov = tanf(0.5f*fov); + + + hor *= 2.f * farPlane * tanfov; + vertical *= 2.f * farPlane * tanfov; + + b3Scalar aspect; + float width = m_instancingRenderer->getScreenWidth(); + float height = m_instancingRenderer->getScreenHeight(); + + aspect = width / height; + + hor*=aspect; + + + b3Vector3 rayToCenter = rayFrom + rayForward; + b3Vector3 dHor = hor * 1.f/width; + b3Vector3 dVert = vertical * 1.f/height; + + + b3Vector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical; + rayTo += b3Scalar(x) * dHor; + rayTo -= b3Scalar(y) * dVert; + return rayTo; +} + + +bool GpuRigidBodyDemo::mouseMoveCallback(float x,float y) +{ + if (m_data->m_pickBody>=0 && m_data->m_pickConstraint>=0) + { + m_data->m_rigidBodyPipeline->removeConstraintByUid(m_data->m_pickConstraint); + b3Vector3 newRayTo = getRayTo(x,y); + b3Vector3 rayFrom; + b3Vector3 oldPivotInB = m_data->m_pickPivotInB; + b3Vector3 newPivotB; + m_instancingRenderer->getCameraPosition(rayFrom); + b3Vector3 dir = newRayTo-rayFrom; + dir.normalize(); + dir *= m_data->m_pickDistance; + newPivotB = rayFrom + dir; + m_data->m_pickPivotInB = newPivotB; + m_data->m_pickConstraint = m_data->m_rigidBodyPipeline->createPoint2PointConstraint(m_data->m_pickBody,m_data->m_pickFixedBody,m_data->m_pickPivotInA,m_data->m_pickPivotInB); + m_data->m_rigidBodyPipeline->writeAllInstancesToGpu(); + return true; + } + return false; +} +bool GpuRigidBodyDemo::mouseButtonCallback(int button, int state, float x, float y) +{ + if (state==1) + { + if (button==0) + { + b3AlignedObjectArray rays; + b3AlignedObjectArray hitResults; + b3Vector3 camPos; + m_instancingRenderer->getCameraPosition(camPos); + + b3RayInfo ray; + ray.m_from = camPos; + ray.m_to = getRayTo(x,y); + rays.push_back(ray); + b3RayHit hit; + hit.m_hitFraction = 1.f; + hitResults.push_back(hit); + m_data->m_rigidBodyPipeline->castRays(rays,hitResults); + if (hitResults[0].m_hitFraction<1.f) + { + + int hitBodyA = hitResults[0].m_hitBody; + if (m_data->m_np->getBodiesCpu()[hitBodyA].m_invMass) + { + //printf("hit!\n"); + m_data->m_np->readbackAllBodiesToCpu(); + m_data->m_pickBody = hitBodyA; + + + + + //pivotInA + b3Vector3 pivotInB; + pivotInB.setInterpolate3(ray.m_from,ray.m_to,hitResults[0].m_hitFraction); + b3Vector3 posA; + b3Quaternion ornA; + m_data->m_np->getObjectTransformFromCpu(posA,ornA,hitBodyA); + b3Transform tr; + tr.setOrigin(posA); + tr.setRotation(ornA); + b3Vector3 pivotInA = tr.inverse()*pivotInB; + if (m_data->m_pickFixedBody<0) + { + b3Vector3 pos(0,0,0); + b3Quaternion orn(0,0,0,1); + int fixedSphere = m_data->m_np->registerConvexHullShape(0,0,0,0);//>registerSphereShape(0.1); + m_data->m_pickFixedBody = m_data->m_rigidBodyPipeline->registerPhysicsInstance(0,pos,orn,fixedSphere,0,false); + + if (m_data->m_pickGraphicsShapeIndex<0) + { + int strideInBytes = 9*sizeof(float); + int numVertices = sizeof(point_sphere_vertices)/strideInBytes; + int numIndices = sizeof(point_sphere_indices)/sizeof(int); + m_data->m_pickGraphicsShapeIndex = m_instancingRenderer->registerShape(&point_sphere_vertices[0],numVertices,point_sphere_indices,numIndices,B3_GL_POINTS); + float color[4] ={1,0,0,1}; + float scaling[4]={1,1,1,1}; + + m_data->m_pickGraphicsShapeInstance = m_instancingRenderer->registerGraphicsInstance(m_data->m_pickGraphicsShapeIndex,pivotInB,orn,color,scaling); + m_instancingRenderer->writeTransforms(); + delete m_data->m_instancePosOrnColor; + m_data->m_instancePosOrnColor=0; + } else + { + m_instancingRenderer->writeSingleInstanceTransformToCPU(pivotInB,orn,m_data->m_pickGraphicsShapeInstance); + m_instancingRenderer->writeSingleInstanceTransformToGPU(pivotInB,orn,m_data->m_pickGraphicsShapeInstance); + m_data->m_np->setObjectTransformCpu(pos,orn,m_data->m_pickFixedBody); + } + + } + pivotInB.w = 0.f; + m_data->m_pickPivotInA = pivotInA; + m_data->m_pickPivotInB = pivotInB; + m_data->m_pickConstraint = m_data->m_rigidBodyPipeline->createPoint2PointConstraint(hitBodyA,m_data->m_pickFixedBody,pivotInA,pivotInB);//hitResults[0].m_hitResult0 + m_data->m_rigidBodyPipeline->writeAllInstancesToGpu(); + m_data->m_np->writeAllBodiesToGpu(); + m_data->m_pickDistance = (pivotInB-camPos).length(); + + return true; + } + } + } + } else + { + if (button==0) + { + if (m_data->m_pickConstraint>=0) + { + m_data->m_rigidBodyPipeline->removeConstraintByUid(m_data->m_pickConstraint); + m_data->m_pickConstraint=-1; + } + } + } + + //printf("button=%d, state=%d\n",button,state); + return false; +} \ No newline at end of file diff --git a/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemo.h b/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemo.h index c42dfc779..cf30152ea 100644 --- a/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemo.h +++ b/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemo.h @@ -2,6 +2,7 @@ #define GPU_RIGID_BODY_DEMO_H #include "../GpuDemo.h" +#include "Bullet3Common/b3Vector3.h" class GpuRigidBodyDemo : public GpuDemo { @@ -38,6 +39,10 @@ public: virtual void clientMoveAndDisplay(); + //for picking + b3Vector3 getRayTo(int x,int y); + virtual bool mouseMoveCallback(float x,float y); + virtual bool mouseButtonCallback(int button, int state, float x, float y); }; diff --git a/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemoInternalData.h b/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemoInternalData.h index a5b8943de..9977294db 100644 --- a/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemoInternalData.h +++ b/Demos3/GpuDemos/rigidbody/GpuRigidBodyDemoInternalData.h @@ -18,12 +18,28 @@ struct GpuRigidBodyDemoInternalData class b3GpuSapBroadphase* m_bp; class b3DynamicBvhBroadphase* m_broadphaseDbvt; + b3Vector3 m_pickPivotInA; + b3Vector3 m_pickPivotInB; + float m_pickDistance; + int m_pickBody; + int m_pickConstraint; + + int m_pickFixedBody; + int m_pickGraphicsShapeIndex; + int m_pickGraphicsShapeInstance; + GpuRigidBodyDemoInternalData() :m_instancePosOrnColor(0), m_copyTransformsToVBOKernel(0), m_rigidBodyPipeline(0), m_np(0), m_bp(0), - m_broadphaseDbvt(0) + m_broadphaseDbvt(0), + m_pickConstraint(-1), + m_pickFixedBody(-1), + m_pickGraphicsShapeIndex(-1), + m_pickGraphicsShapeInstance(-1), + m_pickBody(-1) + { } }; diff --git a/Demos3/Wavefront/tiny_obj_loader.cpp b/Demos3/Wavefront/tiny_obj_loader.cpp new file mode 100644 index 000000000..0cc9e2914 --- /dev/null +++ b/Demos3/Wavefront/tiny_obj_loader.cpp @@ -0,0 +1,654 @@ +// +// Copyright 2012-2013, Syoyo Fujita. +// +// Licensed under 2-clause BSD liecense. +// + +// +// version 0.9.5: Parse multiple group name. +// Add support of specifying the base path to load material file. +// version 0.9.4: Initial suupport of group tag(g) +// version 0.9.3: Fix parsing triple 'x/y/z' +// version 0.9.2: Add more .mtl load support +// version 0.9.1: Add initial .mtl load support +// version 0.9.0: Initial +// + + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "tiny_obj_loader.h" + +namespace tinyobj { + +struct vertex_index { + int v_idx, vt_idx, vn_idx; + vertex_index() {}; + vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}; + vertex_index(int vidx, int vtidx, int vnidx) : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}; + +}; +// for std::map +static inline bool operator<(const vertex_index& a, const vertex_index& b) +{ + if (a.v_idx != b.v_idx) return (a.v_idx < b.v_idx); + if (a.vn_idx != b.vn_idx) return (a.vn_idx < b.vn_idx); + if (a.vt_idx != b.vt_idx) return (a.vt_idx < b.vt_idx); + + return false; +} + +struct obj_shape { + std::vector v; + std::vector vn; + std::vector vt; +}; + +static inline bool isSpace(const char c) { + return (c == ' ') || (c == '\t'); +} + +static inline bool isNewLine(const char c) { + return (c == '\r') || (c == '\n') || (c == '\0'); +} + +// Make index zero-base, and also support relative index. +static inline int fixIndex(int idx, int n) +{ + int i; + + if (idx > 0) { + i = idx - 1; + } else if (idx == 0) { + i = 0; + } else { // negative value = relative + i = n + idx; + } + return i; +} + +static inline std::string parseString(const char*& token) +{ + std::string s; + int b = strspn(token, " \t"); + int e = strcspn(token, " \t\r"); + s = std::string(&token[b], &token[e]); + + token += (e - b); + return s; +} + +static inline float parseFloat(const char*& token) +{ + token += strspn(token, " \t"); + float f = (float)atof(token); + token += strcspn(token, " \t\r"); + return f; +} + +static inline void parseFloat2( + float& x, float& y, + const char*& token) +{ + x = parseFloat(token); + y = parseFloat(token); +} + +static inline void parseFloat3( + float& x, float& y, float& z, + const char*& token) +{ + x = parseFloat(token); + y = parseFloat(token); + z = parseFloat(token); +} + + +// Parse triples: i, i/j/k, i//k, i/j +static vertex_index parseTriple( + const char* &token, + int vsize, + int vnsize, + int vtsize) +{ + vertex_index vi(-1); + + vi.v_idx = fixIndex(atoi(token), vsize); + token += strcspn(token, "/ \t\r"); + if (token[0] != '/') { + return vi; + } + token++; + + // i//k + if (token[0] == '/') { + token++; + vi.vn_idx = fixIndex(atoi(token), vnsize); + token += strcspn(token, "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = fixIndex(atoi(token), vtsize); + token += strcspn(token, "/ \t\r"); + if (token[0] != '/') { + return vi; + } + + // i/j/k + token++; // skip '/' + vi.vn_idx = fixIndex(atoi(token), vnsize); + token += strcspn(token, "/ \t\r"); + return vi; +} + +static unsigned int +updateVertex( + std::map& vertexCache, + std::vector& positions, + std::vector& normals, + std::vector& texcoords, + const std::vector& in_positions, + const std::vector& in_normals, + const std::vector& in_texcoords, + const vertex_index& i) +{ + const std::map::iterator it = vertexCache.find(i); + + if (it != vertexCache.end()) { + // found cache + return it->second; + } + + assert(in_positions.size() > (3*i.v_idx+2)); + + positions.push_back(in_positions[3*i.v_idx+0]); + positions.push_back(in_positions[3*i.v_idx+1]); + positions.push_back(in_positions[3*i.v_idx+2]); + + if (i.vn_idx >= 0) { + normals.push_back(in_normals[3*i.vn_idx+0]); + normals.push_back(in_normals[3*i.vn_idx+1]); + normals.push_back(in_normals[3*i.vn_idx+2]); + } + + if (i.vt_idx >= 0) { + texcoords.push_back(in_texcoords[2*i.vt_idx+0]); + texcoords.push_back(in_texcoords[2*i.vt_idx+1]); + } + + unsigned int idx = positions.size() / 3 - 1; + vertexCache[i] = idx; + + return idx; +} + +static bool +exportFaceGroupToShape( + shape_t& shape, + const std::vector in_positions, + const std::vector in_normals, + const std::vector in_texcoords, + const std::vector >& faceGroup, + const material_t material, + const std::string name) +{ + if (faceGroup.empty()) { + return false; + } + + // Flattened version of vertex data + std::vector positions; + std::vector normals; + std::vector texcoords; + std::map vertexCache; + std::vector indices; + + // Flatten vertices and indices + for (size_t i = 0; i < faceGroup.size(); i++) { + const std::vector& face = faceGroup[i]; + + vertex_index i0 = face[0]; + vertex_index i1(-1); + vertex_index i2 = face[1]; + + size_t npolys = face.size(); + + // Polygon -> triangle fan conversion + for (size_t k = 2; k < npolys; k++) { + i1 = i2; + i2 = face[k]; + + unsigned int v0 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i0); + unsigned int v1 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i1); + unsigned int v2 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i2); + + indices.push_back(v0); + indices.push_back(v1); + indices.push_back(v2); + } + + } + + // + // Construct shape. + // + shape.name = name; + shape.mesh.positions.swap(positions); + shape.mesh.normals.swap(normals); + shape.mesh.texcoords.swap(texcoords); + shape.mesh.indices.swap(indices); + + shape.material = material; + + return true; + +} + + +void InitMaterial(material_t& material) { + material.name = ""; + material.ambient_texname = ""; + material.diffuse_texname = ""; + material.specular_texname = ""; + material.normal_texname = ""; + for (int i = 0; i < 3; i ++) { + material.ambient[i] = 0.f; + material.diffuse[i] = 0.f; + material.specular[i] = 0.f; + material.transmittance[i] = 0.f; + material.emission[i] = 0.f; + } + material.shininess = 1.f; +} + +std::string LoadMtl ( + std::map& material_map, + const char* filename, + const char* mtl_basepath) +{ + material_map.clear(); + std::stringstream err; + + std::string filepath; + + if (mtl_basepath) { + filepath = std::string(mtl_basepath) + std::string(filename); + } else { + filepath = std::string(filename); + } + + std::ifstream ifs(filepath.c_str()); + if (!ifs) { + err << "Cannot open file [" << filepath << "]" << std::endl; + return err.str(); + } + + material_t material; + + int maxchars = 8192; // Alloc enough size. + std::vector buf(maxchars); // Alloc enough size. + while (ifs.peek() != -1) { + ifs.getline(&buf[0], maxchars); + + std::string linebuf(&buf[0]); + + // Trim newline '\r\n' or '\r' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // new mtl + if ((0 == strncmp(token, "newmtl", 6)) && isSpace((token[6]))) { + // flush previous material. + material_map.insert(std::pair(material.name, material)); + + // initial temporary material + InitMaterial(material); + + // set new mtl name + char namebuf[4096]; + token += 7; + sscanf(token, "%s", namebuf); + material.name = namebuf; + continue; + } + + // ambient + if (token[0] == 'K' && token[1] == 'a' && isSpace((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + // diffuse + if (token[0] == 'K' && token[1] == 'd' && isSpace((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 's' && isSpace((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 't' && isSpace((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // emission + if(token[0] == 'K' && token[1] == 'e' && isSpace(token[2])) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + // shininess + if(token[0] == 'N' && token[1] == 's' && isSpace(token[2])) { + token += 2; + material.shininess = parseFloat(token); + continue; + } + + // ambient texture + if ((0 == strncmp(token, "map_Ka", 6)) && isSpace(token[6])) { + token += 7; + material.ambient_texname = token; + continue; + } + + // diffuse texture + if ((0 == strncmp(token, "map_Kd", 6)) && isSpace(token[6])) { + token += 7; + material.diffuse_texname = token; + continue; + } + + // specular texture + if ((0 == strncmp(token, "map_Ks", 6)) && isSpace(token[6])) { + token += 7; + material.specular_texname = token; + continue; + } + + // normal texture + if ((0 == strncmp(token, "map_Ns", 6)) && isSpace(token[6])) { + token += 7; + material.normal_texname = token; + continue; + } + + // unknown parameter + const char* _space = strchr(token, ' '); + if(!_space) { + _space = strchr(token, '\t'); + } + if(_space) { + int len = _space - token; + std::string key(token, len); + std::string value = _space + 1; + material.unknown_parameter.insert(std::pair(key, value)); + } + } + // flush last material. + material_map.insert(std::pair(material.name, material)); + + return err.str(); +} + +std::string +LoadObj( + std::vector& shapes, + const char* filename, + const char* mtl_basepath) +{ + + shapes.clear(); + + std::stringstream err; + + std::ifstream ifs(filename); + if (!ifs) { + err << "Cannot open file [" << filename << "]" << std::endl; + return err.str(); + } + + std::vector v; + std::vector vn; + std::vector vt; + std::vector > faceGroup; + std::string name; + + // material + std::map material_map; + material_t material; + + int maxchars = 8192; // Alloc enough size. + std::vector buf(maxchars); // Alloc enough size. + while (ifs.peek() != -1) { + ifs.getline(&buf[0], maxchars); + + std::string linebuf(&buf[0]); + + // Trim newline '\r\n' or '\r' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && isSpace((token[1]))) { + token += 2; + float x, y, z; + parseFloat3(x, y, z, token); + v.push_back(x); + v.push_back(y); + v.push_back(z); + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && isSpace((token[2]))) { + token += 3; + float x, y, z; + parseFloat3(x, y, z, token); + vn.push_back(x); + vn.push_back(y); + vn.push_back(z); + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && isSpace((token[2]))) { + token += 3; + float x, y; + parseFloat2(x, y, token); + vt.push_back(x); + vt.push_back(y); + continue; + } + + // face + if (token[0] == 'f' && isSpace((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + std::vector face; + while (!isNewLine(token[0])) { + vertex_index vi = parseTriple(token, v.size() / 3, vn.size() / 3, vt.size() / 2); + face.push_back(vi); + int n = strspn(token, " \t\r"); + token += n; + } + + faceGroup.push_back(face); + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) { + + char namebuf[4096]; + token += 7; + sscanf(token, "%s", namebuf); + + if (material_map.find(namebuf) != material_map.end()) { + material = material_map[namebuf]; + } else { + // { error!! material not found } + InitMaterial(material); + } + continue; + + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && isSpace((token[6]))) { + char namebuf[4096]; + token += 7; + sscanf(token, "%s", namebuf); + + std::string err_mtl = LoadMtl(material_map, namebuf, mtl_basepath); + if (!err_mtl.empty()) { + faceGroup.clear(); // for safety + return err_mtl; + } + continue; + } + + // group name + if (token[0] == 'g' && isSpace((token[1]))) { + + // flush previous face group. + shape_t shape; + bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name); + if (ret) { + shapes.push_back(shape); + } + + faceGroup.clear(); + + std::vector names; + while (!isNewLine(token[0])) { + std::string str = parseString(token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + // names[0] must be 'g', so skipt 0th element. + if (names.size() > 1) { + name = names[1]; + } else { + name = ""; + } + + continue; + } + + // object name + if (token[0] == 'o' && isSpace((token[1]))) { + + // flush previous face group. + shape_t shape; + bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name); + if (ret) { + shapes.push_back(shape); + } + + faceGroup.clear(); + + // @todo { multiple object name? } + char namebuf[4096]; + token += 2; + sscanf(token, "%s", namebuf); + name = std::string(namebuf); + + + continue; + } + + // Ignore unknown command. + } + + shape_t shape; + bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name); + if (ret) { + shapes.push_back(shape); + } + faceGroup.clear(); // for safety + + return err.str(); +} + + +}; diff --git a/Demos3/Wavefront/tiny_obj_loader.h b/Demos3/Wavefront/tiny_obj_loader.h new file mode 100644 index 000000000..bc3ad2eb7 --- /dev/null +++ b/Demos3/Wavefront/tiny_obj_loader.h @@ -0,0 +1,60 @@ +// +// Copyright 2012-2013, Syoyo Fujita. +// +// Licensed under 2-clause BSD liecense. +// +#ifndef _TINY_OBJ_LOADER_H +#define _TINY_OBJ_LOADER_H + +#include +#include +#include + +namespace tinyobj { + +typedef struct +{ + std::string name; + + float ambient[3]; + float diffuse[3]; + float specular[3]; + float transmittance[3]; + float emission[3]; + float shininess; + + std::string ambient_texname; + std::string diffuse_texname; + std::string specular_texname; + std::string normal_texname; + std::map unknown_parameter; +} material_t; + +typedef struct +{ + std::vector positions; + std::vector normals; + std::vector texcoords; + std::vector indices; +} mesh_t; + +typedef struct +{ + std::string name; + material_t material; + mesh_t mesh; +} shape_t; + +/// Loads .obj from a file. +/// 'shapes' will be filled with parsed shape data +/// The function returns error string. +/// Returns empty string when loading .obj success. +/// 'mtl_basepath' is optional, and used for base path for .mtl file. +std::string LoadObj( + std::vector& shapes, // [output] + const char* filename, + const char* mtl_basepath = NULL); + +}; + +#endif // _TINY_OBJ_LOADER_H diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index a5bf00803..e57306f7d 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -1027,6 +1027,15 @@ void GLInstancingRenderer::setCameraPitch(float pitch) m_data->m_azi = pitch; } +float GLInstancingRenderer::getCameraYaw() const +{ + return m_data->m_ele; +} +float GLInstancingRenderer::getCameraPitch() const +{ + return m_data->m_azi; +} + void GLInstancingRenderer::setCameraTargetPosition(float cameraPos[4]) { m_data->m_cameraTargetPosition = b3Vector3(cameraPos[0],cameraPos[1],cameraPos[2]); diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.h b/btgui/OpenGLWindow/GLInstancingRenderer.h index adb9786a9..0497b14ab 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.h +++ b/btgui/OpenGLWindow/GLInstancingRenderer.h @@ -100,7 +100,8 @@ public: void setCameraYaw(float yaw); void setCameraPitch(float pitch); - + float getCameraYaw() const; + float getCameraPitch() const; void resize(int width, int height); int getScreenWidth() diff --git a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp index 3808b863c..8f0b77b3f 100644 --- a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp +++ b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp @@ -199,12 +199,12 @@ void b3GpuRaycast::castRaysHost(const b3AlignedObjectArray& rays, b3A hitResults[r].m_hitFraction = hitFraction; hitResults[r].m_hitPoint.setInterpolate3(rays[r].m_from, rays[r].m_to,hitFraction); hitResults[r].m_hitNormal = hitNormal; - hitResults[r].m_hitResult0 = hitBodyIndex; + hitResults[r].m_hitBody = hitBodyIndex; } } } - +///todo: add some acceleration structure (AABBs, tree etc) void b3GpuRaycast::castRays(const b3AlignedObjectArray& rays, b3AlignedObjectArray& hitResults, int numBodies,const struct b3RigidBodyCL* bodies, int numCollidables, const struct b3Collidable* collidables, const struct b3GpuNarrowPhaseInternalData* narrowphaseData) { diff --git a/src/Bullet3OpenCL/Raycast/b3RaycastInfo.h b/src/Bullet3OpenCL/Raycast/b3RaycastInfo.h index 99d4dc4a4..fba8bd07a 100644 --- a/src/Bullet3OpenCL/Raycast/b3RaycastInfo.h +++ b/src/Bullet3OpenCL/Raycast/b3RaycastInfo.h @@ -13,7 +13,7 @@ B3_ATTRIBUTE_ALIGNED16(struct) b3RayInfo B3_ATTRIBUTE_ALIGNED16(struct) b3RayHit { b3Scalar m_hitFraction; - int m_hitResult0; + int m_hitBody; int m_hitResult1; int m_hitResult2; b3Vector3 m_hitPoint; diff --git a/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.h b/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.h index a3ac9fa84..78386920f 100644 --- a/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.h +++ b/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.h @@ -87,7 +87,8 @@ B3_ATTRIBUTE_ALIGNED16(struct) b3GpuGenericConstraint b3Quaternion m_relTargetAB; int m_flags; - int m_padding[3]; + int m_uid; + int m_padding[2]; int getRigidBodyA() const { diff --git a/src/Bullet3OpenCL/RigidBody/b3GpuPgsJacobiSolver.cpp b/src/Bullet3OpenCL/RigidBody/b3GpuPgsJacobiSolver.cpp index 326a39ebb..e6b15e6f5 100644 --- a/src/Bullet3OpenCL/RigidBody/b3GpuPgsJacobiSolver.cpp +++ b/src/Bullet3OpenCL/RigidBody/b3GpuPgsJacobiSolver.cpp @@ -189,7 +189,10 @@ struct b3BatchConstraint static b3AlignedObjectArray batchConstraints; static b3AlignedObjectArray batches; - +void b3GpuPgsJacobiSolver::recomputeBatches() +{ + batches.clear(); +} @@ -695,7 +698,7 @@ b3Scalar b3GpuPgsJacobiSolver::solveGroupCacheFriendlyIterations(b3OpenCLArray* gpuConstraints); int sortConstraintByBatch3( struct b3BatchConstraint* cs, int numConstraints, int simdWidth , int staticIdx, int numBodies); + void recomputeBatches(); }; #endif //B3_GPU_PGS_JACOBI_SOLVER_H diff --git a/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp b/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp index 459d5adbe..6bde0ac1e 100644 --- a/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp +++ b/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp @@ -56,6 +56,7 @@ bool dumpContactStats = false; b3GpuRigidBodyPipeline::b3GpuRigidBodyPipeline(cl_context ctx,cl_device_id device, cl_command_queue q,class b3GpuNarrowPhase* narrowphase, class b3GpuSapBroadphase* broadphaseSap , struct b3DynamicBvhBroadphase* broadphaseDbvt, const b3Config& config) { m_data = new b3GpuRigidBodyPipelineInternalData; + m_data->m_constraintUid=0; m_data->m_config = config; m_data->m_context = ctx; m_data->m_device = device; @@ -140,9 +141,41 @@ void b3GpuRigidBodyPipeline::removeConstraint(b3TypedConstraint* constraint) m_data->m_joints.remove(constraint); } + + +void b3GpuRigidBodyPipeline::removeConstraintByUid(int uid) +{ + m_data->m_gpuSolver->recomputeBatches(); + //slow linear search + m_data->m_gpuConstraints->copyToHost(m_data->m_cpuConstraints); + //remove + for (int i=0;im_cpuConstraints.size();i++) + { + if (m_data->m_cpuConstraints[i].m_uid == uid) + { + //m_data->m_cpuConstraints.remove(m_data->m_cpuConstraints[i]); + m_data->m_cpuConstraints.swap(i,m_data->m_cpuConstraints.size()-1); + m_data->m_cpuConstraints.pop_back(); + + break; + } + } + + if (m_data->m_cpuConstraints.size()) + { + m_data->m_gpuConstraints->copyFromHost(m_data->m_cpuConstraints); + } else + { + m_data->m_gpuConstraints->resize(0); + } + +} int b3GpuRigidBodyPipeline::createPoint2PointConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB) { + m_data->m_gpuSolver->recomputeBatches(); b3GpuGenericConstraint c; + c.m_uid = m_data->m_constraintUid; + m_data->m_constraintUid++; c.m_flags = B3_CONSTRAINT_FLAG_ENABLED; c.m_rbA = bodyA; c.m_rbB = bodyB; @@ -151,10 +184,11 @@ int b3GpuRigidBodyPipeline::createPoint2PointConstraint(int bodyA, int bodyB, co c.m_breakingImpulseThreshold = 1e30f; c.m_constraintType = B3_GPU_POINT2POINT_CONSTRAINT_TYPE; m_data->m_cpuConstraints.push_back(c); - return 0; + return c.m_uid; } int b3GpuRigidBodyPipeline::createFixedConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB, const float* frameOrnA, const float* frameOrnB) { + m_data->m_gpuSolver->recomputeBatches(); return 0; } diff --git a/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h b/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h index 480fec0ae..eaff485ce 100644 --- a/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h +++ b/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h @@ -57,6 +57,7 @@ public: int createPoint2PointConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB); int createFixedConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB, const float* frameOrnA, const float* frameOrnB); + void removeConstraintByUid(int uid); void addConstraint(class b3TypedConstraint* constraint); void removeConstraint(b3TypedConstraint* constraint); diff --git a/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipelineInternalData.h b/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipelineInternalData.h index e604488b6..312717b93 100644 --- a/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipelineInternalData.h +++ b/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipelineInternalData.h @@ -60,7 +60,7 @@ struct b3GpuRigidBodyPipelineInternalData b3AlignedObjectArray m_cpuConstraints; b3AlignedObjectArray m_joints; - + int m_constraintUid; class b3GpuNarrowPhase* m_narrowphase; b3Vector3 m_gravity;