c++ - FBX Sdk Skeletal Animations -
i have loaded , rendered fbx model using fbx sdk , directx. i'm trying implement skeletal animations. first i'm trying put character on different poses modifying bones matrices. (so can achieve animations setting different poses @ times)
here's code of loading fbx , skinning information.
fbxloader.h
#include <fbxsdk.h> #include <vector> #include <string> #include <map> #include <d3d11_1.h> #include <directxmath.h> #include "textureloader.h" using namespace directx; struct vertex { xmfloat3 pos; xmfloat2 tex; xmfloat4 boneids; xmfloat4 weights; vertex() { boneids = { 0, 0, 0, 0 }; weights = { 0, 0, 0, 0 }; } }; struct keyframe { fbxlonglong mframenum; fbxamatrix mglobaltransform; keyframe* mnext; keyframe() : mnext(nullptr) {} }; struct joint { int mparentindex; const char* mname; fbxamatrix mglobalbindposeinverse; keyframe* manimation; fbxnode *mnode; joint() : mnode(nullptr), manimation(nullptr) { mglobalbindposeinverse.setidentity(); mparentindex = -1; } ~joint() { while (manimation) { keyframe* temp = manimation->mnext; delete manimation; manimation = temp; } } }; struct skeleton { std::vector<joint> mjoints; }; class mesh { public: mesh(id3d11device *dev, std::vector<vertex> vertices, id3d11shaderresourceview *texture) { this->vertices = vertices; this->texture = texture; this->setupmesh(dev); } void draw(id3d11devicecontext *devcon) { uint stride = sizeof(vertex); uint offset = 0; devcon->iasetvertexbuffers(0, 1, &vertexbuffer, &stride, &offset); if (this->texture != nullptr) devcon->pssetshaderresources(0, 1, &texture); devcon->draw(vertices.size(), 0); } private: std::vector<vertex> vertices; id3d11shaderresourceview *texture = nullptr; id3d11buffer* vertexbuffer; bool setupmesh(id3d11device *dev) { hresult hr; d3d11_buffer_desc vbd; vbd.usage = d3d11_usage_immutable; vbd.bytewidth = sizeof(vertex) * vertices.size(); vbd.bindflags = d3d11_bind_vertex_buffer; vbd.cpuaccessflags = 0; vbd.miscflags = 0; d3d11_subresource_data initdata; initdata.psysmem = &vertices[0]; hr = dev->createbuffer(&vbd, &initdata, &vertexbuffer); if (failed(hr)) return false; } }; class fbxloader { public: fbxloader(); ~fbxloader(); void loadfbx(hwnd hwnd, id3d11device *dev, id3d11devicecontext *devcon, const char* filename); void draw(id3d11devicecontext *devcon); xmmatrix getanimatedmatrix(int index); skeleton skeleton; private: fbxmanager *fbxsdkmanager = nullptr; fbxscene *fbxscene; std::map<int, int> controlpoints; std::vector<mesh> meshes; hwnd hwnd; void processnode(id3d11device *dev, id3d11devicecontext *devcon, fbxnode *node, fbxgeometryconverter *gconverter); mesh processmesh(id3d11device* dev, id3d11devicecontext *devcon, fbxmesh *mesh); void processskeletonheirarchy(fbxnode* rootnode); void processskeletonheirarchyre(fbxnode* node, int depth, int index, int parentindex); unsigned int findjointindex(const std::string& jointname); id3d11shaderresourceview *loadtexture(id3d11device *dev, id3d11devicecontext *devcon, const char* texturefilename); };
fbxloader.cpp
#include "fbxloader.h" fbxloader::fbxloader() { } fbxloader::~fbxloader() { } void fbxloader::loadfbx(hwnd hwnd, id3d11device * dev, id3d11devicecontext *devcon, const char * filename) { if (fbxsdkmanager == nullptr) { fbxsdkmanager = fbxmanager::create(); fbxiosettings* iosettings = fbxiosettings::create(fbxsdkmanager, iosroot); fbxsdkmanager->setiosettings(iosettings); } fbximporter *importer = fbximporter::create(fbxsdkmanager, ""); fbxscene = fbxscene::create(fbxsdkmanager, ""); fbxgeometryconverter gconverter(fbxsdkmanager); bool bsuccess = importer->initialize(filename, -1, fbxsdkmanager->getiosettings()); bsuccess = importer->import(fbxscene); importer->destroy(); fbxnode *fbxrootnode = fbxscene->getrootnode(); processskeletonheirarchy(fbxrootnode); this->hwnd = hwnd; processnode(dev, devcon, fbxrootnode, &gconverter); } void fbxloader::draw(id3d11devicecontext * devcon) { (int = 0; < meshes.size(); i++) { meshes[i].draw(devcon); } } xmmatrix fbxloader::getanimatedmatrix(int index) { xmmatrix bonematxm; fbxamatrix bonemat = skeleton.mjoints[index].mglobalbindposeinverse; //* skeleton.mjoints[0].manimation->mglobaltransform; bonematxm = xmmatrixtranslation(bonemat.gett().mdata[0], bonemat.gett().mdata[1], bonemat.gett().mdata[2]); bonematxm *= xmmatrixrotationx(bonemat.getr().mdata[0]); bonematxm *= xmmatrixrotationy(bonemat.getr().mdata[1]); bonematxm *= xmmatrixrotationz(bonemat.getr().mdata[2]); return bonematxm; } void fbxloader::processnode(id3d11device * dev, id3d11devicecontext *devcon, fbxnode * node, fbxgeometryconverter * gconverter) { if (node) { if (node->getnodeattribute() != nullptr) { fbxnodeattribute::etype attributetype = node->getnodeattribute()->getattributetype(); if (attributetype == fbxnodeattribute::emesh) { fbxmesh *mesh; mesh = (fbxmesh*)gconverter->triangulate(node->getnodeattribute(), true); meshes.push_back(processmesh(dev, devcon, mesh)); } } (int = 0; < node->getchildcount(); i++) { processnode(dev, devcon, node->getchild(i), gconverter); } } } mesh fbxloader::processmesh(id3d11device * dev, id3d11devicecontext *devcon, fbxmesh * mesh) { std::vector<vertex> meshvertices; id3d11shaderresourceview *meshtexture = nullptr; fbxvector4 *vertices = mesh->getcontrolpoints(); (int j = 0; j < mesh->getpolygoncount(); j++) { int numvertices = mesh->getpolygonsize(j); fbxlayerelementarraytemplate<fbxvector2> *uvvertices = 0; mesh->gettextureuv(&uvvertices, fbxlayerelement::etexturediffuse); (int k = 0; k < numvertices; k++) { int controlpointindex = mesh->getpolygonvertex(j, k); vertex vertex; vertex.pos.x = (float)vertices[controlpointindex].mdata[0]; vertex.pos.y = (float)vertices[controlpointindex].mdata[1]; vertex.pos.z = (float)vertices[controlpointindex].mdata[2]; vertex.tex.x = (float)uvvertices->getat(mesh->gettextureuvindex(j, k)).mdata[0]; vertex.tex.y = 1.0f - (float)uvvertices->getat(mesh->gettextureuvindex(j, k)).mdata[1]; controlpoints[controlpointindex] = meshvertices.size(); meshvertices.push_back(vertex); } } int materialcount = mesh->getnode()->getsrcobjectcount<fbxsurfacematerial>(); (int = 0; < materialcount; i++) { fbxsurfacematerial *material = (fbxsurfacematerial*)mesh->getnode()->getsrcobject<fbxsurfacematerial>(i); if (material) { fbxproperty prop = material->findproperty(fbxsurfacematerial::sdiffuse); const fbxtexture* texture = fbxcast<fbxtexture>(prop.getsrcobject<fbxtexture>(0)); const fbxfiletexture* filetexture = fbxcast<fbxfiletexture>(texture); id3d11shaderresourceview *meshctexture = loadtexture(dev, devcon, filetexture->getfilename()); meshtexture = meshctexture; } } const fbxvector4 lt = mesh->getnode()->getgeometrictranslation(fbxnode::esourcepivot); const fbxvector4 lr = mesh->getnode()->getgeometricrotation(fbxnode::esourcepivot); const fbxvector4 ls = mesh->getnode()->getgeometricscaling(fbxnode::esourcepivot); fbxamatrix geometrytransform = fbxamatrix(lt, lr, ls); (unsigned int deformerindex = 0; deformerindex < mesh->getdeformercount(); ++deformerindex) { fbxskin* skin = reinterpret_cast<fbxskin*>(mesh->getdeformer(deformerindex, fbxdeformer::eskin)); if (!skin) continue; (unsigned int clusterindex = 0; clusterindex < skin->getclustercount(); ++clusterindex) { fbxcluster* cluster = skin->getcluster(clusterindex); std::string jointname = cluster->getlink()->getname(); unsigned int jointindex = findjointindex(jointname); fbxamatrix transformmatrix; fbxamatrix transformlinkmatrix; fbxamatrix globalbindposeinversematrix; cluster->gettransformmatrix(transformmatrix); cluster->gettransformlinkmatrix(transformlinkmatrix); globalbindposeinversematrix = transformlinkmatrix.inverse() * transformmatrix * geometrytransform; skeleton.mjoints[jointindex].mglobalbindposeinverse = globalbindposeinversematrix; skeleton.mjoints[jointindex].mnode = cluster->getlink(); (unsigned int = 0; < cluster->getcontrolpointindicescount(); ++i) { int vertexid = controlpoints[cluster->getcontrolpointindices()[i]]; if (meshvertices[vertexid].boneids.x == 0) meshvertices[vertexid].boneids.x = jointindex; if (meshvertices[vertexid].boneids.y == 0) meshvertices[vertexid].boneids.y = jointindex; if (meshvertices[vertexid].boneids.z == 0) meshvertices[vertexid].boneids.z = jointindex; if (meshvertices[vertexid].boneids.w == 0) meshvertices[vertexid].boneids.w = jointindex; if (meshvertices[vertexid].weights.x == 0) meshvertices[vertexid].weights.x = cluster->getcontrolpointweights()[i]; if (meshvertices[vertexid].weights.y == 0) meshvertices[vertexid].weights.y = cluster->getcontrolpointweights()[i]; if (meshvertices[vertexid].weights.z == 0) meshvertices[vertexid].weights.z = cluster->getcontrolpointweights()[i]; if (meshvertices[vertexid].weights.w == 0) meshvertices[vertexid].weights.w = cluster->getcontrolpointweights()[i]; } fbxanimstack* animstack = fbxscene->getsrcobject<fbxanimstack>(0); fbxstring animstackname = animstack->getname(); fbxtakeinfo* takeinfo = fbxscene->gettakeinfo(animstackname); fbxtime start = takeinfo->mlocaltimespan.getstart(); fbxtime end = takeinfo->mlocaltimespan.getstop(); fbxlonglong animationlength = end.getframecount(fbxtime::eframes30) - start.getframecount(fbxtime::eframes30) + 1; keyframe** anim = &skeleton.mjoints[jointindex].manimation; (fbxlonglong = start.getframecount(fbxtime::eframes30); <= end.getframecount(fbxtime::eframes30); ++i) { fbxtime time; time.setframe(i, fbxtime::eframes30); *anim = new keyframe(); (*anim)->mframenum = i; fbxamatrix transformoffset = mesh->getnode()->evaluateglobaltransform(1.0f) * geometrytransform; (*anim)->mglobaltransform = transformoffset.inverse() * cluster->getlink()->evaluateglobaltransform(time); anim = &((*anim)->mnext); } } } return mesh(dev, meshvertices, meshtexture); } void fbxloader::processskeletonheirarchy(fbxnode * rootnode) { (int childindex = 0; childindex < rootnode->getchildcount(); ++childindex) { fbxnode *node = rootnode->getchild(childindex); processskeletonheirarchyre(node, 0, 0, -1); } } void fbxloader::processskeletonheirarchyre(fbxnode * node, int depth, int index, int parentindex) { if (node->getnodeattribute() && node->getnodeattribute()->getattributetype() && node->getnodeattribute()->getattributetype() == fbxnodeattribute::eskeleton) { joint joint; joint.mparentindex = parentindex; joint.mname = node->getname(); skeleton.mjoints.push_back(joint); } (int = 0; < node->getchildcount(); i++) { processskeletonheirarchyre(node->getchild(i), depth + 1, skeleton.mjoints.size(), index); } } unsigned int fbxloader::findjointindex(const std::string & jointname) { (unsigned int = 0; < skeleton.mjoints.size(); ++i) { if (skeleton.mjoints[i].mname == jointname) { return i; } } } id3d11shaderresourceview * fbxloader::loadtexture(id3d11device * dev, id3d11devicecontext * devcon, const char * texturefilename) { hresult hr; id3d11shaderresourceview *texture; std::string filenamestr(texturefilename); std::string sl = "/"; size_t start_pos = filenamestr.find(sl); filenamestr.replace(start_pos, sl.length(), "\\"); std::wstring filename = std::wstring(filenamestr.begin(), filenamestr.end()); hr = createwictexturefromfile(dev, devcon, filename.c_str(), nullptr, &texture); if (failed(hr)) return nullptr; return texture; }
here's vertex shader
matrix bonetransform = mul(bones[boneids[0]], weights[0]); bonetransform += mul(bones[boneids[1]], weights[1]); bonetransform += mul(bones[boneids[2]], weights[2]); bonetransform += mul(bones[boneids[3]], weights[3]); float4 posl = mul(bonetransform, pos); output.pos = mul(posl, world);
here's drawing code
cb.mworld = xmmatrixtranspose(m_world); cb.mview = xmmatrixtranspose(m_view); cb.mprojection = xmmatrixtranspose(m_projection); (int = 0; < jasper->skeleton.mjoints.size(); i++) cb.bones[i] = xmmatrixtranspose(xmmatrixidentity()); devcon->updatesubresource(pconstantbuffer, 0, nullptr, &cb, 0, 0); devcon->vssetshader(pvs, 0, 0); devcon->vssetconstantbuffers(0, 1, &pconstantbuffer); devcon->pssetshader(pps, 0, 0); devcon->pssetsamplers(0, 1, &texsamplerstate); model->draw(devcon);
and when set bones matrices in vertex shader identity matrix get.
shouldn't when use identity matrix?
Comments
Post a Comment