void setup_vertex_uv_buffer_object(void) { glGenBuffers(1, &vertex_uv_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_uv_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * trig.UVs().size(), &trig.UVs()[0], GL_STATIC_DRAW); }
bool OBJ::write(const TriangleMesh& mesh, std::string output_file) { mesh.WriteOBJFile(output_file); return true; }
virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroids[numObjects] = SimdVector3(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroids[numObjects] += vertex0; centroids[numObjects]+= vertex1; centroids[numObjects]+= vertex2; } } centroids[numObjects] *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroids[numObjects]; vertex1 -= centroids[numObjects]; vertex2 -= centroids[numObjects]; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } shapeIndex[numObjects] = numObjects; shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } }
void makeBallScene() { g_camera = new Camera; g_scene = new Scene; g_image = new Image; g_image->resize(512, 512); Material* lambert = new Lambert(Vector3(1.0f,0.5f,0.0f)); Material* lambert_ground = new Lambert(Vector3(0.9f,0.9f,0.9f)); Material* mirror = new Mirror(Vector3(0.6f)); Material* glass = new Glass(Vector3(0.95f),1.5f); Material* brdf = new BPhong(Vector3(0.4f),Vector3(0.6f),200); // set up the camera g_camera->setBGColor(Vector3(0.0f, 0.0f, 0.0f)); g_camera->setEye(Vector3( 10, 3, 10)); g_camera->setLookAt(Vector3(0, 0, 0)); g_camera->setUp(Vector3(0, 1, 0)); g_camera->setFOV(45); // create and place a point light source PointLight * light = new PointLight; light->setPosition(Vector3(5, 15, 5)); light->setColor(Vector3(1, 1, 1)); light->setWattage(4.0 * PI * 700); g_scene->addLight(light); // create the floor triangle TriangleMesh * floor = new TriangleMesh; floor->createSingleTriangle(); floor->setV1(Vector3(-100, 0, -100)); floor->setV2(Vector3(0, 0, 100)); floor->setV3(Vector3(100, 0, 0)); floor->setN1(Vector3(0, 1, 0)); floor->setN2(Vector3(0, 1, 0)); floor->setN3(Vector3(0, 1, 0)); TriangleMesh * right = new TriangleMesh; right->createSingleTriangle(); right->setV1(Vector3(10, 0, -10)); right->setV2(Vector3(0, 100, 0)); right->setV3(Vector3(-10, 0, 10)); right->setN1(Vector3(1, 0, 1)); right->setN2(Vector3(1, 0, 1)); right->setN3(Vector3(1, 0, 1)); TriangleMesh * left = new TriangleMesh; left->createSingleTriangle(); left->setV1(Vector3(0, 0, 0)); left->setV2(Vector3(100, 0, 0)); left->setV3(Vector3(0, 100, 0)); left->setN1(Vector3(0, 0, 1)); left->setN2(Vector3(0, 0, 1)); left->setN3(Vector3(0, 0, 1)); Triangle* t = new Triangle; t->setIndex(0); t->setMesh(floor); t->setMaterial(lambert_ground); Triangle* t2 = new Triangle; t2->setIndex(0); t2->setMesh(right); t2->setMaterial(lambert_ground); Triangle* t3 = new Triangle; t3->setIndex(0); t3->setMesh(left); t3->setMaterial(lambert_ground); g_scene->addObject(t); g_scene->addObject(t2); //g_scene->addObject(t3); //create two balls Sphere * sphere1 = new Sphere; sphere1->setCenter(Vector3(0.5, 1, 1)); sphere1->setRadius(0.2); sphere1->setMaterial(lambert); Sphere * sphere2 = new Sphere; sphere2->setCenter(Vector3(1, 1, 0.5)); sphere2->setRadius(0.2); sphere2->setMaterial(lambert); Sphere * sphere3= new Sphere; sphere3->setCenter(Vector3(4, 1, 2)); sphere3->setRadius(1); sphere3->setMaterial(glass); Sphere * sphere4 = new Sphere; sphere4->setCenter(Vector3(2, 1, 4)); sphere4->setRadius(1); sphere4->setMaterial(brdf); g_scene->addObject(sphere1); g_scene->addObject(sphere2); g_scene->addObject(sphere3); g_scene->addObject(sphere4); g_scene->preCalc(); }
void makeTeapotScene() { g_camera = new Camera; g_scene = new Scene; g_image = new Image; g_image->resize(512, 512); // set up the camera g_camera->setBGColor(Vector3(0.0f, 0.0f, 0.2f)); g_camera->setEye(Vector3(0, 6, 2)); g_camera->setLookAt(Vector3(0, 0, 0)); g_camera->setUp(Vector3(0, 1, 0)); g_camera->setFOV(45); // create and place a point light source PointLight * light = new PointLight; light->setPosition(Vector3(-2.5, 10, -2.5)); light->setColor(Vector3(1, 1, 1)); light->setWattage(4.0 * PI * 700); PointLight * light1 = new PointLight; light1->setPosition(Vector3(10, 15, 10)); light1->setColor(Vector3(1, 1, 1)); light1->setWattage(4.0 * PI * 700); g_scene->addLight(light); //g_scene->addLight(light1); //for test shadow Material* lambert = new Lambert(Vector3(1.0f)); Material* mirror = new Mirror(Vector3(0.8f)); Material* glass = new Glass(Vector3(0.95f), 1.5f); Material* brdf = new BPhong(Vector3(0.4f,0.4f,0.0f), Vector3(0.6f,0.6f,0.0f), 50); TriangleMesh * teapot = new TriangleMesh; Matrix4x4 xform; teapot->load("teapot.obj"); addMeshTrianglesToScene(teapot, brdf); xform.setIdentity(); xform *= translate(-5, 0, 0); teapot = new TriangleMesh; teapot->load("teapot.obj",xform); addMeshTrianglesToScene(teapot, lambert); xform.setIdentity(); xform *= translate(-5, 0, -5); teapot = new TriangleMesh; teapot->load("teapot.obj", xform); addMeshTrianglesToScene(teapot, mirror); // create the floor triangle TriangleMesh * floor = new TriangleMesh; floor->createSingleTriangle(); floor->setV1(Vector3(-100, 0, -100)); floor->setV2(Vector3( 0, 0, 100)); floor->setV3(Vector3( 100, 0, -100)); floor->setN1(Vector3(0, 1, 0)); floor->setN2(Vector3(0, 1, 0)); floor->setN3(Vector3(0, 1, 0)); Triangle* t = new Triangle; t->setIndex(0); t->setMesh(floor); t->setMaterial(lambert); g_scene->addObject(t); // let objects do pre-calculations if needed g_scene->preCalc(); }
void makeBunny20Scene() { g_camera = new Camera; g_scene = new Scene; g_image = new Image; g_image->resize(512, 512); // set up the camera g_camera->setBGColor(Vector3(0.0f, 0.0f, 0.2f)); g_camera->setEye(Vector3(0, 5, 15)); g_camera->setLookAt(Vector3(0, 0, 0)); g_camera->setUp(Vector3(0, 1, 0)); g_camera->setFOV(45); // create and place a point light source PointLight * light = new PointLight; light->setPosition(Vector3(10, 20, 10)); light->setColor(Vector3(1, 1, 1)); light->setWattage(4.0 * PI * 1000); g_scene->addLight(light); TriangleMesh * mesh; Material* material = new Lambert(Vector3(1.0f)); Matrix4x4 xform; Matrix4x4 xform2; xform2 *= rotate(110, 0, 1, 0); xform2 *= scale(.6, 1, 1.1); // bunny 1 xform.setIdentity(); xform *= scale(0.3, 2.0, 0.7); xform *= translate(-1, .4, .3); xform *= rotate(25, .3, .1, .6); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 2 xform.setIdentity(); xform *= scale(.6, 1.2, .9); xform *= translate(7.6, .8, .6); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 3 xform.setIdentity(); xform *= translate(.7, 0, -2); xform *= rotate(120, 0, .6, 1); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 4 xform.setIdentity(); xform *= translate(3.6, 3, -1); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 5 xform.setIdentity(); xform *= translate(-2.4, 2, 3); xform *= scale(1, .8, 2); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 6 xform.setIdentity(); xform *= translate(5.5, -.5, 1); xform *= scale(1, 2, 1); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 7 xform.setIdentity(); xform *= rotate(15, 0, 0, 1); xform *= translate(-4, -.5, -6); xform *= scale(1, 2, 1); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 8 xform.setIdentity(); xform *= rotate(60, 0, 1, 0); xform *= translate(5, .1, 3); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 9 xform.setIdentity(); xform *= translate(-3, .4, 6); xform *= rotate(-30, 0, 1, 0); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 10 xform.setIdentity(); xform *= translate(3, 0.5, -2); xform *= rotate(180, 0, 1, 0); xform *= scale(1.5, 1.5, 1.5); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 11 xform = xform2; xform *= scale(0.3, 2.0, 0.7); xform *= translate(-1, .4, .3); xform *= rotate(25, .3, .1, .6); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 12 xform = xform2; xform *= scale(.6, 1.2, .9); xform *= translate(7.6, .8, .6); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 13 xform = xform2; xform *= translate(.7, 0, -2); xform *= rotate(120, 0, .6, 1); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 14 xform = xform2; xform *= translate(3.6, 3, -1); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 15 xform = xform2; xform *= translate(-2.4, 2, 3); xform *= scale(1, .8, 2); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 16 xform = xform2; xform *= translate(5.5, -.5, 1); xform *= scale(1, 2, 1); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 17 xform = xform2; xform *= rotate(15, 0, 0, 1); xform *= translate(-4, -.5, -6); xform *= scale(1, 2, 1); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 18 xform = xform2; xform *= rotate(60, 0, 1, 0); xform *= translate(5, .1, 3); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 19 xform = xform2; xform *= translate(-3, .4, 6); xform *= rotate(-30, 0, 1, 0); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // bunny 20 xform = xform2; xform *= translate(3, 0.5, -2); xform *= rotate(180, 0, 1, 0); xform *= scale(1.5, 1.5, 1.5); mesh = new TriangleMesh; mesh->load("bunny.obj", xform); addMeshTrianglesToScene(mesh, material); // create the floor triangle mesh = new TriangleMesh; mesh->createSingleTriangle(); mesh->setV1(Vector3(-100, 0, -100)); mesh->setV2(Vector3( 0, 0, 100)); mesh->setV3(Vector3( 100, 0, -100)); mesh->setN1(Vector3(0, 1, 0)); mesh->setN2(Vector3(0, 1, 0)); mesh->setN3(Vector3(0, 1, 0)); Triangle* t = new Triangle; t->setIndex(0); t->setMesh(mesh); t->setMaterial(material); g_scene->addObject(t); // let objects do pre-calculations if needed g_scene->preCalc(); }
int main(int argc, const char * argv[]) { Electrostatics e; TriangleMesh *teststl = new TriangleMesh(); teststl->read("/Users/phaedon/github/bem-laplace-simple/meshes/sphere5120.stl", MeshFileFormat::MFF_STL); teststl->write("/Users/phaedon/github/bem-laplace-simple/meshes/sphere5120.obj", MeshFileFormat::MFF_OBJ); TriangleMesh *s = new TriangleMesh(); s->read("/Users/phaedon/github/bem-laplace-simple/meshes/sphere_5mm_h0cm_s3.obj", MeshFileFormat::MFF_OBJ); e.addBubble(s); s = new TriangleMesh(); s->read("/Users/phaedon/github/bem-laplace-simple/meshes/sphere_5mm_h10cm.obj", MeshFileFormat::MFF_OBJ); e.addBubble(s); s = new TriangleMesh(); s->read("/Users/phaedon/github/bem-laplace-simple/meshes/sphere_5mm_h30cm.obj", MeshFileFormat::MFF_OBJ); e.addBubble(s); s = new TriangleMesh(); s->read("/Users/phaedon/github/bem-laplace-simple/meshes/sphere_5mm_h50cm.obj", MeshFileFormat::MFF_OBJ); e.addBubble(s); s = new TriangleMesh(); s->read("/Users/phaedon/github/bem-laplace-simple/meshes/sphere_5mm_h80cm.obj", MeshFileFormat::MFF_OBJ); e.addBubble(s); s = new TriangleMesh(); s->read("/Users/phaedon/github/bem-laplace-simple/meshes/sphere_5mm_h90cm.obj", MeshFileFormat::MFF_OBJ); e.addBubble(s); s = new TriangleMesh(); s->read("/Users/phaedon/github/bem-laplace-simple/meshes/sphere_5mm_h95cm.obj", MeshFileFormat::MFF_OBJ); e.addBubble(s); s = new TriangleMesh(); s->read("/Users/phaedon/github/bem-laplace-simple/meshes/sphere_5mm_h995mm_s3.obj", MeshFileFormat::MFF_OBJ); e.addBubble(s); TriangleMesh *plane = new TriangleMesh(); plane->read("/Users/phaedon/github/bem-laplace-simple/meshes/plane_h1_s50mm_t128.obj", MeshFileFormat::MFF_OBJ); e.setSurface(plane); std::vector<double> caps; e.capacitance(caps); for (size_t i = 0; i < caps.size(); i++) { std::cout << "capacitance of " << i << "th bubble: " << caps[i] << std::endl; } std::cout << "Finished!" << std::endl; return 0; }
void GenerateBezierPatch(const BezierPatchDescriptor& desc, TriangleMesh& mesh) { auto idxOffset = mesh.vertices.size(); const auto segsHorz = std::max(1u, desc.segments.x); const auto segsVert = std::max(1u, desc.segments.y); const auto invHorz = Gs::Real(1) / static_cast<Gs::Real>(segsHorz); const auto invVert = Gs::Real(1) / static_cast<Gs::Real>(segsVert); auto AddQuad = [&](unsigned int u, unsigned int v, VertexIndex i0, VertexIndex i1, VertexIndex i2, VertexIndex i3) { if (desc.backFacing) AddTriangulatedQuad(mesh, desc.alternateGrid, u, v, i1, i0, i3, i2, idxOffset); else AddTriangulatedQuad(mesh, desc.alternateGrid, u, v, i0, i1, i2, i3, idxOffset); }; /* Generate vertices */ static const Gs::Real delta = Gs::Real(0.01); Gs::Vector3 coord, normal; Gs::Vector2 texCoord; for (unsigned int i = 0; i <= segsVert; ++i) { for (unsigned int j = 0; j <= segsHorz; ++j) { /* Compute coordinate and texture-coordinate */ texCoord.x = static_cast<Gs::Real>(j) * invHorz; texCoord.y = static_cast<Gs::Real>(i) * invVert; coord = desc.bezierPatch(texCoord.x, texCoord.y); /* Sample bezier patch to approximate normal */ auto uOffset = (desc.bezierPatch(texCoord.x + delta, texCoord.y) - coord); auto vOffset = (desc.bezierPatch(texCoord.x, texCoord.y + delta) - coord); normal = Gs::Cross(uOffset, vOffset).Normalized(); /* Add vertex */ if (!desc.backFacing) { texCoord.y = Gs::Real(1) - texCoord.y; normal = -normal; } mesh.AddVertex(coord, normal, texCoord); } } /* Generate indices */ const auto strideHorz = segsHorz + 1; for (unsigned int v = 0; v < segsVert; ++v) { for (unsigned int u = 0; u < segsHorz; ++u) { AddQuad( u, v, ( v *strideHorz + u ), ( (v+1)*strideHorz + u ), ( (v+1)*strideHorz + u+1 ), ( v *strideHorz + u+1 ) ); } } }
/** Additional initialisation after loading of the model is finished. */ void PhysicalObject::init() { // 1. Determine size of the object // ------------------------------- Vec3 min, max; TrackObjectPresentationSceneNode* presentation = m_object->getPresentation<TrackObjectPresentationSceneNode>(); if (presentation->getNode()->getType() == scene::ESNT_ANIMATED_MESH) { scene::IAnimatedMesh *mesh = ((scene::IAnimatedMeshSceneNode*)presentation->getNode())->getMesh(); MeshTools::minMax3D(mesh, &min, &max); } else if (presentation->getNode()->getType()==scene::ESNT_MESH) { scene::IMesh *mesh = ((scene::IMeshSceneNode*)presentation->getNode())->getMesh(); MeshTools::minMax3D(mesh, &min, &max); } else if (presentation->getNode()->getType()==scene::ESNT_LOD_NODE) { scene::ISceneNode* node = ((LODNode*)presentation->getNode())->getAllNodes()[0]; if (node->getType() == scene::ESNT_ANIMATED_MESH) { scene::IAnimatedMesh *mesh = ((scene::IAnimatedMeshSceneNode*)node)->getMesh(); MeshTools::minMax3D(mesh, &min, &max); } else if (node->getType()==scene::ESNT_MESH) { scene::IMesh *mesh = ((scene::IMeshSceneNode*)node)->getMesh(); MeshTools::minMax3D(mesh, &min, &max); } else { Log::fatal("PhysicalObject", "Unknown node type"); } } else if (dynamic_cast<TrackObjectPresentationInstancing*>(presentation) != NULL) { TrackObjectPresentationInstancing* instancing = dynamic_cast<TrackObjectPresentationInstancing*>(presentation); STKInstancedSceneNode* instancing_group = instancing->getInstancingGroup(); if (instancing_group != NULL) { scene::IMesh* mesh = instancing_group->getMesh(); MeshTools::minMax3D(mesh, &min, &max); } } else { Log::fatal("PhysicalObject", "Unknown node type"); } Vec3 extend = max-min; // Adjust the mesth of the graphical object so that its center is where it // is in bullet (usually at (0,0,0)). It can be changed in the case clause // if this is not correct for a particular shape. m_graphical_offset = -0.5f*(max+min); switch (m_body_type) { case MP_CONE_Y: { if (m_radius < 0) m_radius = 0.5f*extend.length_2d(); m_shape = new btConeShape(m_radius, extend.getY()); break; } case MP_CONE_X: { if (m_radius < 0) m_radius = 0.5f*sqrt(extend.getY()*extend.getY() + extend.getZ()*extend.getZ()); m_shape = new btConeShapeX(m_radius, extend.getY()); break; } case MP_CONE_Z: { if (m_radius < 0) m_radius = 0.5f*sqrt(extend.getX()*extend.getX() + extend.getY()*extend.getY()); m_shape = new btConeShapeZ(m_radius, extend.getY()); break; } case MP_CYLINDER_Y: { if (m_radius < 0) m_radius = 0.5f*extend.length_2d(); m_shape = new btCylinderShape(0.5f*extend); break; } case MP_CYLINDER_X: { if (m_radius < 0) m_radius = 0.5f*sqrt(extend.getY()*extend.getY() + extend.getZ()*extend.getZ()); m_shape = new btCylinderShapeX(0.5f*extend); break; } case MP_CYLINDER_Z: { if (m_radius < 0) m_radius = 0.5f*sqrt(extend.getX()*extend.getX() + extend.getY()*extend.getY()); m_shape = new btCylinderShapeZ(0.5f*extend); break; } case MP_SPHERE: { if(m_radius<0) { m_radius = std::max(extend.getX(), extend.getY()); m_radius = 0.5f*std::max(m_radius, extend.getZ()); } m_shape = new btSphereShape(m_radius); break; } case MP_EXACT: { TriangleMesh* triangle_mesh = new TriangleMesh(); // In case of readonly materials we have to get the material from // the mesh, otherwise from the node. This is esp. important for // water nodes, which only have the material defined in the node, // but not in the mesh at all! bool is_readonly_material = false; scene::IMesh* mesh = NULL; switch (presentation->getNode()->getType()) { case scene::ESNT_MESH : case scene::ESNT_WATER_SURFACE : case scene::ESNT_OCTREE : { scene::IMeshSceneNode *node = (scene::IMeshSceneNode*)presentation->getNode(); mesh = node->getMesh(); is_readonly_material = node->isReadOnlyMaterials(); break; } case scene::ESNT_ANIMATED_MESH : { // for now just use frame 0 scene::IAnimatedMeshSceneNode *node = (scene::IAnimatedMeshSceneNode*)presentation->getNode(); mesh = node->getMesh()->getMesh(0); is_readonly_material = node->isReadOnlyMaterials(); break; } default: Log::warn("PhysicalObject", "Unknown object type, " "cannot create exact collision body!"); return; } // switch node->getType() for(unsigned int i=0; i<mesh->getMeshBufferCount(); i++) { scene::IMeshBuffer *mb = mesh->getMeshBuffer(i); // FIXME: take translation/rotation into account if (mb->getVertexType() != video::EVT_STANDARD && mb->getVertexType() != video::EVT_2TCOORDS) { Log::warn("PhysicalObject", "createPhysicsBody: Ignoring type '%d'!", mb->getVertexType()); continue; } // Handle readonly materials correctly: mb->getMaterial can return // NULL if the node is not using readonly materials. E.g. in case // of a water scene node, the mesh (which is the animated copy of // the original mesh) does not contain any material information, // the material is only available in the node. const video::SMaterial &irrMaterial = is_readonly_material ? mb->getMaterial() : presentation->getNode()->getMaterial(i); video::ITexture* t=irrMaterial.getTexture(0); const Material* material=0; TriangleMesh *tmesh = triangle_mesh; if(t) { std::string image = std::string(core::stringc(t->getName()).c_str()); material = material_manager ->getMaterial(StringUtils::getBasename(image)); if(material->isIgnore()) continue; } u16 *mbIndices = mb->getIndices(); Vec3 vertices[3]; Vec3 normals[3]; if (mb->getVertexType() == video::EVT_STANDARD) { irr::video::S3DVertex* mbVertices = (video::S3DVertex*)mb->getVertices(); for(unsigned int j=0; j<mb->getIndexCount(); j+=3) { for(unsigned int k=0; k<3; k++) { int indx=mbIndices[j+k]; core::vector3df v = mbVertices[indx].Pos; //mat.transformVect(v); vertices[k]=v; normals[k]=mbVertices[indx].Normal; } // for k if(tmesh) tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], normals[1], normals[2], material ); } // for j } else { if (mb->getVertexType() == video::EVT_2TCOORDS) { irr::video::S3DVertex2TCoords* mbVertices = (video::S3DVertex2TCoords*)mb->getVertices(); for(unsigned int j=0; j<mb->getIndexCount(); j+=3) { for(unsigned int k=0; k<3; k++) { int indx=mbIndices[j+k]; core::vector3df v = mbVertices[indx].Pos; //mat.transformVect(v); vertices[k]=v; normals[k]=mbVertices[indx].Normal; } // for k if(tmesh) tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], normals[1], normals[2], material ); } // for j } } } // for i<getMeshBufferCount triangle_mesh->createCollisionShape(); m_shape = &triangle_mesh->getCollisionShape(); m_triangle_mesh = triangle_mesh; break; } case MP_NONE: default: Log::warn("PhysicalObject", "Uninitialised moving shape"); // intended fall-through case MP_BOX: { m_shape = new btBoxShape(0.5*extend); break; } } // 2. Create the rigid object // -------------------------- // m_init_pos is the point on the track - add the offset m_init_pos.setOrigin(m_init_pos.getOrigin() + btVector3(0,extend.getY()*0.5f, 0)); m_motion_state = new btDefaultMotionState(m_init_pos); btVector3 inertia; if (m_body_type != MP_EXACT) m_shape->calculateLocalInertia(m_mass, inertia); btRigidBody::btRigidBodyConstructionInfo info(m_mass, m_motion_state, m_shape, inertia); // Make sure that the cones stop rolling by defining angular friction != 0. info.m_angularDamping = 0.5f; m_body = new btRigidBody(info); m_user_pointer.set(this); m_body->setUserPointer(&m_user_pointer); if (!m_is_dynamic) { m_body->setCollisionFlags( m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); m_body->setActivationState(DISABLE_DEACTIVATION); } World::getWorld()->getPhysics()->addBody(m_body); } // init
int main(int argc,char** argv) { int i; for (i=0;i<numObjects;i++) { if (i>0) { shapePtr[i] = prebuildShapePtr[1]; shapeIndex[i] = 1;//sphere } else { shapeIndex[i] = 0; shapePtr[i] = prebuildShapePtr[0]; } } ConvexDecomposition::WavefrontObj wo; char* filename = "file.obj"; tcount = wo.loadObj(filename); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { public: MyConvexDecomposition (FILE* outputFile) :mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroids[numObjects] = SimdVector3(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroids[numObjects] += vertex0; centroids[numObjects]+= vertex1; centroids[numObjects]+= vertex2; } } centroids[numObjects] *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroids[numObjects]; vertex1 -= centroids[numObjects]; vertex2 -= centroids[numObjects]; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } shapeIndex[numObjects] = numObjects; shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { numObjects = 1; //always have the ground object first TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); for (int i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; SimdVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); SimdVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); SimdVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->AddTriangle(vertex0,vertex1,vertex2); } shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh); } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 7; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.01; printf("WavefrontObj num triangles read %i",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); int ret = cb.process(desc); if (outputFile) fclose(outputFile); } CollisionDispatcher* dispatcher = new CollisionDispatcher(); SimdVector3 worldAabbMin(-10000,-10000,-10000); SimdVector3 worldAabbMax(10000,10000,10000); OverlappingPairCache* broadphase = new AxisSweep3(worldAabbMin,worldAabbMax); //OverlappingPairCache* broadphase = new SimpleBroadphase(); physicsEnvironmentPtr = new CcdPhysicsEnvironment(dispatcher,broadphase); physicsEnvironmentPtr->setDeactivationTime(2.f); physicsEnvironmentPtr->setGravity(0,-10,0); PHY_ShapeProps shapeProps; shapeProps.m_do_anisotropic = false; shapeProps.m_do_fh = false; shapeProps.m_do_rot_fh = false; shapeProps.m_friction_scaling[0] = 1.; shapeProps.m_friction_scaling[1] = 1.; shapeProps.m_friction_scaling[2] = 1.; shapeProps.m_inertia = 1.f; shapeProps.m_lin_drag = 0.2f; shapeProps.m_ang_drag = 0.1f; shapeProps.m_mass = 10.0f; PHY_MaterialProps materialProps; materialProps.m_friction = 10.5f; materialProps.m_restitution = 0.0f; CcdConstructionInfo ccdObjectCi; ccdObjectCi.m_friction = 0.5f; ccdObjectCi.m_linearDamping = shapeProps.m_lin_drag; ccdObjectCi.m_angularDamping = shapeProps.m_ang_drag; SimdTransform tr; tr.setIdentity(); for (i=0;i<numObjects;i++) { shapeProps.m_shape = shapePtr[shapeIndex[i]]; shapeProps.m_shape->SetMargin(0.05f); bool isDyna = i>0; //if (i==1) // isDyna=false; if (0)//i==1) { SimdQuaternion orn(0,0,0.1*SIMD_HALF_PI); ms[i].setWorldOrientation(orn.x(),orn.y(),orn.z(),orn[3]); } if (i>0) { switch (i) { case 1: { ms[i].setWorldPosition(0,10,0); //for testing, rotate the ground cube so the stack has to recover a bit break; } case 2: { ms[i].setWorldPosition(0,8,2); break; } default: ms[i].setWorldPosition(0,i*CUBE_HALF_EXTENTS*2 - CUBE_HALF_EXTENTS,0); } float quatIma0,quatIma1,quatIma2,quatReal; SimdQuaternion quat; SimdVector3 axis(0,0,1); SimdScalar angle=0.5f; quat.setRotation(axis,angle); ms[i].setWorldOrientation(quat.getX(),quat.getY(),quat.getZ(),quat[3]); } else { ms[i].setWorldPosition(0,-10+EXTRA_HEIGHT,0); } ccdObjectCi.m_MotionState = &ms[i]; ccdObjectCi.m_gravity = SimdVector3(0,0,0); ccdObjectCi.m_localInertiaTensor =SimdVector3(0,0,0); if (!isDyna) { shapeProps.m_mass = 0.f; ccdObjectCi.m_mass = shapeProps.m_mass; ccdObjectCi.m_collisionFlags = CollisionObject::isStatic; } else { shapeProps.m_mass = 1.f; ccdObjectCi.m_mass = shapeProps.m_mass; ccdObjectCi.m_collisionFlags = 0; } SimdVector3 localInertia; if (shapePtr[shapeIndex[i]]->GetShapeType() == EMPTY_SHAPE_PROXYTYPE) { //take inertia from first shape shapePtr[1]->CalculateLocalInertia(shapeProps.m_mass,localInertia); } else { shapePtr[shapeIndex[i]]->CalculateLocalInertia(shapeProps.m_mass,localInertia); } ccdObjectCi.m_localInertiaTensor = localInertia; ccdObjectCi.m_collisionShape = shapePtr[shapeIndex[i]]; physObjects[i]= new CcdPhysicsController( ccdObjectCi); // Only do CCD if motion in one timestep (1.f/60.f) exceeds CUBE_HALF_EXTENTS physObjects[i]->GetRigidBody()->m_ccdSquareMotionTreshold = CUBE_HALF_EXTENTS; //Experimental: better estimation of CCD Time of Impact: //physObjects[i]->GetRigidBody()->m_ccdSweptShereRadius = 0.5*CUBE_HALF_EXTENTS; physicsEnvironmentPtr->addCcdPhysicsController( physObjects[i]); if (i==1) { //physObjects[i]->SetAngularVelocity(0,0,-2,true); } physicsEnvironmentPtr->setDebugDrawer(&debugDrawer); } //create a constraint if (createConstraint) { //physObjects[i]->SetAngularVelocity(0,0,-2,true); int constraintId; float pivotX=CUBE_HALF_EXTENTS, pivotY=-CUBE_HALF_EXTENTS, pivotZ=CUBE_HALF_EXTENTS; float axisX=1,axisY=0,axisZ=0; HingeConstraint* hinge = 0; SimdVector3 pivotInA(CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS); SimdVector3 pivotInB(-CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS); SimdVector3 axisInA(0,1,0); SimdVector3 axisInB(0,-1,0); RigidBody* rb0 = physObjects[1]->GetRigidBody(); RigidBody* rb1 = physObjects[2]->GetRigidBody(); hinge = new HingeConstraint( *rb0, *rb1,pivotInA,pivotInB,axisInA,axisInB); physicsEnvironmentPtr->m_constraints.push_back(hinge); hinge->SetUserConstraintId(100); hinge->SetUserConstraintType(PHY_LINEHINGE_CONSTRAINT); } clientResetScene(); setCameraDistance(26.f); return glutmain(argc, argv,640,480,"Bullet Physics Demo. http://www.continuousphysics.com/Bullet/phpBB2/"); }
void CorrespondTemplates::computeMappings(char * outfileMappingTet, char * outfileMappingSurf, g_Node * contactPoint) { //Compute the mappings using barycentric coordinates findSurfaceNodes(); maptet2surfID = surfaceNodes; // output tetmesh surface computeSurface( "tet_mesh_surf.wrl" ); deformVolumetricMeshRigidly(); int i, j, k, numNodesTet, numElemsTet, numNodesSurf, numElemsSurf; double dist, minDist, d, mind, distContactPoint, minDistContactPoint; numNodesTet = volumetricMeshNodes.numberOfItems(); numElemsTet = trianglesOnSurface.size(); numNodesSurf = rigidlyAlignedSurfaceTemplate->getNumberOfNodes(); numElemsSurf = rigidlyAlignedSurfaceTemplate->getNumberOfTriangles(); //First compute the mapping from the tetrahedral mesh to the surface mesh mappingIndicesTet.resize(3*numNodesTet); mappingWeightsTet.resize(3*numNodesTet); offsetsTet.resize(numNodesTet); for(i = 0; i < numNodesTet; i++) { if(surfaceNodes[i] == -1) { mappingIndicesTet[3*i] = mappingIndicesTet[3*i+1] = mappingIndicesTet[3*i+2] = -1; mappingWeightsTet[3*i] = mappingWeightsTet[3*i+1] = mappingWeightsTet[3*i+2] = -1; } else { for(j = 0; j < numElemsSurf; j++) { // g_Vector closestPoint = computeClosestPoint(volumetricMeshNodes[i], rigidlyAlignedSurfaceTemplate->elements()[j]); // dist = closestPoint.DistanceTo(volumetricMeshNodes[i]->coordinate()); g_Vector closestPoint; dist = computeClosestPoint(*volumetricMeshNodes[i], *rigidlyAlignedSurfaceTemplate->elements()[j], closestPoint ); dist = sqrt(dist); if((j == 0) || (dist < minDist)) { minDist = dist; mappingIndicesTet[3*i] = rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[0]->id()-1; mappingIndicesTet[3*i+1] = rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[1]->id()-1; mappingIndicesTet[3*i+2] = rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[2]->id()-1; //---------------------- for(int n = 0; n < 3; n++){ d = volumetricMeshNodes[i]->coordinate().DistanceTo(rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[n]->coordinate()); if((n == 0) || (d < mind)){ mind = d; maptet2surfID[i] = rigidlyAlignedSurfaceTemplate->elements()[j]->nodes()[n]->id()-1; } } //------------------------ vector<double> barycentrics = computeBarycentrics(volumetricMeshNodes[i]->coordinate(), closestPoint, rigidlyAlignedSurfaceTemplate->elements()[j]); mappingWeightsTet[3*i] = barycentrics[0]; mappingWeightsTet[3*i+1] = barycentrics[1]; mappingWeightsTet[3*i+2] = barycentrics[2]; offsetsTet[i] = barycentrics[3]; } } } } //Export if(outfileMappingTet != NULL) { #if 0 FILE * fp = fopen(outfileMappingTet, "w"); if(fp == NULL) { cout<<"Problem writing "<<outfileMappingTet<<endl; return; } for(i = 0; i < numNodesTet; i++) fprintf(fp, "%d %d %d %f %f %f %f\n", mappingIndicesTet[3*i], mappingIndicesTet[3*i+1], mappingIndicesTet[3*i+2], mappingWeightsTet[3*i], mappingWeightsTet[3*i+1], mappingWeightsTet[3*i+2], offsetsTet[i]); fclose(fp); #else // Make a surface mesh using the tetmesh surface plus the coordinates from the surface mesh computeSurface( outfileMappingTet, true ); #endif } //Second compute the mapping from the surface mesh to the tetrahedral mesh mappingIndicesSurf.resize(3*numNodesSurf); mappingWeightsSurf.resize(3*numNodesSurf); offsetsSurf.resize(numNodesSurf); contactTriangleId.resize(3); contactWeights.resize(3); contactoffset.resize(1); for(i = 0; i < numNodesSurf; i++) { for(j = 0; j < numElemsTet; j++) { g_Element elem; set<int>::iterator triangleIt; for(triangleIt = trianglesOnSurface[j].begin(); triangleIt != trianglesOnSurface[j].end(); triangleIt++) elem.node(volumetricMeshNodes[*triangleIt]); // g_Vector closestPoint = computeClosestPoint(rigidlyAlignedSurfaceTemplate->nodes()[i], &elem); // dist = closestPoint.DistanceTo(rigidlyAlignedSurfaceTemplate->nodes()[i]->coordinate()); g_Vector closestPoint; dist = computeClosestPoint(*rigidlyAlignedSurfaceTemplate->nodes()[i], elem, closestPoint ); dist = sqrt(dist); if((j == 0) || (dist < minDist)) { minDist = dist; k = 0; for(triangleIt = trianglesOnSurface[j].begin(); triangleIt != trianglesOnSurface[j].end(); triangleIt++, k++) mappingIndicesSurf[3*i+k] = *triangleIt; vector<double> barycentrics = computeBarycentrics(rigidlyAlignedSurfaceTemplate->nodes()[i]->coordinate(), closestPoint, &elem); mappingWeightsSurf[3*i] = barycentrics[0]; mappingWeightsSurf[3*i+1] = barycentrics[1]; mappingWeightsSurf[3*i+2] = barycentrics[2]; offsetsSurf[i] = barycentrics[3]; } //--------------------------- if(i == 0 && contactPoint != NULL){ g_Vector closestContactPoint; distContactPoint = computeClosestPoint(*contactPoint, elem, closestContactPoint ); distContactPoint = sqrt(distContactPoint); // g_Vector closestContactPoint = computeClosestPoint(contactPoint, &elem); // distContactPoint = closestContactPoint.DistanceTo(contactPoint->coordinate()); if((j == 0) || (distContactPoint < minDistContactPoint)) { minDistContactPoint = distContactPoint; k = 0; for(triangleIt = trianglesOnSurface[j].begin(); triangleIt != trianglesOnSurface[j].end(); triangleIt++, k++) contactTriangleId[3*i+k] = *triangleIt; vector<double> barycentricsContactPoint = computeBarycentrics(contactPoint->coordinate(), closestContactPoint, &elem); contactWeights[3*i] = barycentricsContactPoint[0]; contactWeights[3*i+1] = barycentricsContactPoint[1]; contactWeights[3*i+2] = barycentricsContactPoint[2]; contactoffset[i] = barycentricsContactPoint[3]; } } //---------------------------- } } //Export if(outfileMappingSurf != NULL) { #if 0 FILE * fp = fopen(outfileMappingSurf, "w"); if(fp == NULL) { cout<<"Problem writing "<<outfileMappingSurf<<endl; return; } for(i = 0; i < numNodesSurf; i++) fprintf(fp, "%d %d %d %f %f %f %f\n", mappingIndicesSurf[3*i], mappingIndicesSurf[3*i+1], mappingIndicesSurf[3*i+2], mappingWeightsSurf[3*i], mappingWeightsSurf[3*i+1], mappingWeightsSurf[3*i+2], offsetsSurf[i]); fclose(fp); #else // Make a surface mesh using the tetmesh surface plus the coordinates from the surface mesh TriangleMesh surfTet; for (int i=0; i<numNodesSurf; ++i ) { // std::cerr << i << " " << std::endl; g_Vector coord = mappingWeightsSurf[3*i] * volumetricMeshNodes[mappingIndicesSurf[3*i]]->coordinate(); coord += mappingWeightsSurf[3*i+1] * volumetricMeshNodes[mappingIndicesSurf[3*i+1]]->coordinate(); coord += mappingWeightsSurf[3*i+2] * volumetricMeshNodes[mappingIndicesSurf[3*i+2]]->coordinate(); surfTet.node(new g_Node( coord )); } // std::cerr << std::endl; g_ElementContainer eleSurf = rigidlyAlignedSurfaceTemplate->elements(); g_NodeContainer newNodes = surfTet.nodes(); for ( g_ElementContainer::const_iterator fIt=eleSurf.begin(); fIt != eleSurf.end(); ++fIt ) { g_Element *ele = new g_Element(); g_NodeContainer faceNodes = (*fIt)->nodes(); for ( g_NodeContainer::const_iterator nIt = faceNodes.begin(); nIt != faceNodes.end(); ++nIt ) { ele->node(newNodes[(*nIt)->id()-1]); } surfTet.element(ele); } exportMeshWrapper( outfileMappingSurf, &surfTet ); #endif } }
TriangleMesh * CorrespondTemplates::computeSurface(char * exportFilename, bool useMapping) { int i, j, counter, numTetNodes; TriangleMesh * resultMesh = new TriangleMesh(); vector<int> surfaceIds; //Find the surface: findSurfaceNodes(); numTetNodes = volumetricMeshNodes.numberOfItems(); surfaceIds.resize(numTetNodes); g_NodeContainer nodesSurf; if ( useMapping ) nodesSurf = rigidlyAlignedSurfaceTemplate->nodes(); //Add the nodes: counter = 0; for(i = 0; i < numTetNodes; i++) { if(surfaceNodes[i] == -1) surfaceIds[i] = -1; else { surfaceIds[i] = counter; counter++; g_Vector coord; if ( useMapping ) { coord = mappingWeightsTet[3*i] * nodesSurf[mappingIndicesTet[3*i]]->coordinate(); coord += mappingWeightsTet[3*i+1] * nodesSurf[mappingIndicesTet[3*i+1]]->coordinate(); coord += mappingWeightsTet[3*i+2] * nodesSurf[mappingIndicesTet[3*i+2]]->coordinate(); } else { coord = volumetricMeshNodes[i]->coordinate(); } g_Node * newNode = new g_Node(coord); resultMesh->node(newNode); } } //Add the triangles (find the correct orientation): for(i = 0; i < trianglesOnSurface.size(); i++) { g_Element * elem = new g_Element(); for(j = 0; j < allTetrahedra.size(); j++) { set<int> triangle; triangle.insert(allTetrahedra[j][0]); triangle.insert(allTetrahedra[j][1]); triangle.insert(allTetrahedra[j][2]); if(trianglesOnSurface[i] == triangle) { elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][0]]]); elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][2]]]); elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][1]]]); break; } triangle.clear(); triangle.insert(allTetrahedra[j][0]); triangle.insert(allTetrahedra[j][1]); triangle.insert(allTetrahedra[j][3]); if(trianglesOnSurface[i] == triangle) { elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][0]]]); elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][1]]]); elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][3]]]); break; } triangle.clear(); triangle.insert(allTetrahedra[j][0]); triangle.insert(allTetrahedra[j][2]); triangle.insert(allTetrahedra[j][3]); if(trianglesOnSurface[i] == triangle) { elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][0]]]); elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][3]]]); elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][2]]]); break; } triangle.clear(); triangle.insert(allTetrahedra[j][1]); triangle.insert(allTetrahedra[j][2]); triangle.insert(allTetrahedra[j][3]); if(trianglesOnSurface[i] == triangle) { elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][1]]]); elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][2]]]); elem->node(resultMesh->nodes()[surfaceIds[allTetrahedra[j][3]]]); break; } } resultMesh->element(elem); } //Export: if(exportFilename != NULL) { exportMeshWrapper(exportFilename, resultMesh); } return resultMesh; }
virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroid += vertex0; centroid += vertex1; centroid += vertex2; } } centroid *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } bool isDynamic = true; float mass = 1.f; CollisionShape* convexShape = new ConvexTriangleMeshShape(trimesh); SimdTransform trans; trans.setIdentity(); trans.setOrigin(centroid); m_convexDemo->LocalCreatePhysicsObject(isDynamic, mass, trans,convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } }
void ConvexDecompositionDemo::initPhysics(const char* filename) { ConvexDecomposition::WavefrontObj wo; tcount = wo.loadObj(filename); CollisionDispatcher* dispatcher = new CollisionDispatcher(); SimdVector3 worldAabbMin(-10000,-10000,-10000); SimdVector3 worldAabbMax(10000,10000,10000); OverlappingPairCache* broadphase = new AxisSweep3(worldAabbMin,worldAabbMax); //OverlappingPairCache* broadphase = new SimpleBroadphase(); m_physicsEnvironmentPtr = new CcdPhysicsEnvironment(dispatcher,broadphase); m_physicsEnvironmentPtr->setDeactivationTime(2.f); m_physicsEnvironmentPtr->setGravity(0,-10,0); SimdTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(SimdVector3(0,-4,0)); LocalCreatePhysicsObject(false,0,startTransform,new BoxShape(SimdVector3(30,2,30))); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { ConvexDecompositionDemo* m_convexDemo; public: MyConvexDecomposition (FILE* outputFile,ConvexDecompositionDemo* demo) :m_convexDemo(demo), mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroid += vertex0; centroid += vertex1; centroid += vertex2; } } centroid *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } bool isDynamic = true; float mass = 1.f; CollisionShape* convexShape = new ConvexTriangleMeshShape(trimesh); SimdTransform trans; trans.setIdentity(); trans.setOrigin(centroid); m_convexDemo->LocalCreatePhysicsObject(isDynamic, mass, trans,convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); for (int i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; SimdVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); SimdVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); SimdVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->AddTriangle(vertex0,vertex1,vertex2); } CollisionShape* convexShape = new ConvexTriangleMeshShape(trimesh); bool isDynamic = true; float mass = 1.f; SimdTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(SimdVector3(20,2,0)); LocalCreatePhysicsObject(isDynamic, mass, startTransform,convexShape); } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 7; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.01; printf("WavefrontObj num triangles read %i",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile,this); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); cb.process(desc); if (outputFile) fclose(outputFile); } m_physicsEnvironmentPtr->setDebugDrawer(&debugDrawer); }
////////////////////////////////////////////////////////// // // MeshSweeper implementation // =========== // TriangleMesh* MeshSweeper::makeCylinder( const Polyline& circle, const vec3& path, const mat4& m) //[]----------------------------------------------------[] //| Make cylinder | //[]----------------------------------------------------[] { int np = circle.getNumberOfVertices(); int nv = np * 2; // number of vertices int nb = np - 2; // number of triangles of the base int nt = nv + 2 * nb; // number of triangles TriangleMesh::Arrays data; data.vertices = new vec3[data.numberOfVertices = nv]; data.triangles = new TriangleMesh::Triangle[data.numberOfTriangles = nt]; vec3 c(0, 0, 0); if (true) { Polyline::VertexIterator vit(circle.getVertexIterator()); for (int i = 0; i < np; i++) { const vec3& p = vit++.position; c += p; data.vertices[i + np] = m.transform3x4(p); data.vertices[i] = m.transform3x4(p + path); } c *= Math::inverse(REAL(np)); } TriangleMesh::Triangle* triangle = data.triangles; for (int i = 0; i < np; i++) { int j = (i + np); int k = (i + 1) % np; triangle->setVertices(i, j, k); triangle[1].setVertices(j, k + np, k); triangle += 2; } int v0 = 0; int v1 = 1; int v2 = 2; for (int i = 0; i < nb; i++) { triangle->setVertices(v0, v1, v2); triangle[nb].setVertices(v0 + np, v2 + np, v1 + np); triangle++; v2 = ((v1 = (v0 = v2) + 1) + 1) % np; } TriangleMesh* mesh = new TriangleMesh(data); mesh->computeNormals(); return mesh; }
int main(const int argc, const char **argv) { // parse all command line options into a DynamicConfig ConfigDef config_def; config_def.merge(cli_config_def); config_def.merge(print_config_def); DynamicConfig config(&config_def); t_config_option_keys input_files; config.read_cli(argc, argv, &input_files); // apply command line options to a more handy CLIConfig CLIConfig cli_config; cli_config.apply(config, true); DynamicPrintConfig print_config; // load config files supplied via --load for (std::vector<std::string>::const_iterator file = cli_config.load.values.begin(); file != cli_config.load.values.end(); ++file) { if (!boost::filesystem::exists(*file)) { std::cout << "No such file: " << *file << std::endl; exit(1); } DynamicPrintConfig c; try { c.load(*file); } catch (std::exception &e) { std::cout << "Error while reading config file: " << e.what() << std::endl; exit(1); } c.normalize(); print_config.apply(c); } // apply command line options to a more specific DynamicPrintConfig which provides normalize() // (command line options override --load files) print_config.apply(config, true); print_config.normalize(); // write config if requested if (!cli_config.save.value.empty()) print_config.save(cli_config.save.value); // read input file(s) if any std::vector<Model> models; for (t_config_option_keys::const_iterator it = input_files.begin(); it != input_files.end(); ++it) { if (!boost::filesystem::exists(*it)) { std::cout << "No such file: " << *it << std::endl; exit(1); } Model model; // TODO: read other file formats with Model::read_from_file() try { Slic3r::IO::STL::read(*it, &model); } catch (std::exception &e) { std::cout << *it << ": " << e.what() << std::endl; exit(1); } if (model.objects.empty()) { printf("Error: file is empty: %s\n", it->c_str()); continue; } model.add_default_instances(); // apply command line transform options for (ModelObjectPtrs::iterator o = model.objects.begin(); o != model.objects.end(); ++o) { if (cli_config.scale_to_fit.is_positive_volume()) (*o)->scale_to_fit(cli_config.scale_to_fit.value); (*o)->scale(cli_config.scale.value); (*o)->rotate(cli_config.rotate.value, Z); } // TODO: handle --merge models.push_back(model); } for (std::vector<Model>::iterator model = models.begin(); model != models.end(); ++model) { if (cli_config.info) { // --info works on unrepaired model model->print_info(); } else if (cli_config.export_obj) { std::string outfile = cli_config.output.value; if (outfile.empty()) outfile = model->objects.front()->input_file + ".obj"; TriangleMesh mesh = model->mesh(); mesh.repair(); Slic3r::IO::OBJ::write(mesh, outfile); printf("File exported to %s\n", outfile.c_str()); } else if (cli_config.export_pov) { std::string outfile = cli_config.output.value; if (outfile.empty()) outfile = model->objects.front()->input_file + ".pov"; TriangleMesh mesh = model->mesh(); mesh.repair(); Slic3r::IO::POV::write(mesh, outfile); printf("File exported to %s\n", outfile.c_str()); } else if (cli_config.export_svg) { std::string outfile = cli_config.output.value; if (outfile.empty()) outfile = model->objects.front()->input_file + ".svg"; SLAPrint print(&*model); print.config.apply(print_config, true); print.slice(); print.write_svg(outfile); printf("SVG file exported to %s\n", outfile.c_str()); } else { std::cerr << "error: only --export-svg and --export-obj are currently supported" << std::endl; return 1; } } return 0; }
//----------------------------------------------------------------------------- // BoundaryMap private method definitions //----------------------------------------------------------------------------- void BoundaryMap::computeSignedDistanceField(SparseVoxelMap<float*>& map, const TriangleMesh& mesh) { const float* vertexList = mesh.getVertexList(); const unsigned int* faceList = mesh.getFaceList(); const float *v1, *v2, *v3; unsigned int cMin[3]; unsigned int cMax[3]; float x0 = mDomain.getV1().getX(); float y0 = mDomain.getV1().getY(); float z0 = mDomain.getV1().getZ(); float x[3]; float normal[3]; float dist; // // compute distance // // for each triangle of the mesh for (unsigned int m = 0; m < mesh.getNumFaces(); m++) { std::cout << m << " of " << mesh.getNumFaces() << std::endl; //get triangle vertices v1 = &vertexList[3*faceList[3*m + 0]]; v2 = &vertexList[3*faceList[3*m + 1]]; v3 = &vertexList[3*faceList[3*m + 2]]; // compute bounding box of the triangle this->computeGridCoordinates(cMin, cMax, v1, v2, v3); //std::cout << "cMin[0] = " << cMin[0] << std::endl; //std::cout << "cMin[1] = " << cMin[1] << std::endl; //std::cout << "cMin[2] = " << cMin[2] << std::endl; //std::cout << "cMax[0] = " << cMax[0] << std::endl; //std::cout << "cMax[1] = " << cMax[1] << std::endl; //std::cout << "cMax[2] = " << cMax[2] << std::endl; // for each coordinate within the bounding box for (unsigned int k = cMin[2]; k <= cMax[2]; k++) { for (unsigned int j = cMin[1]; j <= cMax[1]; j++) { for (unsigned int i = cMin[0]; i <= cMax[0]; i++) { // translate coordinate to world coordinates x[0] = x0 + i*mDx; x[1] = y0 + j*mDx; x[2] = z0 + k*mDx; // compute distance to the triangle compute_distance_point_triangle(dist, normal, x, v1, v2, v3); // update sparse voxel map if (dist <= mMaxDist) { Coordinate coord(i, j, k); // if the map already contains distance information // at the current coordinate if (map.contains(coord)) { // check if the previously computed distance is // is greater than [dist]. float prev; float* nodeContent; map.get(nodeContent, coord); prev = nodeContent[NC_DISTANCE]; if (prev > dist) { // if yes, update the map delete[] nodeContent; nodeContent = new float[NC_NUM_ELEMENTS]; nodeContent[NC_DISTANCE] = dist; nodeContent[NC_NORMAL_X] = normal[0]; nodeContent[NC_NORMAL_Y] = normal[1]; nodeContent[NC_NORMAL_Z] = normal[2]; map.add(coord, nodeContent); } } // if not yet contained in the map else { float* nodeContent = new float[NC_NUM_ELEMENTS]; nodeContent[NC_DISTANCE] = dist; nodeContent[NC_NORMAL_X] = normal[0]; nodeContent[NC_NORMAL_Y] = normal[1]; nodeContent[NC_NORMAL_Z] = normal[2]; //std::cout << dist << std::endl; // just add val to the map map.add(coord, nodeContent); } } } } } } // // compute sign of distance // std::cout << "point in mesh test" << std::endl; PointInMeshTest test(mesh, 20); // for each coordinate in the signed distance field std::list<Coordinate>::const_iterator& it = mNodeContents.begin(); std::list<Coordinate>::const_iterator& end = mNodeContents.end(); Coordinate c; for (; it != end; it++) { // translate coordinate to world coordinate c = *it; x[0] = x0 + c.i*mDx; x[1] = y0 + c.j*mDx; x[2] = z0 + c.k*mDx; // if [x] is inside the mesh if (test.isContained(Vector3f(x[0], x[1], x[2]))) { // negate the distances in the signed distance field float* nodeContent; mNodeContents.get(nodeContent, c); nodeContent[NC_DISTANCE] = -nodeContent[NC_DISTANCE]; } } std::cout << "point in mesh test finished" << std::endl; }
void simplifyMesh(TriangleMesh &src, TriangleMesh &dst){ namespace SMS = CGAL::Surface_mesh_simplification; Surface surface; PolyhedronBuilder<HalfedgeDS> builder(src.points, src.facets); surface.delegate(builder); // --- before mesh simplification, to maintain mesh quality high poisson surface reconstruction is applied --- // This is a stop predicate (defines when the algorithm terminates). // In this example, the simplification stops when the number of undirected edges // left in the surface drops below the specified number (1000) // SMS::Count_stop_predicate<Surface> stop(3000); //SMS::Count_ratio_stop_predicate<Surface> stop(0.1); SMS::Count_stop_predicate<Surface> stop(100); // This the actual call to the simplification algorithm. // The surface and stop conditions are mandatory arguments. // The index maps are needed because the vertices and edges // of this surface lack an "id()" field. int r = SMS::edge_collapse (surface ,stop ,CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index, surface)) .edge_index_map(boost::get(CGAL::edge_external_index, surface)) .get_cost(CGAL::Surface_mesh_simplification::Edge_length_cost<Polyhedron>()) .get_placement(CGAL::Surface_mesh_simplification::Midpoint_placement<Polyhedron>()) //.get_cost(CGAL::Surface_mesh_simplification::LindstromTurk_cost<Polyhedron>()) //.get_placement(CGAL::Surface_mesh_simplification::LindstromTurk_placement<Polyhedron>()) ); std::cout << "\nFinished...\n" << r << " edges removed.\n" << (surface.size_of_halfedges()/2) << " final edges.\n" ; std::vector<Eigen::Vector3d> points; std::vector<std::vector<int> > faces; points.resize(surface.size_of_vertices()); faces.resize(surface.size_of_facets()); Polyhedron::Point_iterator pit; int index = 0; for(pit=surface.points_begin(); pit!=surface.points_end(); ++pit){ points[index][0] = pit->x(); points[index][1] = pit->y(); points[index][2] = pit->z(); index ++; } index = 0; Polyhedron::Face_iterator fit; for(fit=surface.facets_begin(); fit!=surface.facets_end(); ++fit){ std::vector<int > face(3); Halfedge_facet_circulator j = fit->facet_begin(); int f_index = 0; do { face[f_index] = std::distance(surface.vertices_begin(), j->vertex()); f_index++; } while ( ++j != fit->facet_begin()); faces[index] = face; index++; } dst.createFromFaceVertex(points, faces); }
void setup_vertex_position_buffer_object(void) { glGenBuffers(1, &vertex_position_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_position_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * trig.VertexCount(), &trig.Vertices()[0], GL_STATIC_DRAW); }
void SLAPrint::slice() { TriangleMesh mesh = this->model->mesh(); mesh.repair(); // align to origin taking raft into account this->bb = mesh.bounding_box(); if (this->config.raft_layers > 0) { this->bb.min.x -= this->config.raft_offset.value; this->bb.min.y -= this->config.raft_offset.value; this->bb.max.x += this->config.raft_offset.value; this->bb.max.y += this->config.raft_offset.value; } mesh.translate(0, 0, -bb.min.z); this->bb.translate(0, 0, -bb.min.z); // if we are generating a raft, first_layer_height will not affect mesh slicing const float lh = this->config.layer_height.value; const float first_lh = this->config.first_layer_height.value; // generate the list of Z coordinates for mesh slicing // (we slice each layer at half of its thickness) this->layers.clear(); { const float first_slice_lh = (this->config.raft_layers > 0) ? lh : first_lh; this->layers.push_back(Layer(first_slice_lh/2, first_slice_lh)); } while (this->layers.back().print_z + lh/2 <= mesh.stl.stats.max.z) { this->layers.push_back(Layer(this->layers.back().print_z + lh/2, this->layers.back().print_z + lh)); } // perform slicing and generate layers { std::vector<float> slice_z; for (size_t i = 0; i < this->layers.size(); ++i) slice_z.push_back(this->layers[i].slice_z); std::vector<ExPolygons> slices; TriangleMeshSlicer(&mesh).slice(slice_z, &slices); for (size_t i = 0; i < slices.size(); ++i) this->layers[i].slices.expolygons = slices[i]; } // generate infill if (this->config.fill_density < 100) { std::auto_ptr<Fill> fill(Fill::new_from_type(this->config.fill_pattern.value)); fill->bounding_box.merge(Point::new_scale(bb.min.x, bb.min.y)); fill->bounding_box.merge(Point::new_scale(bb.max.x, bb.max.y)); fill->spacing = this->config.get_abs_value("infill_extrusion_width", this->config.layer_height.value); fill->angle = Geometry::deg2rad(this->config.fill_angle.value); fill->density = this->config.fill_density.value/100; parallelize<size_t>( 0, this->layers.size()-1, boost::bind(&SLAPrint::_infill_layer, this, _1, fill.get()), this->config.threads.value ); } // generate support material this->sm_pillars.clear(); ExPolygons overhangs; if (this->config.support_material) { // flatten and merge all the overhangs { Polygons pp; for (std::vector<Layer>::const_iterator it = this->layers.begin()+1; it != this->layers.end(); ++it) pp += diff(it->slices, (it - 1)->slices); overhangs = union_ex(pp); } // generate points following the shape of each island Points pillars_pos; const coordf_t spacing = scale_(this->config.support_material_spacing); const coordf_t radius = scale_(this->sm_pillars_radius()); for (ExPolygons::const_iterator it = overhangs.begin(); it != overhangs.end(); ++it) { // leave a radius/2 gap between pillars and contour to prevent lateral adhesion for (float inset = radius * 1.5;; inset += spacing) { // inset according to the configured spacing Polygons curr = offset(*it, -inset); if (curr.empty()) break; // generate points along the contours for (Polygons::const_iterator pg = curr.begin(); pg != curr.end(); ++pg) { Points pp = pg->equally_spaced_points(spacing); for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p) pillars_pos.push_back(*p); } } } // for each pillar, check which layers it applies to for (Points::const_iterator p = pillars_pos.begin(); p != pillars_pos.end(); ++p) { SupportPillar pillar(*p); bool object_hit = false; // check layers top-down for (int i = this->layers.size()-1; i >= 0; --i) { // check whether point is void in this layer if (!this->layers[i].slices.contains(*p)) { // no slice contains the point, so it's in the void if (pillar.top_layer > 0) { // we have a pillar, so extend it pillar.bottom_layer = i + this->config.raft_layers; } else if (object_hit) { // we don't have a pillar and we're below the object, so create one pillar.top_layer = i + this->config.raft_layers; } } else { if (pillar.top_layer > 0) { // we have a pillar which is not needed anymore, so store it and initialize a new potential pillar this->sm_pillars.push_back(pillar); pillar = SupportPillar(*p); } object_hit = true; } } if (pillar.top_layer > 0) this->sm_pillars.push_back(pillar); } } // generate a solid raft if requested // (do this after support material because we take support material shape into account) if (this->config.raft_layers > 0) { ExPolygons raft = this->layers.front().slices + overhangs; // take support material into account raft = offset_ex(raft, scale_(this->config.raft_offset)); for (int i = this->config.raft_layers; i >= 1; --i) { this->layers.insert(this->layers.begin(), Layer(0, first_lh + lh * (i-1))); this->layers.front().slices = raft; } // prepend total raft height to all sliced layers for (size_t i = this->config.raft_layers; i < this->layers.size(); ++i) this->layers[i].print_z += first_lh + lh * (this->config.raft_layers-1); } }
int main(int argc,char** argv) { setCameraDistance(30.f); #define TRISIZE 10.f #ifdef DEBUG_MESH SimdVector3 vert0(-TRISIZE ,0,TRISIZE ); SimdVector3 vert1(TRISIZE ,10,TRISIZE ); SimdVector3 vert2(TRISIZE ,0,-TRISIZE ); meshData.AddTriangle(vert0,vert1,vert2); SimdVector3 vert3(-TRISIZE ,0,TRISIZE ); SimdVector3 vert4(TRISIZE ,0,-TRISIZE ); SimdVector3 vert5(-TRISIZE ,0,-TRISIZE ); meshData.AddTriangle(vert3,vert4,vert5); #else #ifdef ODE_MESH SimdVector3 Size = SimdVector3(15.f,15.f,12.5f); gVertices[0][0] = -Size[0]; gVertices[0][1] = Size[2]; gVertices[0][2] = -Size[1]; gVertices[1][0] = Size[0]; gVertices[1][1] = Size[2]; gVertices[1][2] = -Size[1]; gVertices[2][0] = Size[0]; gVertices[2][1] = Size[2]; gVertices[2][2] = Size[1]; gVertices[3][0] = -Size[0]; gVertices[3][1] = Size[2]; gVertices[3][2] = Size[1]; gVertices[4][0] = 0; gVertices[4][1] = 0; gVertices[4][2] = 0; gIndices[0] = 0; gIndices[1] = 1; gIndices[2] = 4; gIndices[3] = 1; gIndices[4] = 2; gIndices[5] = 4; gIndices[6] = 2; gIndices[7] = 3; gIndices[8] = 4; gIndices[9] = 3; gIndices[10] = 0; gIndices[11] = 4; int vertStride = sizeof(SimdVector3); int indexStride = 3*sizeof(int); TriangleIndexVertexArray* indexVertexArrays = new TriangleIndexVertexArray(NUM_TRIANGLES, gIndices, indexStride, NUM_VERTICES,(float*) &gVertices[0].x(),vertStride); //shapePtr[4] = new TriangleMeshShape(indexVertexArrays); shapePtr[4] = new BvhTriangleMeshShape(indexVertexArrays); #else int vertStride = sizeof(SimdVector3); int indexStride = 3*sizeof(int); const int NUM_VERTS_X = 50; const int NUM_VERTS_Y = 50; const int totalVerts = NUM_VERTS_X*NUM_VERTS_Y; const int totalTriangles = 2*(NUM_VERTS_X-1)*(NUM_VERTS_Y-1); SimdVector3* gVertices = new SimdVector3[totalVerts]; int* gIndices = new int[totalTriangles*3]; int i; for ( i=0;i<NUM_VERTS_X;i++) { for (int j=0;j<NUM_VERTS_Y;j++) { gVertices[i+j*NUM_VERTS_X].setValue((i-NUM_VERTS_X*0.5f)*10.f,2.f*sinf((float)i)*cosf((float)j),(j-NUM_VERTS_Y*0.5f)*10.f); } } int index=0; for ( i=0;i<NUM_VERTS_X-1;i++) { for (int j=0;j<NUM_VERTS_Y-1;j++) { gIndices[index++] = j*NUM_VERTS_X+i; gIndices[index++] = j*NUM_VERTS_X+i+1; gIndices[index++] = (j+1)*NUM_VERTS_X+i+1; gIndices[index++] = j*NUM_VERTS_X+i; gIndices[index++] = (j+1)*NUM_VERTS_X+i+1; gIndices[index++] = (j+1)*NUM_VERTS_X+i; } } TriangleIndexVertexArray* indexVertexArrays = new TriangleIndexVertexArray(totalTriangles, gIndices, indexStride, totalVerts,(float*) &gVertices[0].x(),vertStride); //shapePtr[4] = new TriangleMeshShape(indexVertexArrays); shapePtr[4] = new BvhTriangleMeshShape(indexVertexArrays); #endif #endif//DEBUG_MESH // GLDebugDrawer debugDrawer; //ConstraintSolver* solver = new SimpleConstraintSolver; ConstraintSolver* solver = new OdeConstraintSolver; CollisionDispatcher* dispatcher = new CollisionDispatcher(); BroadphaseInterface* broadphase = new SimpleBroadphase(); physicsEnvironmentPtr = new CcdPhysicsEnvironment(dispatcher,broadphase); physicsEnvironmentPtr->setGravity(-1,-10,1); PHY_ShapeProps shapeProps; shapeProps.m_do_anisotropic = false; shapeProps.m_do_fh = false; shapeProps.m_do_rot_fh = false; shapeProps.m_friction_scaling[0] = 1.; shapeProps.m_friction_scaling[1] = 1.; shapeProps.m_friction_scaling[2] = 1.; shapeProps.m_inertia = 1.f; shapeProps.m_lin_drag = 0.95999998f; shapeProps.m_ang_drag = 0.89999998f; shapeProps.m_mass = 1.0f; PHY_MaterialProps materialProps; materialProps.m_friction = 0.f;// 50.5f; materialProps.m_restitution = 0.1f; CcdConstructionInfo ccdObjectCi; ccdObjectCi.m_friction = 0.f;//50.5f; ccdObjectCi.m_linearDamping = shapeProps.m_lin_drag; ccdObjectCi.m_angularDamping = shapeProps.m_ang_drag; SimdTransform tr; tr.setIdentity(); for (i=0;i<numObjects;i++) { if (i>0) shapeIndex[i] = 1;//2 = tetrahedron else shapeIndex[i] = 4; } for (i=0;i<numObjects;i++) { shapeProps.m_shape = shapePtr[shapeIndex[i]]; bool isDyna = i>0; if (!i) { //SimdQuaternion orn(0,0,0.1*SIMD_HALF_PI); //ms[i].setWorldOrientation(orn.x(),orn.y(),orn.z(),orn[3]); //ms[i].setWorldPosition(0,-10,0); } else { ms[i].setWorldPosition(10,i*15-10,0); } //either create a few stacks, to show several islands, or create 1 large stack, showing stability //ms[i].setWorldPosition((i*5) % 30,i*15-10,0); ccdObjectCi.m_MotionState = &ms[i]; ccdObjectCi.m_gravity = SimdVector3(0,0,0); ccdObjectCi.m_localInertiaTensor =SimdVector3(0,0,0); if (!isDyna) { shapeProps.m_mass = 0.f; ccdObjectCi.m_mass = shapeProps.m_mass; } else { shapeProps.m_mass = 1.f; ccdObjectCi.m_mass = shapeProps.m_mass; } SimdVector3 localInertia; if (shapeProps.m_mass>0.f) { shapePtr[shapeIndex[i]]->CalculateLocalInertia(shapeProps.m_mass,localInertia); } else { localInertia.setValue(0.f,0.f,0.f); } ccdObjectCi.m_localInertiaTensor = localInertia; ccdObjectCi.m_collisionShape = shapePtr[shapeIndex[i]]; physObjects[i]= new CcdPhysicsController( ccdObjectCi); physicsEnvironmentPtr->addCcdPhysicsController( physObjects[i]); /* if (i==0) { physObjects[i]->SetAngularVelocity(0,0,-2,true); physObjects[i]->GetRigidBody()->setDamping(0,0); } */ //for the line that represents the AABB extents // physicsEnvironmentPtr->setDebugDrawer(&debugDrawer); } return glutmain(argc, argv,640,480,"Static Concave Mesh Demo"); }
void SpatialSplit::Split::split<false>(size_t threadIndex, size_t threadCount, LockStepTaskScheduler* scheduler, PrimRefBlockAlloc<PrimRef>& alloc, Scene* scene, TriRefList& prims, TriRefList& lprims_o, PrimInfo& linfo_o, TriRefList& rprims_o, PrimInfo& rinfo_o) const { assert(valid()); TriRefList::item* lblock = lprims_o.insert(alloc.malloc(threadIndex)); TriRefList::item* rblock = rprims_o.insert(alloc.malloc(threadIndex)); linfo_o.reset(); rinfo_o.reset(); /* sort each primitive to left, right, or left and right */ while (atomic_set<PrimRefBlock>::item* block = prims.take()) { for (size_t i=0; i<block->size(); i++) { const PrimRef& prim = block->at(i); const BBox3fa bounds = prim.bounds(); const int bin0 = mapping.bin(bounds.lower)[dim]; const int bin1 = mapping.bin(bounds.upper)[dim]; /* sort to the left side */ if (bin1 < pos) { linfo_o.add(bounds,center2(bounds)); if (likely(lblock->insert(prim))) continue; lblock = lprims_o.insert(alloc.malloc(threadIndex)); lblock->insert(prim); continue; } /* sort to the right side */ if (bin0 >= pos) { rinfo_o.add(bounds,center2(bounds)); if (likely(rblock->insert(prim))) continue; rblock = rprims_o.insert(alloc.malloc(threadIndex)); rblock->insert(prim); continue; } /* split and sort to left and right */ TriangleMesh* mesh = (TriangleMesh*) scene->get(prim.geomID()); TriangleMesh::Triangle tri = mesh->triangle(prim.primID()); const Vec3fa v0 = mesh->vertex(tri.v[0]); const Vec3fa v1 = mesh->vertex(tri.v[1]); const Vec3fa v2 = mesh->vertex(tri.v[2]); PrimRef left,right; float fpos = mapping.pos(pos,dim); splitTriangle(prim,dim,fpos,v0,v1,v2,left,right); if (!left.bounds().empty()) { linfo_o.add(left.bounds(),center2(left.bounds())); if (!lblock->insert(left)) { lblock = lprims_o.insert(alloc.malloc(threadIndex)); lblock->insert(left); } } if (!right.bounds().empty()) { rinfo_o.add(right.bounds(),center2(right.bounds())); if (!rblock->insert(right)) { rblock = rprims_o.insert(alloc.malloc(threadIndex)); rblock->insert(right); } } } alloc.free(threadIndex,block); } }
void PoissonSurfaceReconstruction::reconstruct(std::vector<Eigen::Vector3d> &points, std::vector<Eigen::Vector3d> &normals, TriangleMesh &mesh){ assert(points.size() == normals.size()); std::cout << "creating points with normal..." << std::endl; std::vector<Point_with_normal> points_with_normal; points_with_normal.resize((int)points.size()); for(int i=0; i<(int)points.size(); i++){ Vector vec(normals[i][0], normals[i][1], normals[i][2]); //Point_with_normal pwn(points[i][0], points[i][1], points[i][2], vec); //points_with_normal[i] = pwn; points_with_normal[i] = Point_with_normal(points[i][0], points[i][1], points[i][2], vec); } std::cout << "constructing poisson reconstruction function..." << std::endl; Poisson_reconstruction_function function(points_with_normal.begin(), points_with_normal.end(), CGAL::make_normal_of_point_with_normal_pmap(PointList::value_type())); std::cout << "computing implicit function..." << std::endl; if( ! function.compute_implicit_function() ) { std::cout << "compute implicit function is failure" << std::endl; return; } //return EXIT_FAILURE; // Computes average spacing std::cout << "compute average spacing..." << std::endl; FT average_spacing = CGAL::compute_average_spacing(points_with_normal.begin(), points_with_normal.end(), 6 /* knn = 1 ring */); // Gets one point inside the implicit surface // and computes implicit function bounding sphere radius. Point inner_point = function.get_inner_point(); Sphere bsphere = function.bounding_sphere(); FT radius = std::sqrt(bsphere.squared_radius()); // Defines the implicit surface: requires defining a // conservative bounding sphere centered at inner point. FT sm_sphere_radius = 5.0 * radius; FT sm_dichotomy_error = distance_criteria*average_spacing/1000.0; // Dichotomy error must be << sm_distance //FT sm_dichotomy_error = distance_criteria*average_spacing/10.0; // Dichotomy error must be << sm_distance std::cout << "reconstructed surface" << std::endl; Surface_3 reconstructed_surface(function, Sphere(inner_point,sm_sphere_radius*sm_sphere_radius), sm_dichotomy_error/sm_sphere_radius); // Defines surface mesh generation criteria CGAL::Surface_mesh_default_criteria_3<STr> criteria(angle_criteria, // Min triangle angle (degrees) radius_criteria*average_spacing, // Max triangle size distance_criteria*average_spacing); // Approximation error std::cout << "generating surface mesh..." << std::endl; // Generates surface mesh with manifold option STr tr; // 3D Delaunay triangulation for surface mesh generation C2t3 c2t3(tr); // 2D complex in 3D Delaunay triangulation CGAL::make_surface_mesh(c2t3, // reconstructed mesh reconstructed_surface, // implicit surface criteria, // meshing criteria CGAL::Manifold_tag()); // require manifold mesh if(tr.number_of_vertices() == 0){ std::cout << "surface mesh generation is failed" << std::endl; return; } Polyhedron surface; CGAL::output_surface_facets_to_polyhedron(c2t3, surface); // convert CGAL::surface to TriangleMesh // std::cout << "converting CGA::surface to TriangleMesh..." << std::endl; std::vector<Eigen::Vector3d> pts; std::vector<std::vector<int> > faces; pts.resize(surface.size_of_vertices()); faces.resize(surface.size_of_facets()); Polyhedron::Point_iterator pit; int index = 0; for(pit=surface.points_begin(); pit!=surface.points_end(); ++pit){ pts[index][0] = pit->x(); pts[index][1] = pit->y(); pts[index][2] = pit->z(); index ++; } index = 0; Polyhedron::Face_iterator fit; for(fit=surface.facets_begin(); fit!=surface.facets_end(); ++fit){ std::vector<int > face(3); Halfedge_facet_circulator j = fit->facet_begin(); int f_index = 0; do { face[f_index] = std::distance(surface.vertices_begin(), j->vertex()); f_index++; } while ( ++j != fit->facet_begin()); faces[index] = face; index++; } mesh.createFromFaceVertex(pts, faces); }
void display_handler(void) { // clear scene glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1,1,1); shader.Bind(); // pass uniform variables to shader GLint projectionMatrix_location = glGetUniformLocation(shader.ID(), "projectionMatrix"); GLint viewMatrix_location = glGetUniformLocation(shader.ID(), "viewMatrix"); GLint modelMatrix_location = glGetUniformLocation(shader.ID(), "modelMatrix"); GLint normalMatrix_location = glGetUniformLocation(shader.ID(), "normalMatrix"); GLint materialAmbient_location = glGetUniformLocation(shader.ID(), "materialAmbient"); GLint materialDiffuse_location = glGetUniformLocation(shader.ID(), "materialDiffuse"); GLint materialSpecular_location = glGetUniformLocation(shader.ID(), "materialSpecular"); GLint lightPosition_location = glGetUniformLocation(shader.ID(), "lightPosition"); GLint lightAmbient_location = glGetUniformLocation(shader.ID(), "lightAmbient"); GLint lightDiffuse_location = glGetUniformLocation(shader.ID(), "lightDiffuse"); GLint lightSpecular_location = glGetUniformLocation(shader.ID(), "lightSpecular"); GLint lightGlobal_location = glGetUniformLocation(shader.ID(), "lightGlobal"); GLint materialShininess_location = glGetUniformLocation(shader.ID(), "materialShininess"); GLint constantAttenuation_location = glGetUniformLocation(shader.ID(), "constantAttenuation"); GLint linearAttenuation_location = glGetUniformLocation(shader.ID(), "linearAttenuation"); GLint useTexture_location = glGetUniformLocation(shader.ID(), "useTexture"); glUniformMatrix4fv( projectionMatrix_location, 1, GL_FALSE, &projectionMatrix[0][0]); glUniformMatrix4fv( viewMatrix_location, 1, GL_FALSE, &viewMatrix[0][0]); glUniformMatrix4fv( modelMatrix_location, 1, GL_FALSE, &modelMatrix[0][0]); glUniformMatrix3fv( normalMatrix_location, 1, GL_FALSE, &normalMatrix[0][0]); glUniform3fv( materialAmbient_location, 1, materialAmbient); glUniform3fv( materialDiffuse_location, 1, materialDiffuse); glUniform3fv( materialSpecular_location, 1, materialSpecular); glUniform3fv( lightPosition_location, 1, lightPosition); glUniform3fv( lightAmbient_location, 1, lightAmbient); glUniform3fv( lightDiffuse_location, 1, lightDiffuse); glUniform3fv( lightSpecular_location, 1, lightSpecular); glUniform3fv( lightGlobal_location, 1, lightGlobal); glUniform1f( materialShininess_location, materialShininess); glUniform1f( constantAttenuation_location, constantAttenuation); glUniform1f( linearAttenuation_location, linearAttenuation); glUniform1i( useTexture_location, useTexture); // bind texture to shader GLint texture0_location = glGetAttribLocation(shader.ID(), "texture0"); if (texture0_location != -1) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); glUniform1i(texture0_location, 0); } // bind vertex uv coordinates to shader GLint uv_location = glGetAttribLocation(shader.ID(), "vertex_uv"); if (uv_location != -1) { glEnableVertexAttribArray(uv_location); glBindBuffer(GL_ARRAY_BUFFER, vertex_uv_buffer); glVertexAttribPointer(uv_location, 2, GL_FLOAT, GL_FALSE, 0, 0); } // bind vertex positions to shader GLint position_location = glGetAttribLocation(shader.ID(), "vertex_position"); if (position_location != -1) { glEnableVertexAttribArray(position_location); glBindBuffer(GL_ARRAY_BUFFER, vertex_position_buffer); glVertexAttribPointer(position_location, 3, GL_FLOAT, GL_FALSE, 0, 0); } // bind vertex normals to shader GLint normal_location = glGetAttribLocation(shader.ID(), "vertex_normal"); if (normal_location != -1) { glEnableVertexAttribArray(normal_location); glBindBuffer(GL_ARRAY_BUFFER, vertex_normal_buffer); glVertexAttribPointer(normal_location, 3, GL_FLOAT, GL_FALSE, 0, 0); } // draw the scene glDrawArrays(GL_TRIANGLES, 0, trig.VertexCount()); glDisableVertexAttribArray(position_location); glDisableVertexAttribArray(uv_location); glDisableVertexAttribArray(normal_location); shader.Unbind(); glFlush(); }
int main(int argc, char **argv) { atexit(cleanup); // parse arguments char *model_path = NULL; char *vertexshader_path = NULL; char *fragmentshader_path = NULL; char *texture_path = NULL; bool use_smoothed_normals; if (argc >= 6) { texture_path = argv[5]; useTexture = 1; } if (argc >= 5) { model_path = argv[1]; vertexshader_path = argv[2]; fragmentshader_path = argv[3]; use_smoothed_normals = *argv[4] != '0'; } else { std::cerr << "Usage:" << std::endl; std::cerr << argv[0] << " <model::path> " << " <vertex-shader::path> " << " <fragment-shader::path> " << " <smooth-normals::{0,1}>" << " (<texture::path>)" << std::endl; exit(1); } // initialise OpenGL glutInit(&argc, argv); glutInitWindowSize(windowX, windowY); glutCreateWindow("CG-CW1"); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glEnable(GL_DEPTH_TEST); // set display and keyboard callbacks glutDisplayFunc(display_handler); glutKeyboardFunc(keyboard_handler); // initialise the OpenGL Extension Wrangler library for VBOs GLenum err = glewInit(); if (err != GLEW_OK){ std::cerr << "Error!" << std::endl; exit(1); } if (!GLEW_VERSION_2_1) { std::cerr << "Error 2.1!" << std::endl; exit(1); } // create shader, prepare data for OpenGL trig.LoadFile(model_path); shader.Init(vertexshader_path, fragmentshader_path); setup_texture(texture_path, &textureID); setup_vertex_position_buffer_object(); setup_vertex_uv_buffer_object(); setup_vertex_normal_buffer_object(use_smoothed_normals); // set up camera and object transformation matrices projectionMatrix = get_default_projectionMatrix(); viewMatrix = get_default_viewMatrix(); modelMatrix = get_default_modelMatrix(); normalMatrix = get_default_normalMatrix(); glutMainLoop(); }