diff --git a/CMakeLists.txt b/CMakeLists.txt index 51a5bd3..eda3c95 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,9 +14,10 @@ set(gui text.cpp rectangle.cpp) set(utils util.cpp) set(math quaternion.cpp vector.cpp matrix.cpp ray.cpp) set(render waterPlane.cpp particleEmitter.cpp camera.cpp light.cpp material.cpp mesh.cpp model.cpp node.cpp quad.cpp box.cpp root.cpp shader.cpp texture.cpp) +set(anim animationChannel.cpp animation.cpp) set(armature skeleton.cpp bone.cpp) -add_library(vb01 SHARED main.cpp ${render} ${math} ${utils} ${gui} ${armature}) +add_library(vb01 SHARED main.cpp ${render} ${math} ${utils} ${gui} ${armature} ${anim}) target_link_libraries(vb01 glfw) target_link_libraries(vb01 glad) target_link_libraries(vb01 assimp) diff --git a/animation.cpp b/animation.cpp new file mode 100644 index 0000000..4fa8822 --- /dev/null +++ b/animation.cpp @@ -0,0 +1,25 @@ +#include"animation.h" + +using namespace std; + +namespace vb01{ + Animation::Animation(string name){ + this->name=name; + } + + Animation::~Animation(){ + } + + void Animation::update(){ + } + + Animation::KeyframeGroup* Animation::getKeyframeGroup(Bone *b){ + int id=-1; + for(int i=0;i-1?&(keyframeGroups[id]):nullptr; + } +} diff --git a/animation.h b/animation.h new file mode 100644 index 0000000..0e6aee5 --- /dev/null +++ b/animation.h @@ -0,0 +1,49 @@ +#ifndef ANIMATION_H +#define ANIMATION_H + +#include +#include + +namespace vb01{ + class Bone; + + class Animation{ + public: + struct KeyframeGroup{ + struct Keyframe{ + enum Type{ + POS_X, + POS_Y, + POS_Z, + ROT_W, + ROT_X, + ROT_Y, + ROT_Z, + SCALE_X, + SCALE_Y, + SCALE_Z + }; + enum Interpolation{CONSTANT,LINEAR,BEZIER}; + + Type type; + Interpolation interpolation; + float value; + int frame; + }; + Bone *bone=nullptr; + std::vector keyframes; + }; + + Animation(std::string); + ~Animation(); + void update(); + KeyframeGroup* getKeyframeGroup(Bone *b); + inline std::string getName(){return name;} + inline void addKeyframeGroup(KeyframeGroup k){keyframeGroups.push_back(k);} + private: + std::string name; + std::vector keyframeGroups; + }; +} + +#endif diff --git a/animationChannel.cpp b/animationChannel.cpp new file mode 100644 index 0000000..e69de29 diff --git a/animationChannel.h b/animationChannel.h new file mode 100644 index 0000000..6c87cd9 --- /dev/null +++ b/animationChannel.h @@ -0,0 +1,14 @@ +#ifndef ANIMATION_CHANNEL_H +#define ANIMATION_CHANNEL_H + +namespace vb01{ + class AnimationChannel{ + public: + AnimationChannel(); + ~AnimationChannel(); + void update(); + private: + }; +} + +#endif diff --git a/animationController.cpp b/animationController.cpp new file mode 100644 index 0000000..68ca9d0 --- /dev/null +++ b/animationController.cpp @@ -0,0 +1,12 @@ +#include "animationController.h" + +namespace vb01{ + AnimationController::AnimationController(){ + } + + AnimationController::~AnimationController(){ + } + + void AnimationController::update(){ + } +} diff --git a/animationController.h b/animationController.h new file mode 100644 index 0000000..8d5e6c4 --- /dev/null +++ b/animationController.h @@ -0,0 +1,19 @@ +#ifndef ANIMATION_CONTROLLER_H +#define ANIMATION_CONTROLLER_H + +#include + +namespace vb01{ + class AnimationController{ + public: + AnimationController(); + ~AnimationController(); + void update(); + private: + protected: + void onAnimationEnd(std::string){} + void onAnimationStart(std::string){} + }; +} + +#endif diff --git a/bone.cpp b/bone.cpp index 4cd4fe4..7920757 100644 --- a/bone.cpp +++ b/bone.cpp @@ -1,5 +1,9 @@ #include"bone.h" +using namespace std; + namespace vb01{ - Bone::Bone() : Node(){} + Bone::Bone(string name, Vector3 pos) : Node(pos){ + this->name=name; + } } diff --git a/bone.h b/bone.h index 40d37ec..8866cd3 100644 --- a/bone.h +++ b/bone.h @@ -2,12 +2,16 @@ #define BONE_H #include"node.h" +#include namespace vb01{ class Bone : public Node{ public: - Bone(); + Bone(std::string,Vector3=Vector3::VEC_ZERO); + std::string getName(){return name;} private: + std::string name; + Vector3 yAxis,zAxis; }; } diff --git a/box.cpp b/box.cpp index de7bd1c..d25b236 100755 --- a/box.cpp +++ b/box.cpp @@ -64,7 +64,7 @@ namespace vb01{ Vertex v; v.pos=pos[data[3*i]]; v.norm=norm[data[3*i+1]]; - v.texCoords=tex[data[3*i+2]]; + v.uv=tex[data[3*i+2]]; vertices[i]=v; indices[i]=i; } diff --git a/light.cpp b/light.cpp index 4423e15..415c47c 100755 --- a/light.cpp +++ b/light.cpp @@ -87,8 +87,8 @@ namespace vb01{ for(Mesh *mesh : meshes){ Material *mat=mesh->getMaterial(); if(n->isVisible()&&mat&&mat->isLightingEnabled()){ - Vector3 pos=n->getWorldPosition(); - Quaternion rot=n->getWorldOrientation(); + Vector3 pos=n->localToGlobalPosition(Vector3::VEC_ZERO); + Quaternion rot=n->localToGlobalOrientation(Quaternion::QUAT_W); Vector3 rotAxis=rot.norm().getAxis(); if(rotAxis==Vector3::VEC_ZERO) diff --git a/matrix.cpp b/matrix.cpp index 1f88ade..052e6bb 100644 --- a/matrix.cpp +++ b/matrix.cpp @@ -139,13 +139,16 @@ namespace vb01{ int newRows=dim[0]-1,newColumns=dim[1]-1; float **matrix=new float*[dim[0]]; bool offsetRows=false,offsetColumns=false; + for(int i=0;imatrix[i][j]; } + else if(i==row) offsetRows=true; else if(j==column) offsetColumns=true; } @@ -155,11 +158,17 @@ namespace vb01{ void Matrix::invert(){ transpose(); float **matrix=new float*[dim[0]]; + for(int i=0;imatrix[i]; + delete[] this->matrix; + this->matrix=matrix; *this/getDeterminant(); } diff --git a/mesh.cpp b/mesh.cpp index f79499d..e066e62 100755 --- a/mesh.cpp +++ b/mesh.cpp @@ -18,10 +18,15 @@ namespace vb01{ } - Mesh::Mesh(Vertex *vertices, unsigned int *indices,int numTris){ + Mesh::Mesh(Vertex *vertices,unsigned int *indices,int numTris,VertexGroup *vertexGroups,int numVertexGroups,ShapeKey *shapeKeys,int numShapeKeys,string name){ this->vertices=vertices; this->indices=indices; this->numTris=numTris; + this->groups=vertexGroups; + this->numVertexGroups=numVertexGroups; + this->shapeKeys=shapeKeys; + this->numShapeKeys=numShapeKeys; + this->name=name; construct(); } @@ -77,7 +82,7 @@ namespace vb01{ glEnableVertexAttribArray(0); glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),(void*)(offsetof(Vertex,norm))); glEnableVertexAttribArray(1); - glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,sizeof(Vertex),(void*)(offsetof(Vertex,texCoords))); + glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,sizeof(Vertex),(void*)(offsetof(Vertex,uv))); glEnableVertexAttribArray(2); glVertexAttribPointer(3,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),(void*)(offsetof(Vertex,tan))); glEnableVertexAttribArray(3); @@ -94,10 +99,8 @@ namespace vb01{ Quaternion orient=Quaternion::QUAT_W; if(node){ - Node::Transform t=node->getWorldTransform(); - - pos=t.position; - orient=t.orientation; + pos=node->localToGlobalPosition(Vector3::VEC_ZERO); + orient=node->localToGlobalOrientation(Quaternion::QUAT_W); camPos=cam->getPosition(); } @@ -120,8 +123,8 @@ namespace vb01{ for(Node *n : descendants){ for(Mesh *m : n->getMeshes()) if(m!=this){ - Vector3 position=n->getWorldPosition(); - Quaternion rotation=n->getWorldOrientation(); + Vector3 position=n->localToGlobalPosition(Vector3::VEC_ZERO); + Quaternion rotation=n->localToGlobalOrientation(Quaternion::QUAT_W); Vector3 rotAxis=rotation.norm().getAxis(); if(rotAxis==Vector3::VEC_ZERO) @@ -188,4 +191,24 @@ namespace vb01{ glPolygonMode(GL_FRONT_AND_BACK,wireframe?GL_LINE:GL_FILL); glDrawElements(GL_TRIANGLES,3*numTris,GL_UNSIGNED_INT,0); } + + Mesh::VertexGroup& Mesh::getVertexGroup(string name){ + int id=-1; + for(int i=0;imaterial=mat;} + VertexGroup& getVertexGroup(std::string); + ShapeKey& getShapeKey(std::string); inline void setNode(Node *node){this->node=node;} inline void setCastShadow(bool castShadow){this->castShadow=castShadow;} inline void setReflect(bool r){this->reflect=r;} inline void setWireframe(bool w){this->wireframe=w;} + inline void setSkeleton(Skeleton *sk){this->skeleton=sk;} inline Node* getNode(){return node;} inline Material* getMaterial(){return material;} inline std::vector& getMeshes(){return meshes;} inline bool isCastShadow(){return castShadow;} inline int getNumVerts(){return 3*numTris;} inline Vertex* getVerts(){return vertices;} + inline std::string getName(){return name;} + inline Skeleton* getSkeleton(){return skeleton;} inline unsigned int* getIndices(){return indices;} private: Shader *environmentShader=nullptr; @@ -59,9 +70,10 @@ namespace vb01{ bool staticVerts=true,castShadow=false,reflect=false,wireframe=false; Vertex *vertices; - VertexGroup groups; + VertexGroup *groups; + ShapeKey *shapeKeys; unsigned int *indices,VAO,VBO,EBO; - int numTris; + int numTris,numVertexGroups=0,numShapeKeys=0; }; } diff --git a/model.cpp b/model.cpp index be41d31..1f122fe 100755 --- a/model.cpp +++ b/model.cpp @@ -3,6 +3,11 @@ #include"material.h" #include"vector.h" #include"util.h" +#include"bone.h" +#include"root.h" +#include"skeleton.h" +#include"animation.h" + #include #include #include @@ -49,11 +54,11 @@ namespace vb01{ v.biTan.z=mesh->mBitangents[i].z; if(mesh->mTextureCoords[0]){ - v.texCoords.x=mesh->mTextureCoords[0][i].x; - v.texCoords.y=mesh->mTextureCoords[0][i].y; + v.uv.x=mesh->mTextureCoords[0][i].x; + v.uv.y=mesh->mTextureCoords[0][i].y; } else - v.texCoords=Vector2::VEC_ZERO; + v.uv=Vector2::VEC_ZERO; vertices[i]=v; } for(int i=0;igetRootNode(); if(b){ Importer importer; const aiScene *scene=importer.ReadFile(path,aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals | aiProcess_CalcTangentSpace); @@ -79,130 +85,319 @@ namespace vb01{ processNode(scene->mRootNode,scene,this); } else{ - int numTris,numVerts,numGroups,v=0,u=0,vg=0,b=0; - Mesh::Vertex *vertices; - Mesh::VertexGroup *groups=new Mesh::VertexGroup[5]; - unsigned int *indices; - Vector3 *pos,*norm; - + enum Stage{ARMATURE,MESH}; + + Stage stage; ifstream in(path); - string l; - bool verts=false,uv=false,vertexGroups=false,bones=false; - + string l,name=""; + Vector3 localPos=Vector3::VEC_ZERO,localScale=Vector3::VEC_IJK; + Quaternion localRot=Quaternion::QUAT_W; + vector childrenChain; + vector skeletons; + vector meshes; + vector lights; + vector nodes; + + Skeleton *skeleton=nullptr; + string animName=""; + Bone *animBone=nullptr; + + vector vertPos,vertNorm; + const int numVertsPerFace=3; + int numVertPos=0,numFaces=0,vertId=0,faceId=0,groupId=-1,groupVertId=0,numGroups=0,numShapeKeys=0; + Mesh::Vertex *vertices; + u32 *indices; + Mesh::VertexGroup *groups=nullptr; + Mesh::ShapeKey *shapeKeys=nullptr; + while(getline(in,l)){ - if(l.substr(0,8)=="numFaces"){ - numTris=atoi(l.substr(9,string::npos).c_str()); - vertices=new Mesh::Vertex[numTris*3]; - indices=new unsigned int[numTris*3]; - } - else if(l.substr(0,11)=="numVertices"){ - numVerts=atoi(l.substr(12,string::npos).c_str()); - pos=new Vector3[numVerts]; - norm=new Vector3[numVerts]; - } - else if(l.substr(0,9)=="numGroups"){ - numGroups=atoi(l.substr(10,string::npos).c_str()); - groups=new Mesh::VertexGroup[numGroups]; - } - if(l=="vertices:"){ - verts=true; + int colonId=-1; + for(int i=0;igetBone(parName); + if(!parent) + parent=this; + + Bone *bone=new Bone(preColon); + skeleton->addBone(bone,parent); + bone->setPosition(parent->globalToLocalPosition(pos)); + bone->lookAt(yAxis,zAxis,parent); + + break; } - float *coords=new float[numCoords]; - for(int i=0;iaddAnimation(new Animation(animName)); + continue; + } + Bone *b=skeleton->getBone(preColon); + if(b){ + animBone=b; + Animation *anim=skeleton->getAnimation(animName); + Animation::KeyframeGroup *group=anim->getKeyframeGroup(animBone); + if(!group){ + Animation::KeyframeGroup kg; + kg.bone=animBone; + anim->addKeyframeGroup(kg); + } + continue; + } + else{ + Animation::KeyframeGroup::Keyframe::Type type; + Animation::KeyframeGroup::Keyframe::Interpolation interp; + if(preColon=="pos_x") + type=Animation::KeyframeGroup::Keyframe::Type::POS_X; + else if(preColon=="pos_y") + type=Animation::KeyframeGroup::Keyframe::Type::POS_Y; + else if(preColon=="pos_z") + type=Animation::KeyframeGroup::Keyframe::Type::POS_Z; + else if(preColon=="rot_w") + type=Animation::KeyframeGroup::Keyframe::Type::ROT_W; + else if(preColon=="rot_x") + type=Animation::KeyframeGroup::Keyframe::Type::ROT_X; + else if(preColon=="rot_y") + type=Animation::KeyframeGroup::Keyframe::Type::ROT_Y; + else if(preColon=="rot_z") + type=Animation::KeyframeGroup::Keyframe::Type::ROT_Z; + else if(l==""){ + skeletons.push_back(skeleton); + break; + } + else{ + int numData=3; + string data[numData]; + + getLineData(l,data,numData); + + float value=atof(data[0].c_str()),frame=atoi(data[1].c_str()); + interp=(Animation::KeyframeGroup::Keyframe::Interpolation)atoi(data[2].c_str()); + + Animation::KeyframeGroup::Keyframe keyframe; + keyframe.type=type; + keyframe.interpolation=interp; + keyframe.value=value; + keyframe.frame=frame; + skeleton->getAnimation(animName)->getKeyframeGroup(animBone)->keyframes.push_back(keyframe); + } } - for(int i=0;i<3*numTris;i++) - for(int j=0;j0){ + groups[groupId].vertices=new u32[numVerts]; + groups[groupId].weights=new float[numVerts]; + } + } + else{ + int numData=2,vertId; + float weight; + string data[numData]; + getLineData(l,data,numData); + vertId=atoi(data[0].c_str()); + weight=atof(data[1].c_str()); + groups[groupId].vertices[groupVertId]=vertId; + groups[groupId].weights[groupVertId]=weight; + groupVertId++; + } + break; + } + { + case SHAPE_KEYS: + if(l==""){ + meshes.push_back(new Mesh(vertices,indices,numFaces,groups,numGroups,shapeKeys,numShapeKeys,name)); + break; + } + break; + } } - delete[] coords; } } - delete[] pos; - delete[] norm; - attachChild(new Node()); - children[0]->attachMesh(new Mesh(vertices,indices,numTris)); + for(Mesh *mesh : meshes){ + Node *meshNode=new Node(localPos,localRot,localScale); + meshNode->attachMesh(mesh); + nodes.push_back(meshNode); + for(string line : childrenChain){ + int spaceId=-1; + for(int i=0;igetName()==childName){ + for(Skeleton *sk : skeletons){ + if(sk->getName()==parentName) + mesh->setSkeleton(sk); + } + } + } + } + for(Light *light : lights){ + Node *lightNode=new Node(localPos,localRot,localScale); + lightNode->addLight(light); + nodes.push_back(lightNode); + } + for(string line : childrenChain){ + int spaceId=-1; + for(int i=0;igetMesh(0); + Skeleton *sk0=m0->getSkeleton(); + if(m0->getName()==childName||(sk0&&sk0->getName()==childName)){ + childNode=nodes[i]; + for(int j=0;jgetMesh(0); + Skeleton *sk1=m1->getSkeleton(); + if(m1->getName()==parentName||(sk1&&sk1->getName()==parentName)) + parentNode=nodes[j]; + } + } + } + if(childNode!=parentNode) + parentNode->attachChild(childNode); + } } } @@ -226,6 +421,26 @@ namespace vb01{ Node::update(); } + void Model::getLineData(string &line,string data[],int numData,int offset){ + int offsetComma=0,c1=0; + for(int i=0;i descendants; getDescendants(this,descendants); diff --git a/model.h b/model.h index 6be023f..b76ae8d 100755 --- a/model.h +++ b/model.h @@ -29,6 +29,7 @@ namespace vb01{ void processMesh(aiMesh*, const aiScene*, Node*); // std::vector processTexture(aiMaterial*, Assimp::aiTextureType); void processMaterial(); + void getLineData(std::string&,std::string[],int,int=0); Material* material; bool castShadow=false,reflect=false,wireframe=false; diff --git a/node.cpp b/node.cpp index fb3704a..c20e136 100755 --- a/node.cpp +++ b/node.cpp @@ -6,14 +6,21 @@ #include"text.h" #include"material.h" #include"matrix.h" +#include +#include using namespace std; +using namespace glm; namespace vb01{ - Node::Node(Vector3 pos, Quaternion orientation, Vector3 scale){ + Node::Node(Vector3 pos, Quaternion orientation, Vector3 scale,string name){ this->pos=pos; this->scale=scale; this->orientation=orientation; + this->name=name; + axis[0]=Vector3::VEC_I; + axis[1]=Vector3::VEC_J; + axis[2]=Vector3::VEC_K; } Node::~Node(){ @@ -49,6 +56,7 @@ namespace vb01{ void Node::attachChild(Node *child){ child->setParent(this); children.push_back(child); + child->updateLocalAxis(); } void Node::dettachChild(Node *child){ @@ -91,15 +99,33 @@ namespace vb01{ text->setNode(this); } - void Node::lookAt(Vector3 newDir,Vector3 upDir){ - Vector3 dir=getLocalAxis(2).norm(),newDirLocal=globalToLocal(newDir.norm()),upDirLocal=globalToLocal(upDir.norm()); - float angle=dir.getAngleBetween(newDirLocal); - Vector3 rotAxis=dir.cross(newDirLocal); - orientation=Quaternion(angle,rotAxis)*orientation; - Vector3 up=getLocalAxis(1).norm(); - angle=up.getAngleBetween(upDirLocal); - rotAxis=up.cross(upDirLocal); - orientation=Quaternion(angle,rotAxis.norm())*orientation; + void Node::lookAt(Vector3 newDir,Vector3 newUp,Node *node){ + newDir=node->localToGlobalPosition(newDir); + newUp=node->localToGlobalPosition(newUp); + float angle=axis[2].getAngleBetween(newDir); + Vector3 rotAxis=axis[2].cross(newDir).norm(); + if(rotAxis==Vector3::VEC_ZERO) + rotAxis=axis[1]; + //setOrientation((Quaternion(angle,rotAxis)*(orientation))); + setOrientation(node->globalToLocalOrientation(Quaternion(angle,rotAxis)*node->localToGlobalOrientation(orientation))); + + mat3 mat; + mat[0][0]=axis[0].x; + mat[1][0]=axis[0].y; + mat[2][0]=axis[0].z; + mat[0][1]=axis[1].x; + mat[1][1]=axis[1].y; + mat[2][1]=axis[1].z; + mat[0][2]=axis[2].x; + mat[1][2]=axis[2].y; + mat[2][2]=axis[2].z; + mat=inverse(mat); + vec3 nu=vec3(newUp.x,newUp.y,newUp.z)*mat; + newUp=(axis[0]*nu.x+axis[1]*nu.y).norm(); + angle=axis[1].getAngleBetween(newUp); + //setOrientation((Quaternion(angle*(nu.x<0?1:-1),axis[2])*(orientation))); + setOrientation(node->globalToLocalOrientation(Quaternion(angle*(nu.x<0?1:-1),axis[2])*node->localToGlobalOrientation(orientation))); + //setOrientation(node->globalToLocalOrientation(Quaternion(angle,axis[2])*node->localToGlobalOrientation(orientation))); } void Node::getDescendants(Node *node, vector &descendants){ @@ -111,111 +137,116 @@ namespace vb01{ } } - Node::Transform Node::getWorldTransform(){ - Transform t; - Vector3 scale=Vector3::VEC_IJK; - Quaternion orient=Quaternion::QUAT_W; - Vector3 origin=Vector3::VEC_ZERO,axis[]={Vector3::VEC_I,Vector3::VEC_J,Vector3::VEC_K}; + void Node::updateLocalAxis(){ + Node *rootNode=Root::getSingleton()->getRootNode(),*par=this; + while(par->getParent()) + par=par->getParent(); + if(par!=rootNode) + return; + + Vector3 parAxis[3]={ + parent->getLocalAxis(0), + parent->getLocalAxis(1), + parent->getLocalAxis(2) + }; + + for(int i=0;i<3;i++) + axis[i]=(orientation*parAxis[i]).norm(); + for(Node *ch : children) + ch->updateLocalAxis(); + } + + Vector3 Node::localToGlobalPosition(Vector3 localPos){ + Vector3 origin=Vector3::VEC_ZERO; vector ancestors; ancestors.push_back(this); Node *parent=this->getParent(); + while(parent){ ancestors.push_back(parent); parent=parent->getParent(); } + while(!ancestors.empty()){ int id=ancestors.size()-1; - Quaternion o=ancestors[id]->getOrientation(); - Vector3 p=ancestors[id]->getPosition(),s=ancestors[id]->getScale(); - origin=origin+axis[0]*p.x*s.x+axis[1]*p.y*s.y+axis[2]*p.z*s.z; - orient=o*orient; - scale=s; - for(int i=0;i<3;i++) - axis[i]=orient*axis[i]; + Node *par=ancestors[id]->getParent(); + Vector3 parAxis[]={ + par?par->getLocalAxis(0):Vector3::VEC_I, + par?par->getLocalAxis(1):Vector3::VEC_J, + par?par->getLocalAxis(2):Vector3::VEC_K + }; + Vector3 p=ancestors[id]->getPosition(); + origin=origin+parAxis[0]*p.x+parAxis[1]*p.y+parAxis[2]*p.z; ancestors.pop_back(); } - - t.position=origin,t.orientation=orient,t.scale=scale; - return t; + return origin+axis[0]*localPos.x+axis[1]*localPos.y+axis[2]*localPos.z; } - Vector3 Node::getLocalAxis(int i){ - Transform t; - Vector3 pos=Vector3::VEC_ZERO,scale=Vector3::VEC_IJK; - Quaternion orient=Quaternion::QUAT_W; - Vector3 origin=Vector3::VEC_ZERO,axis[]={Vector3::VEC_I,Vector3::VEC_J,Vector3::VEC_K}; + Vector3 Node::globalToLocalPosition(Vector3 globalPos){ + Vector3 origin=globalPos; vector ancestors; ancestors.push_back(this); Node *parent=this->getParent(); + while(parent){ ancestors.push_back(parent); parent=parent->getParent(); } + while(!ancestors.empty()){ - int id=ancestors.size()-1; - Quaternion o=ancestors[id]->getOrientation(); - Vector3 p=ancestors[id]->getPosition(),s=ancestors[id]->getScale(); - origin=origin+axis[0]*p.x*s.x+axis[1]*p.y*s.y+axis[2]*p.z*s.z; - orient=o*orient; - scale=s; - for(int i=0;i<3;i++) - axis[i]=orient*axis[i]; - ancestors.pop_back(); + int id=0; + Node *par=ancestors[id]->getParent(); + Vector3 parAxis[]={ + par?par->getLocalAxis(0):Vector3::VEC_I, + par?par->getLocalAxis(1):Vector3::VEC_J, + par?par->getLocalAxis(2):Vector3::VEC_K + }; + Vector3 p=ancestors[id]->getPosition(); + origin=origin-parAxis[0]*p.x-parAxis[1]*p.y-parAxis[2]*p.z; + ancestors.erase(ancestors.begin()); + } + //return origin+axis[0]*localPos.x+axis[1]*localPos.y+axis[2]*localPos.z; + return origin; + } + + Quaternion Node::localToGlobalOrientation(Quaternion localRot){ + Quaternion origin=Quaternion::QUAT_W; + vector ancestors; + ancestors.push_back(this); + Node *parent=this->getParent(); + + while(parent){ + ancestors.push_back(parent); + parent=parent->getParent(); } - return axis[i]; + while(!ancestors.empty()){ + int id=ancestors.size()-1; + Quaternion o=ancestors[id]->getOrientation(); + origin=o*origin; + ancestors.pop_back(); + } + return localRot*origin; } - Vector3 Node::localToGlobal(Vector3 p0){ - Vector3 dir=getLocalAxis(2),up=getLocalAxis(1),left=getLocalAxis(0); - float **mat=new float*[3]; - for(int i=0;i<3;i++) - mat[i]=new float[3]; + Quaternion Node::globalToLocalOrientation(Quaternion globalRot){ + Quaternion origin=globalRot; + vector ancestors; + ancestors.push_back(this); + Node *parent=this->getParent(); - mat[0][0]=left.x; - mat[1][0]=left.y; - mat[2][0]=left.z; - mat[0][1]=up.x; - mat[1][1]=up.y; - mat[2][1]=up.z; - mat[0][2]=dir.x; - mat[1][2]=dir.y; - mat[2][2]=dir.z; + while(parent){ + ancestors.push_back(parent); + parent=parent->getParent(); + } - Vector3 p=Matrix(mat,3,3)*p0; - - for(int i=0;i<3;i++) - delete[] mat[i]; - delete[] mat; - - return p; - } - - Vector3 Node::globalToLocal(Vector3 p0){ - Vector3 dir=getLocalAxis(2),up=getLocalAxis(1),left=getLocalAxis(0); - float **mat=new float*[3]; - for(int i=0;i<3;i++) - mat[i]=new float[3]; - - mat[0][0]=left.x; - mat[1][0]=left.y; - mat[2][0]=left.z; - mat[0][1]=up.x; - mat[1][1]=up.y; - mat[2][1]=up.z; - mat[0][2]=dir.x; - mat[1][2]=dir.y; - mat[2][2]=dir.z; - - Matrix m(mat,3,3); - m.invert(); - Vector3 p=m*p0; - - for(int i=0;i<3;i++) - delete[] mat[i]; - delete[] mat; - - return p; + while(!ancestors.empty()){ + int id=ancestors.size()-1; + Quaternion o=ancestors[id]->getOrientation(); + origin=origin*Quaternion(-o.getAngle(),o.getAxis()); + ancestors.pop_back(); + } + return origin; } void Node::updateShaders(){ @@ -236,4 +267,9 @@ namespace vb01{ } } } + + void Node::setOrientation(Quaternion q){ + this->orientation=q; + updateLocalAxis(); + } } diff --git a/node.h b/node.h index 977a5e7..c10fdb5 100755 --- a/node.h +++ b/node.h @@ -4,6 +4,7 @@ #include"quaternion.h" #include"vector.h" #include +#include namespace vb01{ class Mesh; @@ -15,11 +16,11 @@ namespace vb01{ class Node{ public: struct Transform{ - Vector3 position,scale; - Quaternion orientation; + Vector3 position=Vector3::VEC_ZERO,scale=Vector3::VEC_IJK; + Quaternion orientation=Quaternion::QUAT_W; }; - Node(Vector3=Vector3::VEC_ZERO,Quaternion=Quaternion::QUAT_W,Vector3=Vector3::VEC_IJK); + Node(Vector3=Vector3::VEC_ZERO,Quaternion=Quaternion::QUAT_W,Vector3=Vector3::VEC_IJK,std::string=""); virtual ~Node(); void attachMesh(Mesh*); void attachParticleEmitter(ParticleEmitter*); @@ -29,20 +30,23 @@ namespace vb01{ void addLight(Light*); void removeLight(int); void addText(Text*); - void lookAt(Vector3,Vector3); - Transform getWorldTransform(); - Vector3 getLocalAxis(int); - Vector3 localToGlobal(Vector3); - Vector3 globalToLocal(Vector3); + void lookAt(Vector3,Vector3,Node*); + void updateLocalAxis(); + void setOrientation(Quaternion); + void getDescendants(Node*,std::vector&); + Vector3 localToGlobalPosition(Vector3); + Vector3 globalToLocalPosition(Vector3); + Quaternion localToGlobalOrientation(Quaternion); + Quaternion globalToLocalOrientation(Quaternion); + Vector3 localToGlobalScale(Vector3); + Vector3 globalToLocalScale(Vector3); inline Text* getText(int i){return texts[i];} - inline Vector3 getWorldPosition(){return getWorldTransform().position;} - inline Quaternion getWorldOrientation(){return getWorldTransform().orientation;} - inline Vector3 getWorldScale(){return getWorldTransform().scale;} inline std::vector& getMeshes(){return meshes;} inline Mesh* getMesh(int i){return meshes[i];} inline Node* getParent(){return parent;} inline void setParent(Node *par){this->parent=par;} inline Node* getChild(int i){return children[i];} + inline Vector3 getLocalAxis(int i){return axis[i];} inline Vector3 getPosition(){return pos;} inline Vector3 getScale(){return scale;} inline void setPosition(Vector3 pos){this->pos=pos;} @@ -53,21 +57,21 @@ namespace vb01{ inline int getNumLights(){return lights.size();} inline int getNumChildren(){return children.size();} inline Quaternion getOrientation(){return orientation;} - inline void setOrientation(Quaternion q){this->orientation=q;} inline bool isVisible(){return visible;} + inline std::string getName(){return name;} inline void setVisible(bool v){this->visible=v;} - void getDescendants(Node*,std::vector&); protected: void updateShaders(); bool visible=true; - Vector3 pos,scale; + Vector3 pos,scale,axis[3]; Quaternion orientation; std::vector meshes; std::vector emitters; std::vector children; std::vector lights; std::vector texts; + std::string name; Node *parent=nullptr; }; } diff --git a/particleEmitter.cpp b/particleEmitter.cpp index 586063d..9829d80 100755 --- a/particleEmitter.cpp +++ b/particleEmitter.cpp @@ -139,7 +139,7 @@ namespace vb01{ shader->setVec2(startSize,"startSize"); shader->setVec2(endSize,"endSize"); - Vector3 nodePos=node->getWorldTransform().position; + Vector3 nodePos=node->localToGlobalPosition(Vector3::VEC_ZERO); Vector3 nodeDir=node->getLocalAxis(2); Vector3 nodeUp=node->getLocalAxis(1); Vector3 nodeLeft=node->getLocalAxis(0); diff --git a/quad.cpp b/quad.cpp index 27e86f6..cfed173 100755 --- a/quad.cpp +++ b/quad.cpp @@ -36,22 +36,22 @@ namespace vb01{ v6.pos=Vector3(size.x,0,0); } v1.norm=Vector3(0,0,-1); - v1.texCoords=Vector2(1,1); + v1.uv=Vector2(1,1); v2.norm=Vector3(0,0,-1); - v2.texCoords=Vector2(0,1); + v2.uv=Vector2(0,1); v3.norm=Vector3(0,0,-1); - v3.texCoords=Vector2(0,0); + v3.uv=Vector2(0,0); v4.norm=Vector3(0,0,-1); - v4.texCoords=Vector2(0,0); + v4.uv=Vector2(0,0); v5.norm=Vector3(0,0,-1); - v5.texCoords=Vector2(1,0); + v5.uv=Vector2(1,0); v6.norm=Vector3(0,0,-1); - v6.texCoords=Vector2(1,1); + v6.uv=Vector2(1,1); indices[0]=0; indices[1]=1; diff --git a/quaternion.h b/quaternion.h index 359a447..358084d 100755 --- a/quaternion.h +++ b/quaternion.h @@ -50,6 +50,7 @@ namespace vb01{ } inline Quaternion norm(){return *this/getLength();} inline Quaternion recip(){return conj()/getLengthSq();} + inline Quaternion invert(){return conj()/(getLengthSq());} inline float getLengthSq(){return w*w+x*x+y*y+z*z;} inline float getLength(){return std::sqrt(getLengthSq());} diff --git a/ray.cpp b/ray.cpp index b8de292..ac23fdc 100644 --- a/ray.cpp +++ b/ray.cpp @@ -7,8 +7,8 @@ using namespace std; namespace vb01{ void retrieveCollisions(Vector3 rayPos, Vector3 rayDir,Node *node,std::vector &results, const float rayLength){ - Vector3 pos=node->getWorldPosition(); - Quaternion rot=node->getWorldOrientation(); + Vector3 pos=node->localToGlobalPosition(Vector3::VEC_ZERO); + Quaternion rot=node->localToGlobalOrientation(Quaternion::QUAT_W); for(Mesh *m : node->getMeshes()){ const int numVerts=m->getNumVerts(); Mesh::Vertex *vertices=m->getVerts(); diff --git a/root.cpp b/root.cpp index 2f660c7..809ee16 100755 --- a/root.cpp +++ b/root.cpp @@ -31,7 +31,7 @@ namespace vb01{ camera=new Camera(); } - void Root::start(int width,int height){ + void Root::start(int width,int height,string name){ this->width=width; this->height=height; @@ -39,7 +39,7 @@ namespace vb01{ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3); glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE); - window=glfwCreateWindow(width,height,"KEK",NULL,NULL); + window=glfwCreateWindow(width,height,name.c_str(),NULL,NULL); if(window==NULL){ std::cout<<"Failed to load window.\n"; exit(-1); diff --git a/root.h b/root.h index 84f10b0..4bd5faa 100755 --- a/root.h +++ b/root.h @@ -20,7 +20,7 @@ namespace vb01{ class Root{ public: void update(); - void start(int,int); + void start(int,int,std::string); inline Camera* getCamera(){return camera;} inline Node* getRootNode(){return rootNode;} inline Node* getGuiNode(){return guiNode;} diff --git a/script.py b/script.py index 77e37f7..9bef5d2 100644 --- a/script.py +++ b/script.py @@ -2,25 +2,18 @@ import sys def exportData(ob): par=ob.parent - file.write(ob.name+"\n") + file.write(ob.type+": "+ob.name+"\n") file.write("pos: "+str(ob.location.x)+" "+str(ob.location.y)+" "+str(ob.location.z)+"\n") file.write("rot: "+str(ob.rotation_quaternion.w)+" "+str(ob.rotation_quaternion.x)+" "+str(ob.rotation_quaternion.y)+" "+str(-ob.rotation_quaternion.z)+"\n") file.write("scale: "+str(ob.scale.x)+" "+str(ob.scale.y)+" "+str(ob.scale.z)+"\n") - file.write("parent: "+('None' if par is None else par.name)+"\n") + file.write("parent: "+('-' if par is None else par.name)+"\n") if(ob.type=="ARMATURE"): file.write("bones: "+str(len(ob.data.bones))) for bone in ob.data.bones: - tail=bone.tail head=bone.head - file.write("\n"+bone.name+": "+str(head.x)+" "+str(head.y)+" "+str(head.z)+" "+str(tail.x)+" "+str(tail.y)+" "+str(tail.z)) - - file.write("\nboneHierarchy:") - for bone in ob.data.bones: - numChildren=len(bone.children) - if numChildren>0: - file.write('\n'+bone.name+' '+str(numChildren)+':') - for ch in bone.children: - file.write(' '+ch.name) + xAxis=bone.x_axis + yAxis=bone.y_axis + file.write("\n"+bone.name+": "+('None' if bone.parent is None else bone.parent.name)+" "+str(bone.length)+" "+str(head.x)+" "+str(head.y)+" "+str(head.z)+" "+str(xAxis.x)+" "+str(xAxis.y)+" "+str(xAxis.z)+" "+str(yAxis.x)+" "+str(yAxis.y)+" "+str(yAxis.z)+" ") numAnims=len(ob.animation_data.nla_tracks[0].strips) if numAnims>0: @@ -29,7 +22,7 @@ def exportData(ob): animName=nlaStrip.name action=bpy.data.actions[animName] numAnimBones=len(action.groups) - file.write("\n"+animName+": "+str(numAnimBones)+"\n") + file.write("\nanimationName: "+animName+"\n") print('Exporting animation '+animName+'...\n') for group in action.groups: @@ -56,13 +49,22 @@ def exportData(ob): file.write("rot_"+coords[arrInd]) elif coordType=="scale": file.write("scale_"+coords[arrInd+1]) - file.write(' '+str(numKeyframes)+':\n') + file.write(': '+str(numKeyframes)+'\n') for keyframe in channel.keyframe_points: keyframeId=keyframe.co[0] interp=keyframe.interpolation bpy.context.scene.frame_set(int(start)+int(keyframeId)) poseBone=ob.pose.bones[group.name] + interpInt=-1 + + if interp=='CONSTANT': + interpInt=0 + elif interp=='LINEAR': + interpInt=1 + elif interp=='BEZIER': + interpInt=2 + if bpy.context.scene.frame_current>end: bpy.context.scene.frame_current=bpy.context.scene.frame_current-1 if coordType=="location": @@ -71,7 +73,7 @@ def exportData(ob): file.write(str(poseBone.rotation_quaternion[arrInd])) elif coordType=="scale": file.write(str(poseBone.scale[arrInd])) - file.write(" "+str(keyframeId)+" "+interp) + file.write(" "+str(keyframeId)+" "+str(interpInt)) if interp=='BEZIER': file.write(" "+str(keyframe.handle_left_type)+" "+str(keyframe.handle_left.x)+" "+str(keyframe.handle_left.y)+" ") file.write(str(keyframe.handle_right_type)+" "+str(keyframe.handle_right.x)+" "+str(keyframe.handle_right.y)) @@ -86,31 +88,56 @@ def exportData(ob): #if mesh.shape_keys is not NoneType: #numShapeKeys=len(mesh.shape_keys[0].key_blocks)-1 - file.write("vertices: "+str(numVerts)+","+str(numFaces)+"\n") + file.write("vertices: "+str(numVerts)+" "+str(numFaces)+" \n") print('Exporting vertices...\n') for vert in mesh.vertices: pos=vert.co norm=vert.normal - file.write(str(pos.x)+" "+str(pos.y)+" "+str(pos.z)+" "+str(norm.x)+" "+str(norm.y)+" "+str(norm.z)+"\n") - - file.write("uv:\n") - print('Exporting texture coordinates...\n') + file.write(str(pos.x)+" "+str(pos.y)+" "+str(pos.z)+" "+str(norm.x)+" "+str(norm.y)+" "+str(norm.z)+" \n") + ''' for face in mesh.polygons: - for vert,loop in zip(face.vertices,face.loop_indices): - uv=mesh.uv_layers[0].data[loop].uv - file.write(str(vert)+" "+str(uv.x)+" "+str(uv.y)+"\n") - + for vert,loop in zip(face.vertices,mesh.loops): + pos=mesh.vertices[vert].co + norm=mesh.vertices[vert].normal + uv=mesh.uv_layers[0].data[loop.index].uv + tan=loop.tangent + bitan=loop.bitangent + file.write(str(pos.x)+" "+str(pos.y)+" "+str(pos.z)+" "+str(norm.x)+" "+str(norm.y)+" "+str(norm.z)+str(uv.x)+" "+str(uv.y)+" "+str(tan.x)+" "+str(tan.y)+" "+str(tan.z)+" "+str(bitan.x)+" "+str(bitan.y)+" "+str(bitan.z)+" \n") + ''' + + file.write("faces:\n") + print('Exporting faces...\n') + mesh.calc_tangents() + for face in mesh.polygons: + for vert,loopInd in zip(face.vertices,face.loop_indices): + uv=mesh.uv_layers[0].data[loopInd].uv + loop=mesh.loops[loopInd] + tan=loop.tangent + bitan=loop.bitangent + file.write(str(vert)+" "+str(uv.x)+" "+str(uv.y)+" "+str(tan.x)+" "+str(tan.y)+" "+str(tan.z)+" "+str(bitan.x)+" "+str(bitan.y)+" "+str(bitan.z)+" \n") + mesh.free_tangents() + if numGroups>0: + groupVerts=[] file.write("groups: "+str(numGroups)+"\n") print('Exporting vertex groups...\n') - for group in ob.vertex_groups: - file.write(group.name+":\n") + for i in range(0,numGroups): + groupVerts.append([]) + for vert in mesh.vertices: + for g in vert.groups: + if g.group==ob.vertex_groups[i].index: + groupVerts[i].append(vert.index) + + for i in range(0,numGroups): + group=ob.vertex_groups[i] + file.write(group.name+": "+str(len(groupVerts[i]))+"\n") for vert in mesh.vertices: for g in vert.groups: if g.group==group.index: - file.write(str(vert.index)+" "+str(g.weight)+"\n") + file.write(str(vert.index)+" "+str(g.weight)+" \n") + if numShapeKeys>0: - file.write('shape keys:\n') + file.write('shapeKeys:\n') print('Exporting shape keys...\n') for shape_key in mesh.shape_keys.key_blocks: if shape_key.name=='Basis': @@ -120,7 +147,14 @@ def exportData(ob): if(newPos!=mesh.vertices[i].co): file.write('\n'+str(i)+" "+str(newPos.x)+' '+str(newPos.y)+' '+str(newPos.z)) -fl="/home/dominykas/c++/vb01/kek.vb"; +fl=bpy.data.filepath +dotId=0 +for i in range(len(fl)): + if(fl[i]=='.'): + dotId=i + break +fl=fl[0:dotId]+".vb" + objects=[] selectedObjects=bpy.context.selected_objects diff --git a/skeleton.cpp b/skeleton.cpp index 44faddf..261072a 100644 --- a/skeleton.cpp +++ b/skeleton.cpp @@ -1,5 +1,35 @@ #include"skeleton.h" +#include"animation.h" + +using namespace std; namespace vb01{ - Skeleton::Skeleton(){} + Skeleton::Skeleton(string name){ + this->name=name; + } + + void Skeleton::addBone(Bone *bone, Node *parent){ + parent->attachChild(bone); + bones.push_back(bone); + } + + Bone* Skeleton::getBone(string name){ + Bone *bone=nullptr; + for(Bone *b : bones) + if(b->getName()==name){ + bone=b; + break; + } + return bone; + } + + Animation* Skeleton::getAnimation(string name){ + Animation *anim=nullptr; + for(Animation *a : animations) + if(a->getName()==name){ + anim=a; + break; + } + return anim; + } } diff --git a/skeleton.h b/skeleton.h index 9a1b56b..d993af0 100644 --- a/skeleton.h +++ b/skeleton.h @@ -1,11 +1,27 @@ #ifndef SKELETON_H #define SKELETON_H +#include +#include +#include"bone.h" + namespace vb01{ + class Animation; + class Skeleton{ public: - Skeleton(); + Skeleton(std::string=""); + void addBone(Bone*,Node*); + Bone* getBone(std::string); + Animation* getAnimation(std::string); + inline void addAnimation(Animation *anim){animations.push_back(anim);} + inline Bone* getBone(int i){return bones[i];} + inline std::vector& getBones(){return bones;} + inline std::string getName(){return name;} private: + std::string name; + std::vector bones; + std::vector animations; }; }