//////////////////////////////////////////////////////////////////////////////// // // Paella // Copyright (C) 2015 - Thomas FORGIONE, Emilie JALRAS, Marion LENFANT, Thierry MALON, Amandine PAILLOUX // Authors : // Thomas FORGIONE // Emilie JALRAS // Marion LENFANT // Thierry MALON // Amandine PAILLOUX // // This file is part of the project Paella // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it freely, // subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; // you must not claim that you wrote the original software. // If you use this software in a product, an acknowledgment // in the product documentation would be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, // and must not be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source distribution. //////////////////////////////////////////////////////////////////////////////// #include #include #include namespace pae { AnimatedMesh::AnimatedMesh(Skeleton3D const& skeleton) { auto segments = click(skeleton); this->segments = segments.first; auto mesh = skeleton.computeMesh(); associateBranches(segments.first, mesh); findFaces(associatedSegment, mesh, segments.first.size()); mesh.prepare(); vertices = mesh.vertices; geo::Tree> tree{segments.second}; listToTree(this->segments, tree); genStructure(this->segments, tree, structure); genStructure(this->segments, tree, roots); genRotations(roots, rotations); genStructuredFaces(facesPerSegment, structure, structuredFaces); genOtherVertices(vertices, facesPerSegment[facesPerSegment.size()-1], associatedSegment, structure, otherVertices); genColors(structure, colors); paths.push_back({}); genPaths(structure, paths); structure.node = -1; std::cout << tree << std::endl << "-------------------------" << std::endl; std::cout << structure << std::endl; std::cout << "structure size = " << structure.size() << std::endl; } geo::Tree& genStructure(std::vector> const& segments, geo::Tree> const& tree, geo::Tree& ret) { constexpr float eps = 0.0001; for (auto& child : tree.children) { for (unsigned int i = 0; i < segments.size(); i++) { // Compare segments[i] and (tree, child) if ( (((segments[i].first - tree.node).norm2() < eps) && ((segments[i].second - child.node).norm2() < eps)) || (((segments[i].first - child.node).norm2() < eps) && ((segments[i].second - tree.node).norm2() < eps))) { ret.children.push_back(geo::Tree{static_cast(i)}); genStructure(segments, child, ret.children[ret.children.size()-1]); } } } return ret; } geo::Tree>& genStructure(std::vector> const& segments, geo::Tree> const& tree, geo::Tree>& ret) { constexpr float eps = 0.0001; for (auto& child : tree.children) { for (unsigned int i = 0; i < segments.size(); i++) { // Compare segments[i] and (tree, child) if ( (((segments[i].first - tree.node).norm2() < eps) && ((segments[i].second - child.node).norm2() < eps)) || (((segments[i].first - child.node).norm2() < eps) && ((segments[i].second - tree.node).norm2() < eps))) { ret.children.push_back(geo::Tree>{child.node}); genStructure(segments, child, ret.children[ret.children.size()-1]); } } } return ret; } geo::Tree>>& genStructuredFaces( std::vector>> const& facesPerSegment, geo::Tree const& structure, geo::Tree>>& faces ) { // for (auto const& face_group : facesPerSegment) for (auto child : structure.children) { auto tree = geo::Tree>>{}; tree.node = facesPerSegment[child.node]; faces.children.push_back(tree); genStructuredFaces(facesPerSegment, child, faces.children[faces.children.size()-1]); } return faces; } std::unordered_map& genOtherVertices( std::vector> const& vertices, std::vector> const& otherFaces, std::vector associatedSegment, geo::Tree const& structure, std::unordered_map& ret, geo::Path path ) { // for (auto const& child : structure.children) path.push_back(0); for (unsigned int i = 0; i < structure.children.size(); i++) { path[path.size()-1] = i; for (auto const& f : otherFaces) { if (associatedSegment[f.x()] == static_cast(structure.children[i].node)) { ret.insert({f.x(), path}); } if (associatedSegment[f.y()] == static_cast(structure.children[i].node)) { ret.insert({f.y(), path}); } if (associatedSegment[f.z()] == static_cast(structure.children[i].node)) { ret.insert({f.z(), path}); } } genOtherVertices(vertices, otherFaces, associatedSegment, structure.children[i], ret, path); } return ret; } geo::Tree>& genColors( geo::Tree const& structure, geo::Tree>& colors) { for (auto const& child : structure.children) { geo::Tree> tree; tree.node = {{ static_cast(std::rand())/RAND_MAX, static_cast(std::rand())/RAND_MAX, static_cast(std::rand())/RAND_MAX }}; colors.children.push_back(tree); genColors(child, colors.children[colors.children.size()-1]); } return colors; } geo::Tree& genRotations( geo::Tree> const& extremities, geo::Tree& ret ) { for (auto const& child : extremities.children) { geo::Rotation r; r.center = extremities.node; geo::Tree tree; tree.node = r; ret.children.push_back(tree); genRotations(child, ret.children[ret.children.size()-1]); } return ret; } std::vector& genPaths( geo::Tree const& structure, std::vector& paths, geo::Path currentPath) { currentPath.push_back(0); // for (auto const& child : structure.children) for (unsigned int i = 0; i < structure.children.size(); i++) { currentPath[currentPath.size()-1] = i; paths.push_back(currentPath); genPaths(structure.children[i], paths, currentPath); } return paths; } void AnimatedMesh::associateBranches(std::vector> const& segments, geo::Mesh& mesh) { // stock each point at the index corresponding to the nearest segment for(unsigned int i=0;i p = geo::Point{i,mesh.vertices[i]}; associatedSegment.push_back(findNearestSegment(segments, p)); } } //finds the nearest segment to a point unsigned int AnimatedMesh::findNearestSegment(std::vector> const& segments, geo::Point const& p) { unsigned int nearestSegment = 0; float shortest_distance = std::numeric_limits::max(); for(unsigned int i=0;i distance) { shortest_distance = distance; nearestSegment = i; } } return nearestSegment; } void AnimatedMesh::findFaces(std::vector const& associatedSegments, geo::Mesh& mesh, unsigned int nbSegments) { for (unsigned int i=0;i>{}); } unsigned int segment; for(unsigned int i=0;i> const& vertices, geo::Tree>> const& faces, geo::Tree> const& colors, geo::Tree> const& extremities, geo::Tree const& rotations) { // for (auto const& child : faces.children) for (unsigned int i = 0; i < faces.children.size(); i++) { // Apply good rotation glPushMatrix(); rotations.children[i].node(); glBegin(GL_TRIANGLES); for (auto const& face : faces.children[i].node) { glColor3fv(&colors.children[i].node[0]); glVertex3fv(&vertices[face.x()].data[0]); glVertex3fv(&vertices[face.y()].data[0]); glVertex3fv(&vertices[face.z()].data[0]); } glEnd(); drawTree(vertices, faces.children[i], colors.children[i], extremities.children[i], rotations.children[i]); glPopMatrix(); } } void drawOthers(std::vector> const& vertices, std::unordered_map const& other_vertices, std::vector> const& faces, geo::Tree> const& colors, geo::Tree const& rotations) { // OpenGL is shit, so this will be a bit tricky // The thing is you can't use glRotatef, or glPush/PopMatrix inside glBegin() ... glEnd() // but we need to do this since the transformation we have to apply is different for each // vertex (since the vertices of the face are not mapped to the same segment) // What we'll do is to call gluProject after applying the rotations, and glUnProject // after reseting the modelview matrix. This way, each vertex will have the good transform // and we will be able to draw the face. for (auto const& f : faces) { // To avoid some copies of GL_MODELVIEW_MATRIX, we will first project everything, // and then unproject everything. // Ok, let's do the projection // Some variables needed to store de matrices GLdouble modelview[16]; GLdouble projection[16]; GLint viewport[4]; // tmp will be the projected vertices, and v will be the unprojected ones geo::Vector3 tmp1,tmp2,tmp3; geo::Vector3 v1,v2,v3; // First, let's save the state of the projection and viewport matrices glGetDoublev(GL_PROJECTION_MATRIX, projection); glGetIntegerv(GL_VIEWPORT, viewport); // Now Let's project the vertices, after applying the transformation // Projection of the first vertex glPushMatrix(); // Apply the transformation to the vertex rotations.execPath(other_vertices.at(f.x())); // Get the new modelview matrix glGetDoublev(GL_MODELVIEW_MATRIX, modelview); // Compute the result of the projection and store it into tmp1 gluProject(vertices[f.x()].x(), vertices[f.x()].y(), vertices[f.x()].z(), modelview, projection, viewport, &tmp1.data[0], &tmp1.data[1], &tmp1.data[2]); glPopMatrix(); // Same for the second glPushMatrix(); rotations.execPath(other_vertices.at(f.y())); glGetDoublev(GL_MODELVIEW_MATRIX, modelview); gluProject(vertices[f.y()].x(), vertices[f.y()].y(), vertices[f.y()].z(), modelview, projection, viewport, &tmp2.data[0], &tmp2.data[1], &tmp2.data[2]); glPopMatrix(); // And for the third glPushMatrix(); rotations.execPath(other_vertices.at(f.z())); glGetDoublev(GL_MODELVIEW_MATRIX, modelview); gluProject(vertices[f.z()].x(), vertices[f.z()].y(), vertices[f.z()].z(), modelview, projection, viewport, &tmp3.data[0], &tmp3.data[1], &tmp3.data[2]); glPopMatrix(); // Here, tmp1 tmp2 and tmp3 store the projected vertices. We will now // unproject them with the modelview matrix WITHOUT taking account // of the vertex-dependant transformation // We will get back the first modelview matrix WITHOUT transformations glGetDoublev(GL_MODELVIEW_MATRIX, modelview); // And unproject everything with this modelview matrix gluUnProject(tmp1.data[0], tmp1.data[1], tmp1.data[2], modelview, projection, viewport, &v1.data[0], &v1.data[1], &v1.data[2]); // Same for v2 gluUnProject(tmp2.data[0], tmp2.data[1], tmp2.data[2], modelview, projection, viewport, &v2.data[0], &v2.data[1], &v2.data[2]); // And for v3 gluUnProject(tmp3.data[0], tmp3.data[1], tmp3.data[2], modelview, projection, viewport, &v3.data[0], &v3.data[1], &v3.data[2]); // Here we are, by doing this "hack", we used opengl to compute the // result of the transformations on the vertices // That is to say, v1, v2 and v3 are now the three vertices of the face // with the transformation done correctly. // Now, we just have to render the triangle with the classic opengl way glBegin(GL_TRIANGLES); glColor3fv(&colors.applyPath(other_vertices.at(f.x())).node[0]); glVertex3d(v1.data[0], v1.data[1], v1.data[2]); glColor3fv(&colors.applyPath(other_vertices.at(f.y())).node[0]); glVertex3d(v2.data[0], v2.data[1], v2.data[2]); glColor3fv(&colors.applyPath(other_vertices.at(f.z())).node[0]); glVertex3d(v3.data[0], v3.data[1], v3.data[2]); glEnd(); } } void AnimatedMesh::draw() const { drawTree(vertices, structuredFaces, colors, roots, rotations); drawOthers(vertices, otherVertices, facesPerSegment[facesPerSegment.size()-1], colors, rotations); } } // namespace pae