I am using OpenFrameworks for animating a 3d model using keypress. The following are the steps that I have successfully completed :-
- Loading a ‘.dae’ file using ofxAssimpModelLoader
- Getting the scene , bones and the nodes present in the 3d model
- Drawing the skeleton using the nodes
My end goal is to be able to lift the hand or legs using keyboard key press. I went through many of the common tutorials for skeletal animation using Assimp but i am still unable to get it woking. Here is my code.
Using Qt Creator with openFrameworks
#include "ofMain.h"
#include "ofxAssimpModelLoader.h"
#include "ofVboMesh.h"
#include <iostream>
#include <memory>
#include <string>
class SkeletonDrawer : public ofxAssimpModelLoader
{
public:
void drawSkeleton();
aiNode *getNodeFromName(string name);
private:
std::map<aiNode*, aiMatrix4x4> nodeMatrices;
void collectNodes(const struct aiScene *sc, const struct aiNode *nd);
};
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
SkeletonDrawer model;
ofLight light;
};
Here is the cpp file :
void ofApp::setup(){
ofDisableArbTex();
if (model.loadModel("/home/anirudhnj/Downloads/ninja/ninja.dae", 20))
{
model.setAnimation(0);
model.setPosition(ofGetWidth() / 2, ofGetHeight() * 0.75, 0);
ofPushMatrix();
model.setRotation(1,90,90,0,0);
ofPopMatrix();
}
ofEnableBlendMode(OF_BLENDMODE_ALPHA);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
light.enable();
ofEnableSeparateSpecularLight();
}
void SkeletonDrawer::collectNodes(const struct aiScene *sc, const struct aiNode *nd)
{
for (unsigned n = 0; n < nd->mNumMeshes; ++n)
{
const struct aiMesh *mesh = sc->mMeshes[nd->mMeshes[n]];
for (int a = 0; a < mesh->mNumBones; ++a)
{
const aiBone *bone = mesh->mBones[a];
//ofLog(OF_LOG_NOTICE)<<bone->mName.C_Str();
// find the corresponding node
aiNode *node = sc->mRootNode->FindNode(bone->mName);
aiNode *tempNode = node;
aiMatrix4x4 nodeMat;
while (tempNode)
{
nodeMatrices[tempNode] = nodeMat;
tempNode = tempNode->mParent;
}
}
}
// process all children
for (unsigned n = 0; n < nd->mNumChildren; n++)
{
collectNodes(sc, nd->mChildren[n]);
}
}
//Returns the node with the given name
aiNode * SkeletonDrawer::getNodeFromName(string name)
{
aiNode * rootNode = scene.get()->mRootNode;
aiNode * selectedNode = rootNode->FindNode(name.c_str()) ;
return selectedNode;
}
void SkeletonDrawer::drawSkeleton()
{
//const aiScene * currentScene = scene.get();
// find all nodes connected to the bone hierarchy
collectNodes(scene.get(), scene.get()->mRootNode);
// calculate node matrices
map<aiNode*, aiMatrix4x4>::iterator i = nodeMatrices.begin();
for(; i != nodeMatrices.end(); ++i)
{
aiNode *node = i->first;
aiMatrix4x4 nodeMat;
const aiNode *tempNode = node;
while (tempNode)
{
nodeMat = tempNode->mTransformation * nodeMat;
tempNode = tempNode->mParent;
}
nodeMatrices[node] = nodeMat;
}
// do all transformations similarly to ofxAssimpModelLoader::draw()
ofPushMatrix();
ofTranslate(pos);
ofRotate(180, 0, 0,1);
ofRotateX(-90);
ofTranslate(-scene_center.x, -scene_center.y, scene_center.z);
if (normalizeScale)
{
ofScale(normalizedScale, normalizedScale, normalizedScale);
}
for (int i = 0; i < rotAngle.size(); i++)
{
ofRotate(rotAngle[i], rotAxis[i].x, rotAxis[i].y, rotAxis[i].z);
}
ofScale(scale.x, scale.y, scale.z);
// draw bones, all nodes connected with their parents
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glColor3f(1, 0, 0);
glLineWidth(5.);
glBegin(GL_LINES);
aiMatrix4x4 mat0, mat1;
aiQuaternion q0, q1;
aiVector3D p0, p1;
i = nodeMatrices.begin();
for(; i != nodeMatrices.end(); ++i)
{
aiNode *n0 = i->first;
aiNode *n1 = n0->mParent;
if (n1 == NULL)
continue;
// get the position from the matrices
mat0 = i->second;
mat0.DecomposeNoScaling(q0, p0);
mat1 = nodeMatrices[n1];
mat1.DecomposeNoScaling(q1, p1);
glVertex3f(p0.x, p0.y, p0.z);
glVertex3f(p1.x, p1.y, p1.z);
}
glEnd();
ofPopMatrix();
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
ofBackground(50, 50, 50, 0);
ofSetColor(255, 255, 255, 255);
ofPushMatrix();
ofTranslate(model.getPosition().x, model.getPosition().y, 0);
ofRotate(-mouseX, 0, 1, 0);
ofTranslate(-model.getPosition().x, -model.getPosition().y, 0);
model.drawFaces();
model.drawSkeleton();
ofPopMatrix();
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
aiQuaternion quaternion ;
aiVector3t<float> movement;
aiNode * selectedNode = model.getNodeFromName("LeftLegJoint");
if(!selectedNode)
return;
selectedNode->mTransformation.DecomposeNoScaling(quaternion ,movement) ;
//**Code here ????**
if(key == OF_KEY_UP)
{
}
if(key == OF_KEY_DOWN)
{
}
if(key == OF_KEY_LEFT)
{
}
if(key == OF_KEY_RIGHT)
{
}
}