int main(int argc, char** argv) { char filename[BUFFERSIZE]; glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(WIDTH, HEIGHT); glutInitWindowPosition(100, 100); glutCreateWindow("render_cad_model"); /* filename of the off file */ sprintf(filename, "%s/%02d.off", argv[1], atoi(argv[2])); /* load off file */ load_off_file(&Nvertice, &Vertices, &Nface, &Faces, filename); printf("load off file done\n"); /* compute face normals */ Fnormals = compute_face_normals(Nvertice, Vertices, Nface, Faces); /* compute vertex normals */ Vnormals = compute_vertex_normals(Nvertice, Vertices, Nface, Faces, Fnormals); /* draw the CAD model */ glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }
/* matlab interface */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int i; double *p; int argc = 1; char* argv[1]; argv[0] = ""; glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(WIDTH, HEIGHT); glutInitWindowPosition(100, 100); glutCreateWindow("render_cad_model"); if (nrhs != 2) mexErrMsgTxt("Wrong number of inputs"); /* parse vertices and faces */ p = (double*)mxGetPr(prhs[0]); Nvertice = mxGetN(prhs[0]); Vertices = (GLdouble*)malloc(sizeof(GLdouble)*Nvertice*3); for(i = 0; i < 3*Nvertice; i++) Vertices[i] = (GLdouble)p[i]; p = (double*)mxGetPr(prhs[1]); Nface = mxGetN(prhs[1]); Faces = (GLuint*)malloc(sizeof(GLuint)*Nface*3); for(i = 0; i < 3*Nface; i++) Faces[i] = (GLuint)p[i]; /* compute face normals */ Fnormals = compute_face_normals(Nvertice, Vertices, Nface, Faces); /* compute vertex normals */ Vnormals = compute_vertex_normals(Nvertice, Vertices, Nface, Faces, Fnormals); /* draw the CAD model */ glutDisplayFunc(display); glutReshapeFunc(reshape); glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); glutMainLoop(); return; }
std::list<VoronoiShard> voronoi_convex_hull_shatter(const gl::MeshPtr &the_mesh, const std::vector<glm::vec3>& the_voronoi_points) { // points define voronoi cells in world space (avoid duplicates) // verts = source (convex hull) mesh vertices in local space std::list<VoronoiShard> ret; std::vector<glm::vec3> mesh_verts = the_mesh->geometry()->vertices(); auto convexHC = std::make_shared<btConvexHullComputer>(); btAlignedObjectArray<btVector3> vertices; btVector3 rbb, nrbb; btScalar nlength, maxDistance, distance; std::vector<glm::vec3> sortedVoronoiPoints = the_voronoi_points; btVector3 normal, plane; btAlignedObjectArray<btVector3> planes, convexPlanes; std::set<int> planeIndices; std::set<int>::iterator planeIndicesIter; int numplaneIndices; int i, j, k; // Normalize verts (numerical stability), convert to world space and get convexPlanes int numverts = mesh_verts.size(); // auto aabb = the_mesh->boundingBox(); // float scale_val = 1.f;//std::max(std::max(aabb.width(), aabb.height()), aabb.depth()); auto mesh_transform = the_mesh->global_transform() ;//* scale(glm::mat4(), vec3(1.f / scale_val)); std::vector<glm::vec3> world_space_verts; world_space_verts.resize(mesh_verts.size()); for (i = 0; i < numverts ;i++) { world_space_verts[i] = (mesh_transform * vec4(mesh_verts[i], 1.f)).xyz(); } //btGeometryUtil::getPlaneEquationsFromVertices(chverts, convexPlanes); // Using convexHullComputer faster than getPlaneEquationsFromVertices for large meshes... convexHC->compute(&world_space_verts[0].x, sizeof(world_space_verts[0]), numverts, 0.0, 0.0); int numFaces = convexHC->faces.size(); int v0, v1, v2; // vertices // get plane equations for the convex-hull n-gons for (i = 0; i < numFaces; i++) { const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[i]]; v0 = edge->getSourceVertex(); v1 = edge->getTargetVertex(); edge = edge->getNextEdgeOfFace(); v2 = edge->getTargetVertex(); plane = (convexHC->vertices[v1]-convexHC->vertices[v0]).cross(convexHC->vertices[v2]-convexHC->vertices[v0]).normalize(); plane[3] = -plane.dot(convexHC->vertices[v0]); convexPlanes.push_back(plane); } const int numconvexPlanes = convexPlanes.size(); int numpoints = the_voronoi_points.size(); for (i = 0; i < numpoints ; i++) { auto curVoronoiPoint = the_voronoi_points[i]; planes.copyFromArray(convexPlanes); for (j = 0; j < numconvexPlanes; j++) { planes[j][3] += planes[j].dot(type_cast(the_voronoi_points[i])); } maxDistance = SIMD_INFINITY; // sort voronoi points std::sort(sortedVoronoiPoints.begin(), sortedVoronoiPoints.end(), pointCmp(curVoronoiPoint)); for (j=1; j < numpoints; j++) { normal = type_cast(sortedVoronoiPoints[j] - curVoronoiPoint); nlength = normal.length(); if (nlength > maxDistance) break; plane = normal.normalized(); plane[3] = -nlength / btScalar(2.); planes.push_back(plane); getVerticesInsidePlanes(planes, vertices, planeIndices); if (vertices.size() == 0) break; numplaneIndices = planeIndices.size(); if (numplaneIndices != planes.size()) { planeIndicesIter = planeIndices.begin(); for (k=0; k < numplaneIndices; k++) { if (k != *planeIndicesIter) planes[k] = planes[*planeIndicesIter]; planeIndicesIter++; } planes.resize(numplaneIndices); } maxDistance = vertices[0].length(); for (k=1; k < vertices.size(); k++) { distance = vertices[k].length(); if (maxDistance < distance) maxDistance = distance; } maxDistance *= btScalar(2.); } if (vertices.size() == 0) continue; // Clean-up voronoi convex shard vertices and generate edges & faces convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),0.0,0.0); // At this point we have a complete 3D voronoi shard mesh contained in convexHC // Calculate volume and center of mass (Stan Melax volume integration) numFaces = convexHC->faces.size(); btScalar volume = btScalar(0.); btVector3 com(0., 0., 0.); for (j = 0; j < numFaces; j++) { const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]]; v0 = edge->getSourceVertex(); v1 = edge->getTargetVertex(); edge = edge->getNextEdgeOfFace(); v2 = edge->getTargetVertex(); while (v2 != v0) { // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here... btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]); volume += vol; com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]); edge = edge->getNextEdgeOfFace(); v1 = v2; v2 = edge->getTargetVertex(); } } com /= volume * btScalar(4.); volume /= btScalar(6.); // Shift all vertices relative to center of mass int numVerts = convexHC->vertices.size(); for (j = 0; j < numVerts; j++) { convexHC->vertices[j] -= com; } // now create our output geometry with indices std::vector<gl::Face3> outer_faces, inner_faces; std::vector<glm::vec3> outer_vertices, inner_vertices; int cur_outer_index = 0, cur_inner_index = 0; for (j = 0; j < numFaces; j++) { const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]]; v0 = edge->getSourceVertex(); v1 = edge->getTargetVertex(); edge = edge->getNextEdgeOfFace(); v2 = edge->getTargetVertex(); // determine if it is an inner or outer face btVector3 cur_plane = (convexHC->vertices[v1] - convexHC->vertices[v0]).cross(convexHC->vertices[v2]-convexHC->vertices[v0]).normalize(); cur_plane[3] = -cur_plane.dot(convexHC->vertices[v0]); bool is_outside = false; for(uint32_t q = 0; q < convexPlanes.size(); q++) { if(is_equal(convexPlanes[q], cur_plane, 0.01f)){ is_outside = true; break;} } std::vector<gl::Face3> *shard_faces = &outer_faces; std::vector<glm::vec3> *shard_vertices = &outer_vertices; int *shard_index = &cur_outer_index; if(!is_outside) { shard_faces = &inner_faces; shard_vertices = &inner_vertices; shard_index = &cur_inner_index; } int face_start_index = *shard_index; // advance index *shard_index += 3; // first 3 verts of n-gon glm::vec3 tmp[] = { type_cast(convexHC->vertices[v0]), type_cast(convexHC->vertices[v1]), type_cast(convexHC->vertices[v2])}; shard_vertices->insert(shard_vertices->end(), tmp, tmp + 3); shard_faces->push_back(gl::Face3(face_start_index, face_start_index + 1, face_start_index + 2)); // add remaining triangles of face (if any) while (true) { edge = edge->getNextEdgeOfFace(); v1 = v2; v2 = edge->getTargetVertex(); // end of n-gon if(v2 == v0) break; shard_vertices->push_back(type_cast(convexHC->vertices[v2])); shard_faces->push_back(gl::Face3(face_start_index, *shard_index - 1, *shard_index)); (*shard_index)++; } } // entry construction gl::Mesh::Entry e0, e1; // outer entry e0.num_vertices = outer_vertices.size(); e0.num_indices = outer_faces.size() * 3; e0.material_index = 0; // inner entry e1.base_index = e0.num_indices; e1.base_vertex = e0.num_vertices; e1.num_vertices = inner_vertices.size(); e1.num_indices = inner_faces.size() * 3; e1.material_index = 1; // create gl::Mesh object for the shard auto inner_geom = gl::Geometry::create(), outer_geom = gl::Geometry::create(); // append verts and indices outer_geom->append_faces(outer_faces); outer_geom->vertices() = outer_vertices; outer_geom->compute_face_normals(); inner_geom->append_faces(inner_faces); inner_geom->append_vertices(inner_vertices); inner_geom->compute_face_normals(); // merge geometries outer_geom->append_vertices(inner_geom->vertices()); outer_geom->append_normals(inner_geom->normals()); outer_geom->append_indices(inner_geom->indices()); outer_geom->faces().insert(outer_geom->faces().end(), inner_geom->faces().begin(), inner_geom->faces().end()); outer_geom->compute_bounding_box(); auto inner_mat = gl::Material::create(); auto m = gl::Mesh::create(outer_geom, gl::Material::create()); m->entries() = {e0, e1}; m->materials().push_back(inner_mat); m->set_position(curVoronoiPoint + type_cast(com)); // m->transform() *= glm::scale(mat4(), vec3(scale_val)); // compute projected texcoords (outside) gl::project_texcoords(the_mesh, m); // compute box mapped texcoords for inside vertices auto &indices = m->geometry()->indices(); auto &vertices = m->geometry()->vertices(); // aabb auto out_aabb = the_mesh->bounding_box(); vec3 aabb_extents = out_aabb.halfExtents() * 2.f; uint32_t base_vertex = m->entries()[1].base_vertex; uint32_t k = m->entries()[1].base_index, kl = k + m->entries()[1].num_indices; for(;k < kl; k += 3) { gl::Face3 f(indices[k] + base_vertex, indices[k] + base_vertex + 1, indices[k] + base_vertex + 2); // normal const vec3 &v0 = vertices[f.a]; const vec3 &v1 = vertices[f.b]; const vec3 &v2 = vertices[f.c]; vec3 n = glm::normalize(glm::cross(v1 - v0, v2 - v0)); float abs_vals[3] = {fabsf(n[0]), fabsf(n[1]), fabsf(n[2])}; // get principal direction int principle_axis = std::distance(abs_vals, std::max_element(abs_vals, abs_vals + 3)); // switch (principle_axis) // { // // X-axis // case 0: // //ZY plane // m->geometry()->texCoords()[f.a] = vec2(v0.z - out_aabb.min.z / aabb_extents.z, // v0.y - out_aabb.min.y / aabb_extents.y); // m->geometry()->texCoords()[f.b] = vec2(v1.z - out_aabb.min.z / aabb_extents.z, // v1.y - out_aabb.min.y / aabb_extents.y); // m->geometry()->texCoords()[f.c] = vec2(v2.z - out_aabb.min.z / aabb_extents.z, // v2.y - out_aabb.min.y / aabb_extents.y); // break; // // // Y-axis // case 1: // // XZ plane // m->geometry()->texCoords()[f.a] = vec2(v0.x - out_aabb.min.x / aabb_extents.x, // v0.z - out_aabb.min.z / aabb_extents.z); // m->geometry()->texCoords()[f.b] = vec2(v1.x - out_aabb.min.x / aabb_extents.x, // v1.z - out_aabb.min.z / aabb_extents.z); // m->geometry()->texCoords()[f.c] = vec2(v2.x - out_aabb.min.x / aabb_extents.x, // v2.z - out_aabb.min.z / aabb_extents.z); // break; // // // Z-axis // case 2: // //XY plane // m->geometry()->texCoords()[f.a] = vec2(v0.x - out_aabb.min.x / aabb_extents.x, // v0.y - out_aabb.min.y / aabb_extents.y); // m->geometry()->texCoords()[f.b] = vec2(v1.x - out_aabb.min.x / aabb_extents.x, // v1.y - out_aabb.min.y / aabb_extents.y); // m->geometry()->texCoords()[f.c] = vec2(v2.x - out_aabb.min.x / aabb_extents.x, // v2.y - out_aabb.min.y / aabb_extents.y); // break; // // default: // break; // } } // push to return structure ret.push_back({m, volume}); } LOG_DEBUG << "Generated " << ret.size() <<" voronoi shards"; return ret; }