JoshButner

Mesh Skinning & Animation - main.cpp

Mar 10th, 2022
44
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.42 KB | None | 0 0
  1. #include "GL/glew.h"
  2. #include "GLFW/glfw3.h"
  3. #include <fstream>
  4. #include <vector>
  5. #include <iostream>
  6. #include <eigen>
  7.  
  8. using namespace Eigen;
  9.  
  10. class Triangle
  11. {
  12. public:
  13.     int indices[3];
  14.     inline int &operator[](const unsigned int &i) { return indices[i]; };
  15.     inline int operator[](const unsigned int &i) const { return indices[i]; };
  16.     inline void set(int x, int y, int z) { indices[0] = x; indices[1] = y; indices[2] = z; };
  17.     inline Triangle(int x, int y, int z) { indices[0] = x; indices[1] = y; indices[2] = z; };
  18.     inline Triangle() {};
  19.     inline Triangle &operator=(const Triangle &that);
  20. };
  21.  
  22. // ----------------------------------------------------------------------------
  23.  
  24. unsigned int g_windowWidth = 800;
  25. unsigned int g_windowHeight = 600;
  26. char* g_windowName = "Basic Mesh Animation";
  27.  
  28. GLFWwindow* g_window;
  29.  
  30. std::vector<Triangle> g_triangles;
  31. std::vector<Vector3f> g_vertices;
  32. std::vector<Vector3f> g_normals;
  33. std::vector<std::vector<float> > g_weights; // [jointID][vertexID]
  34. std::vector<std::vector<float> > g_poses;   // [poseID][jointID]
  35.  
  36. // joints
  37. unsigned int g_numJoints;
  38. std::vector<int> g_jointParent; // indices of parent joints
  39.  
  40. // local transformations
  41. std::vector<Matrix4f> g_jointRot;           // joint local rotation
  42. std::vector<Matrix4f> g_jointOffset;        // joint local offset
  43. std::vector<Matrix4f> g_jointRotRest;       // joint local rest-pose rotation
  44.  
  45. // ----------------------------------------------------------------------------
  46.  
  47. // global transformations
  48. std::vector<Matrix4f> g_jointTrans;         // joint global transformation
  49. std::vector<Matrix4f> g_jointTransRestInv;  // joint global rest-pose inverse transformation
  50.  
  51. // deformed vertices
  52. std::vector<Vector3f> g_deformedVertices;
  53.  
  54. // ----------------------------------------------------------------------------
  55.  
  56. int g_enableAnimate = 0;
  57. bool g_enableRenderSkeleton = 0;
  58. bool g_enableRenderSkinningWeights = 0;
  59.  
  60. void animate();
  61.  
  62. float getTime()
  63. {
  64.     return (float) glfwGetTime();
  65. }
  66.  
  67. void glfwErrorCallback(int error, const char* description)
  68. {
  69.     std::cerr << "GLFW Error " << error << ": " << description << std::endl;
  70.     exit(1);
  71. }
  72.  
  73. void glfwKeyCallback(GLFWwindow* p_window, int p_key, int p_scancode, int p_action, int p_mods)
  74. {
  75.     if (p_key == GLFW_KEY_ESCAPE && p_action == GLFW_PRESS)
  76.     {
  77.         glfwSetWindowShouldClose(g_window, GL_TRUE);
  78.     }
  79.  
  80.     if (p_key == GLFW_KEY_A && p_action == GLFW_PRESS)
  81.     {
  82.         g_enableAnimate = (g_enableAnimate + 1) % 3;
  83.     }
  84.  
  85.     if (p_key == GLFW_KEY_S && p_action == GLFW_PRESS)
  86.     {
  87.         g_enableRenderSkeleton = !(g_enableRenderSkeleton);
  88.     }
  89.  
  90.     if (p_key == GLFW_KEY_W && p_action == GLFW_PRESS)
  91.     {
  92.         g_enableRenderSkinningWeights = !(g_enableRenderSkinningWeights);
  93.     }
  94. }
  95.  
  96. void initWindow()
  97. {
  98.     // initialize GLFW
  99.     glfwSetErrorCallback(glfwErrorCallback);
  100.     if (!glfwInit())
  101.     {
  102.         std::cerr << "GLFW Error: Could not initialize GLFW library" << std::endl;
  103.         exit(1);
  104.     }
  105.  
  106.     g_window = glfwCreateWindow(g_windowWidth, g_windowHeight, g_windowName, NULL, NULL);
  107.     if (!g_window)
  108.     {
  109.         glfwTerminate();
  110.         std::cerr << "GLFW Error: Could not initialize window" << std::endl;
  111.         exit(1);
  112.     }
  113.  
  114.     // callbacks
  115.     glfwSetKeyCallback(g_window, glfwKeyCallback);
  116.  
  117.     // Make the window's context current
  118.     glfwMakeContextCurrent(g_window);
  119.  
  120.     // turn on VSYNC
  121.     glfwSwapInterval(1);
  122. }
  123.  
  124. void initGL()
  125. {
  126.     glClearColor(1.f, 1.f, 1.f, 1.0f);
  127.  
  128.     glEnable(GL_LIGHTING);
  129.     glEnable(GL_LIGHT0);
  130.     glEnable(GL_DEPTH_TEST);
  131.     glShadeModel(GL_SMOOTH);
  132.  
  133.     glMatrixMode(GL_PROJECTION);
  134.     glLoadIdentity();
  135.     gluPerspective(45.0f, (GLfloat)g_windowWidth / (GLfloat)g_windowHeight, 0.1f, 10.0f);
  136. }
  137.  
  138. void setModelViewMatrix()
  139. {
  140.     glMatrixMode(GL_MODELVIEW);
  141.     glLoadIdentity();
  142.  
  143.     if (g_enableAnimate == 0)
  144.         gluLookAt(sin(getTime() * 0.1f + 0.2f) * 3.0f, 1.0f, cos(getTime() * 0.1f + 0.2f) * 3.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  145.     else
  146.         gluLookAt(2.0f, 1.0f, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  147. }
  148.  
  149. void renderSkeletonRig()
  150. {
  151.     Vector4f v1, v2;
  152.     glDisable(GL_DEPTH_TEST);
  153.     glDisable(GL_LIGHTING);
  154.     glLineWidth(2.0f);
  155.     glPointSize(6.0f);
  156.  
  157.     for (unsigned int jointID = 0; jointID < g_numJoints; ++jointID)
  158.     {
  159.         const int parentJointID = g_jointParent[jointID];
  160.  
  161.         v1.setZero();
  162.         v1(3) = 1.0f;
  163.         v1 = g_jointTrans[jointID] * v1;
  164.  
  165.         glColor3f(1.0f, 0.0f, 1.0f);
  166.  
  167.         glBegin(GL_POINTS);
  168.         glVertex3f(v1(0), v1(1), v1(2));
  169.         glEnd();
  170.  
  171.         if (parentJointID != -1)
  172.         {
  173.             v2.setZero();
  174.             v2(3) = 1.0f;
  175.             v2 = g_jointTrans[parentJointID] * v2;
  176.  
  177.             if (parentJointID % 3 == 0) glColor3f(1.0f, 0.0f, 0.0f);
  178.             if (parentJointID % 3 == 1) glColor3f(0.0f, 1.0f, 0.0f);
  179.             if (parentJointID % 3 == 2) glColor3f(0.0f, 0.0f, 1.0f);
  180.  
  181.             glBegin(GL_LINES);
  182.             glVertex3f(v1(0), v1(1), v1(2));
  183.             glVertex3f(v2(0), v2(1), v2(2));
  184.             glEnd();
  185.         }
  186.     }
  187.  
  188.     glEnable(GL_DEPTH_TEST);
  189.     glEnable(GL_LIGHTING);
  190.     glColor3f(1.0f, 1.0f, 1.0f);
  191. }
  192.  
  193. void renderMesh()
  194. {
  195.     glEnable(GL_COLOR_MATERIAL);
  196.     glBegin(GL_TRIANGLES);
  197.  
  198.     for (auto& triangle : g_triangles)
  199.     {
  200.         for (int i = 0; i < 3; ++i)
  201.         {
  202.             const int vidx = triangle[i];
  203.             const Vector3f v = g_deformedVertices[vidx];
  204.             const Vector3f vn = g_normals[vidx];
  205.             glNormal3f(vn(0), vn(1), vn(2));
  206.  
  207.             if (g_enableRenderSkinningWeights)
  208.             {
  209.                 // weight color
  210.                 float r = 0.4f, g = 0.4f, b = 0.4f;
  211.  
  212.                 for (unsigned int jointID = 0; jointID < g_numJoints - 1; ++jointID)
  213.                 {
  214.                     const float w = g_weights[jointID][vidx];
  215.                     if (jointID % 3 == 0) r += 0.4f * w;
  216.                     if (jointID % 3 == 1) g += 0.4f * w;
  217.                     if (jointID % 3 == 2) b += 0.4f * w;
  218.                 }
  219.  
  220.                 glColor3f(r, g, b);
  221.             }
  222.             else
  223.             {
  224.                 glColor3f(0.8f, 0.8f, 0.8f);
  225.             }
  226.             glVertex3f(v(0), v(1), v(2));
  227.         }
  228.     }
  229.  
  230.     glEnd();
  231. }
  232.  
  233. void render()
  234. {
  235.     setModelViewMatrix();
  236.     renderMesh();
  237.     if (g_enableRenderSkeleton) renderSkeletonRig();
  238. }
  239.  
  240. void renderLoop()
  241. {
  242.     while (!glfwWindowShouldClose(g_window))
  243.     {
  244.         animate();
  245.  
  246.         // clear buffers
  247.         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  248.  
  249.         render();
  250.  
  251.         // Swap front and back buffers
  252.         glfwSwapBuffers(g_window);
  253.  
  254.         // Poll for and process events
  255.         glfwPollEvents();
  256.     }
  257. }
  258.  
  259. // ----------------------------------------------------------------------------
  260.  
  261. bool loadObj(std::string fname, std::vector<Vector3f> &pts, std::vector<Vector3f> &pts_n, std::vector<Triangle> &triangles)
  262. {
  263.     char c[500];
  264.  
  265.     int numVertices = 0, numFaces = 0;
  266.     bool normals = false, texture = false;
  267.     int tint;
  268.     char ch;
  269.     int p, q, r;
  270.     float x, y, z;
  271.     std::vector<Vector3f>::iterator v;
  272.     std::vector<Vector3f>::iterator vn;
  273.     std::vector<Triangle>::iterator t;
  274.     std::ifstream in1(fname.c_str(), std::ios::in);
  275.     if (!in1.is_open()) {
  276.         return false;
  277.     }
  278.     in1.flags(in1.flags() & ~std::ios::skipws);
  279.  
  280.     while (in1 >> ch) {
  281.         if (ch == 'v') {
  282.             in1 >> ch;
  283.             if (ch == ' ') numVertices++;
  284.             else if (ch == 'n') normals = true;
  285.             else if (ch == 't') texture = true;
  286.             else std::cerr << "error \'" << ch << "\'" << std::endl;
  287.         }
  288.         else if (ch == '#') {
  289.             while (in1 >> ch && ch != '\n'); // Read to the end of the line.
  290.         }
  291.         else if (ch == 'f') numFaces++;
  292.     }
  293.     in1.close();
  294.  
  295.     std::cout << "Mesh vertices: " << numVertices << std::endl;
  296.  
  297.     pts.resize(numVertices);
  298.     pts_n.resize(numVertices);
  299.     triangles.resize(numFaces);
  300.     v = pts.begin();
  301.     vn = pts_n.begin();
  302.     t = triangles.begin();
  303.  
  304.     std::ifstream in(fname, std::ios::in);
  305.     if (!in.is_open()) {
  306.         return false;
  307.     }
  308.  
  309.     while (in >> ch) {
  310.         if (ch == '#') {
  311.             in.getline(c, 500);
  312.             continue;
  313.         }
  314.         if (ch == 'g') {
  315.             in.getline(c, 500);
  316.             continue;
  317.         }
  318.         if (ch == 's') {
  319.             in.getline(c, 500);
  320.             continue;
  321.         }
  322.         if (ch == 'm') {
  323.             in.getline(c, 500);
  324.             continue;
  325.         }
  326.         if (ch == 'u') {
  327.             in.getline(c, 500);
  328.             continue;
  329.         }
  330.         if (ch == 'v') {
  331.             ch = in.peek();
  332.             if (ch != 't' && ch != 'n') {
  333.                 in >> x >> y >> z;
  334.                 (*v) << x, y, z;
  335.                 v++;
  336.             }
  337.             else if (ch == 'n') {
  338.                 in >> ch;
  339.                 in >> x >> y >> z;
  340.                 (*vn) << x, y, z;
  341.                 //(*vn).normalize();
  342.                 vn++;
  343.             }
  344.             else {
  345.                 in.getline(c, 500);
  346.             }
  347.             continue;
  348.         }
  349.         if (ch == 'f') {
  350.             if (normals && texture) {
  351.                 in >> p >> ch >> tint >> ch >> tint >> q >> ch >> tint >> ch >> tint >> r >> ch >> tint >> ch >> tint;
  352.             }
  353.             else if (normals) {
  354.                 in >> p >> ch >> ch >> tint >> q >> ch >> ch >> tint >> r >> ch >> ch >> tint;
  355.             }
  356.             else if (texture) {
  357.                 in >> p >> ch >> tint >> q >> ch >> tint >> r >> ch >> tint;
  358.             }
  359.             else {
  360.                 in >> p >> q >> r;
  361.             }
  362.             (*t)[0] = p - 1;
  363.             (*t)[1] = q - 1;
  364.             (*t)[2] = r - 1;
  365.             t++;
  366.             continue;
  367.         }
  368.     }
  369.     in.close();
  370.     return true;
  371. }
  372.  
  373. void loadSkeleton(std::string fname)
  374. {
  375.     std::ifstream in(fname.c_str(), std::ios::in);
  376.     int jointID, parent;
  377.     float offsetX, offsetY, offsetZ;
  378.  
  379.     while (in >> jointID >> parent >> offsetX >> offsetY >> offsetZ)
  380.     {
  381.         g_jointParent.push_back(parent);
  382.  
  383.         Matrix4f offset;
  384.         offset.setIdentity();
  385.         offset(0, 3) = offsetX;
  386.         offset(1, 3) = offsetY;
  387.         offset(2, 3) = offsetZ;
  388.         g_jointOffset.push_back(offset);
  389.     }
  390.  
  391.     g_numJoints = (unsigned int) g_jointParent.size();
  392.  
  393.     std::cout << "Loaded " << g_numJoints << " joints" << std::endl;
  394. }
  395.  
  396. void loaddmat(std::string fname, std::vector<std::vector<float> > &mat)
  397. {
  398.     std::ifstream in(fname.c_str(), std::ios::in);
  399.     int cols, rows;
  400.     in >> cols >> rows;
  401.     mat.resize(cols);
  402.     for (int i = 0; i < cols; i++) {
  403.         mat[i].resize(rows);
  404.         for (int j = 0; j < rows; j++) {
  405.             in >> mat[i][j];
  406.         }
  407.     }
  408. }
  409.  
  410. void setJointRotations(float t)
  411. {
  412.     for (unsigned int jointID = 0; jointID < g_numJoints; ++jointID)
  413.     {
  414.         Quaternionf qB = Quaternionf(g_poses[1][4 * jointID], g_poses[1][4 * jointID + 1], g_poses[1][4 * jointID + 2], g_poses[1][4 * jointID + 3]);
  415.  
  416.         Quaternionf qA;
  417.         qA.setIdentity();
  418.         Quaternionf q = qA.slerp(t, qB);
  419.  
  420.         Matrix4f R;
  421.         R.setIdentity();
  422.         R.block<3, 3>(0, 0) = q.toRotationMatrix();
  423.  
  424.         g_jointRot[jointID] = R;
  425.     }
  426. }
  427.  
  428. void loadData(std::string p_inputData)
  429. {
  430.     // load data
  431.     std::cout << "Loading obj" << std::endl;
  432.     loadObj("data/" + p_inputData + "/mesh.obj", g_vertices, g_normals, g_triangles);
  433.  
  434.     std::cout << "Loading skeleton" << std::endl;
  435.     loadSkeleton("data/" + p_inputData + "/skeleton.bf");
  436.  
  437.     std::cout << "Loading weights" << std::endl;
  438.     loaddmat("data/" + p_inputData + "/weights.dmat", g_weights);
  439.  
  440.     std::cout << "Loading poses" << std::endl;
  441.     loaddmat("data/" + p_inputData + "/pose.dmat", g_poses);
  442.  
  443.     // initialize data structures
  444.     Matrix4f ident;
  445.     ident.setIdentity();
  446.     g_deformedVertices.resize(g_vertices.size());
  447.     g_jointRot.resize(g_numJoints, ident);
  448.     g_jointRotRest.resize(g_numJoints, ident);
  449.     g_jointTrans.resize(g_numJoints, ident);
  450.     g_jointTransRestInv.resize(g_numJoints, ident);
  451.  
  452.     // set rest-pose rotation matrices
  453.     setJointRotations(0.0f);
  454.     g_jointRotRest = g_jointRot;
  455. }
  456.  
  457. // ----------------------------------------------------------------------------
  458.  
  459. Vector3f fromHomog(const Vector4f& homog)
  460. {
  461.     return homog.block<3, 1>(0, 0);
  462. }
  463.  
  464. Vector4f toHomog(const Vector3f& homog)
  465. {
  466.     Vector4f v;
  467.     v << homog, 1.0f;
  468.     return v;
  469. }
  470.  
  471. // ----------------------------------------------------------------------------
  472.  
  473. void computeJointTransformations(
  474.     const std::vector<Matrix4f>& p_local,
  475.     const std::vector<Matrix4f>& p_offset,
  476.     const std::vector<int>& p_jointParent,
  477.     const unsigned int p_numJoints,
  478.     std::vector<Matrix4f>& p_global)
  479. {
  480.     // F(j) = F(p(j)) * R(j) * T(j);
  481.     p_global[0] = p_offset[0] * p_local[0];
  482.     for(int j = 1; j < p_numJoints; j++){
  483.         p_global[j] = p_global[p_jointParent[j]] * p_offset[j] * p_local[j];
  484.     }
  485. }
  486.  
  487. void skinning(
  488.         const std::vector<Vector3f>& p_vertices,
  489.         const unsigned int p_numJoints,
  490.         const std::vector<Matrix4f>& p_jointTrans,
  491.         const std::vector<Matrix4f>& p_jointTransRestInv,
  492.         const std::vector<std::vector<float>>& p_weights,
  493.         std::vector<Vector3f>& p_deformedVertices)
  494. {
  495.     for (unsigned int v = 0; v < p_vertices.size(); v++)
  496.     {
  497.         Vector3f weightedPos = Vector3f(0, 0, 0);
  498.         for (unsigned int j = 0; j < p_numJoints; j++)
  499.         {
  500.             Matrix4f transformation = p_jointTrans[j] * p_jointTransRestInv[j];
  501.             // weightedPos += p_weights[j][v] * transformation;
  502.             Vector4f homogVert = toHomog(p_vertices[v]);
  503.             Vector4f homogWeight = p_weights[j][v] * transformation * homogVert;
  504.             weightedPos += fromHomog(homogWeight);
  505.         }
  506.         p_deformedVertices[v] = weightedPos;
  507.         // p_deformedVertices[v] = p_vertices[v];
  508.     }
  509. }
  510.  
  511. void initRestPose()
  512. {
  513.     computeJointTransformations(g_jointRotRest, g_jointOffset, g_jointParent, g_numJoints, g_jointTrans);
  514.     for (unsigned int jointID = 0; jointID < g_numJoints; ++jointID)
  515.     {
  516.         g_jointTransRestInv[jointID] = g_jointTrans[jointID].inverse();
  517.     }
  518. }
  519.  
  520. void animate()
  521. {
  522.     const float t = std::fabsf(sinf(getTime()));
  523.     switch (g_enableAnimate)
  524.     {
  525.         case 0: setJointRotations(t); break;
  526.         case 1: setJointRotations(0.0f); break;
  527.         case 2: setJointRotations(1.0f); break;
  528.     }
  529.     computeJointTransformations(g_jointRot, g_jointOffset, g_jointParent, g_numJoints, g_jointTrans);
  530.     skinning(g_vertices, g_numJoints, g_jointTrans, g_jointTransRestInv, g_weights, g_deformedVertices);
  531. }
  532.  
  533. int main(int argc, char *argv[])
  534. {
  535.     // loadData("capsule"); // replace this with the following line to load the Ogre instead
  536.     loadData("ogre");
  537.  
  538.     initRestPose();
  539.  
  540.     std::cout << std::endl << "Controls:" << std::endl
  541.         << "Press key A to switch animation control" << std::endl
  542.         << "Press key S to show skeleton rig" << std::endl
  543.         << "Press key W to show skinning weights" << std::endl;
  544.  
  545.     initWindow();
  546.     initGL();
  547.     renderLoop();
  548. }
  549.  
Advertisement
Add Comment
Please, Sign In to add comment