framework2
1498 строк · 71.2 Кб
1//
2// ofxFBXSrcMesh.cpp
3// ConnectionsWall-Nick
4//
5// Created by Nick Hardeman on 7/11/19.
6//
7
8#include "ofxFBXSrcMesh.h"9#include "ofxFBXUtils.h"10
11using namespace ofxFBXSource;12
13//--------------------------------------------------------------
14Mesh::Mesh() {15fbxMesh = NULL;16mNormalsArray = NULL;17}
18
19//--------------------------------------------------------------
20Mesh::~Mesh() {21if( mNormalsArray != NULL ) {22delete [] mNormalsArray;23mNormalsArray = NULL;24}25}
26
27//--------------------------------------------------------------
28void Mesh::setup( FbxNode *pNode ) {29ofxFBXSource::Node::setup( pNode );30setFBXMesh( pNode->GetMesh() );31}
32
33//--------------------------------------------------------------
34void Mesh::setFBXMesh( FbxMesh* lMesh ) {35fbxMesh = lMesh;36mesh.clear();37
38// from ViewScene Example included with the FBX SDK //39if (!lMesh->GetNode()) {40ofLogError("ofxFBXMesh") << " error setFBXMesh, lMesh->GetNode failed" << endl;41return;42}43
44ofLogVerbose() << "** ofxFBXMesh :: " << getName() << " attempting to parse ******* ";45
46vector< string > eMappingModeNames = {"eNone", "eByControlPoint", "eByPolygonVertex", "eByPolygon", "eByEdge", "eAllSame"};47vector<string> eRefModes = {"eDirect", "eIndex", "eIndexToDirect" };48
49const int lPolygonCount = lMesh->GetPolygonCount();50
51// Count the polygon count of each material52FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL;53FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone;54if (lMesh->GetElementMaterial()) {55lMaterialIndice = &lMesh->GetElementMaterial()->GetIndexArray();56lMaterialMappingMode = lMesh->GetElementMaterial()->GetMappingMode();57if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon) {58FBX_ASSERT(lMaterialIndice->GetCount() == lPolygonCount);59if (lMaterialIndice->GetCount() == lPolygonCount) {60
61// make sure the vector is setup and we have the proper amount of materials ready //62for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) {63const int lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex);64if(lMaterialIndex >= 0) {65if(subMeshes.size() < lMaterialIndex + 1) {66subMeshes.resize(lMaterialIndex + 1);67}68}69}70}71}72}73
74// split the vertices based on the materials //75// so that it renders properly //76// if( subMeshes.size() > 1 ) {77fbxMesh->SplitPoints();78// }79
80if(subMeshes.size() == 0) {81subMeshes.resize(1);82}83
84// add in the vertices //85const FbxVector4 * lControlPoints = lMesh->GetControlPoints();86int controlPointCount = lMesh->GetControlPointsCount();87mesh.getVertices().resize( controlPointCount );88
89ofLogVerbose() << "ofxFBXMesh :: number of vertices: " << mesh.getNumVertices() << " sub meshes: " << subMeshes.size();90
91// INDICES /////92mesh.clearIndices();93// populate the indices //94for( int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; lPolygonIndex++ ) {95int faceSize = fbxMesh->GetPolygonSize( lPolygonIndex );96for( int lVerticeIndex = 0; lVerticeIndex < faceSize; lVerticeIndex++ ) {97const int lControlPointIndex = fbxMesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex);98mesh.getVertices()[ lControlPointIndex ] = glm::vec3(lControlPoints[lControlPointIndex][0],99lControlPoints[lControlPointIndex][1],100lControlPoints[lControlPointIndex][2] );101mesh.addIndex( lControlPointIndex );102}103}104
105ofLogVerbose() << "ofxFBXMesh :: number of indices: " << mesh.getNumIndices() << " number of polygons: " << lPolygonCount;106
107
108// TODO: Account for if all mapping modes are not by control point //109
110// Normals //111if( lMesh->GetElementNormalCount() > 0 && lMesh->GetElementNormal() ) {112const FbxGeometryElementNormal * lNormalElement = lMesh->GetElementNormal(0);113mNormalMappingMode = lNormalElement->GetMappingMode();114
115ofLogVerbose() << "ofxFBXMesh :: normals detected. mapping mode: " << eMappingModeNames[ mNormalMappingMode ];116
117mesh.getNormals().resize( controlPointCount );118
119FbxVector4 lCurrentNormal;120if( mNormalMappingMode == FbxGeometryElement::eByControlPoint ) {121for(int i = 0; i < controlPointCount; i++ ) {122int lNormalIndex = i;123if (lNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) {124lNormalIndex = lNormalElement->GetIndexArray().GetAt(i);125}126lCurrentNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex);127mesh.getNormals()[i] = glm::vec3( lCurrentNormal[0], lCurrentNormal[1], lCurrentNormal[2] );128}129} else if( mNormalMappingMode == FbxGeometryElement::eByPolygonVertex ) {130for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) {131int faceSize = fbxMesh->GetPolygonSize( lPolygonIndex );132for( int lVerticeIndex = 0; lVerticeIndex < faceSize; lVerticeIndex++ ) {133const int lControlPointIndex = fbxMesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex);134if(fbxMesh->GetPolygonVertexNormal( lPolygonIndex, lVerticeIndex, lCurrentNormal )) {135mesh.getNormals()[ lControlPointIndex ] = glm::vec3( lCurrentNormal[0], lCurrentNormal[1], lCurrentNormal[2] );136}137}138}139} else {140ofLogVerbose() << "ofxFBXMesh :: clearing normals, only eByControlPoint and eByPolygonVertex supported.";141mNormalMappingMode = FbxGeometryElement::eNone;142mesh.clearNormals();143}144}145
146
147if( fbxMesh->GetElementUVCount() ) mesh.getTexCoords().resize( mesh.getNumVertices() );148
149// TEX COORDS CODE BASED ON CODE FROM FBX SDK 2016.1 example //150//iterating over all uv sets151for (int lUVSetIndex = 0; lUVSetIndex < fbxMesh->GetElementUVCount(); lUVSetIndex++) {152const FbxGeometryElementUV* lUVElement = fbxMesh->GetElementUV( lUVSetIndex );153
154if(!lUVElement)155continue;156
157FbxGeometryElement::EMappingMode lUVMappingMode = lUVElement->GetMappingMode();158ofLogVerbose() << "ofxFBXMesh :: uv mapping mode: " << eMappingModeNames[ lUVMappingMode ];159// only support mapping mode eByPolygonVertex and eByControlPoint160if(lUVElement->GetMappingMode() != FbxGeometryElement::eByPolygonVertex &&161lUVElement->GetMappingMode() != FbxGeometryElement::eByControlPoint ) {162continue;163}164
165//index array, where holds the index referenced to the uv data166const bool lUseIndex = lUVElement->GetReferenceMode() != FbxGeometryElement::eDirect;167const int lIndexCount= (lUseIndex) ? lUVElement->GetIndexArray().GetCount() : 0;168
169//iterating through the data by polygon170const int lPolyCount = fbxMesh->GetPolygonCount();171
172if( lUVElement->GetMappingMode() == FbxGeometryElement::eByControlPoint ) {173for( int lPolyIndex = 0; lPolyIndex < lPolyCount; ++lPolyIndex ) {174// build the max index array that we need to pass into MakePoly175const int lPolySize = fbxMesh->GetPolygonSize(lPolyIndex);176for( int lVertIndex = 0; lVertIndex < lPolySize; ++lVertIndex ) {177FbxVector2 lUVValue;178//get the index of the current vertex in control points array179int lPolyVertIndex = fbxMesh->GetPolygonVertex(lPolyIndex,lVertIndex);180//the UV index depends on the reference mode181int lUVIndex = lUseIndex ? lUVElement->GetIndexArray().GetAt(lPolyVertIndex) : lPolyVertIndex;182lUVValue = lUVElement->GetDirectArray().GetAt(lUVIndex);183mesh.getTexCoords()[ lPolyVertIndex ] = glm::vec2( lUVValue[0], lUVValue[1] );184}185}186} else if (lUVElement->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) {187int lIndexByPolygonVertex = 0;188FbxVector2 lUVValue;189//Let's get normals of each polygon, since the mapping mode of normal element is by polygon-vertex.190for(int lPolygonIndex = 0; lPolygonIndex < fbxMesh->GetPolygonCount(); lPolygonIndex++) {191//get polygon size, you know how many vertices in current polygon.192int lPolygonSize = fbxMesh->GetPolygonSize(lPolygonIndex);193ofLogVerbose() << "ofxFBXMesh :: polygon size: " << lPolygonSize << " ref mode " << eRefModes[lUVElement->GetReferenceMode()];194//retrieve each vertex of current polygon.195for(int i = 0; i < lPolygonSize; i++) {196int lNormalIndex = 0;197//reference mode is direct, the normal index is same as lIndexByPolygonVertex.198if( lUVElement->GetReferenceMode() == FbxGeometryElement::eDirect )199lNormalIndex = lIndexByPolygonVertex;200
201//reference mode is index-to-direct, get normals by the index-to-direct202if( lUVElement->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)203lNormalIndex = lUVElement->GetIndexArray().GetAt(lIndexByPolygonVertex);204
205//Got normals of each polygon-vertex.206lUVValue = lUVElement->GetDirectArray().GetAt(lNormalIndex);207const int lControlPointIndex = fbxMesh->GetPolygonVertex( lPolygonIndex, i );208mesh.getTexCoords()[ lControlPointIndex ] = glm::vec2( lUVValue[0], lUVValue[1] );209
210lIndexByPolygonVertex++;211}//end for i //lPolygonSize212}//end for lPolygonIndex //PolygonCount213}214
215ofLogVerbose( "ofxFBXMesh : num verts: " ) << mesh.getNumVertices() << " tcoords: " << mesh.getNumTexCoords();216}217
218
219// VERTEX COLORS ////220if( lMesh->GetElementVertexColorCount() > 0 && lMesh->GetElementVertexColor() ) {221const FbxLayerElementVertexColor* pVertexColorElement = lMesh->GetElementVertexColor();222FbxGeometryElement::EMappingMode lVertexColorMappingMode = pVertexColorElement->GetMappingMode();223
224mesh.getColors().resize( controlPointCount );225
226ofLogVerbose() << "ofxFBXMesh :: vertex colors detected: mapping mode: " << eMappingModeNames[ lVertexColorMappingMode ];227
228FbxColor lVertexColor;229if( lVertexColorMappingMode == FbxGeometryElement::eByControlPoint ) {230int lVertexColorIndex = 0;231for(int i = 0; i < controlPointCount; i++ ) {232lVertexColorIndex = i;233if ( pVertexColorElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) {234lVertexColorIndex = pVertexColorElement->GetIndexArray().GetAt(i);235}236lVertexColor = pVertexColorElement->GetDirectArray().GetAt(lVertexColorIndex);237mesh.getColors()[i].set( ofFloatColor(lVertexColor.mRed, lVertexColor.mGreen, lVertexColor.mBlue, lVertexColor.mAlpha ) );238}239} else {240ofLogVerbose() << "ofxFBXMesh :: clearing vertex colors, only eByControlPoint supported.";241mesh.clearColors();242mesh.disableColors();243lVertexColorMappingMode = FbxGeometryElement::eNone;244}245} else {246mesh.clearColors();247mesh.disableColors();248}249
250
251// update the meshes offsets and indices counts //252for( int i = 0; i < subMeshes.size(); i++ ) {253subMeshes[i].triangleCount = 0;254subMeshes[i].totalIndices = 0;255}256
257// update the sub meshes with the proper amount of indices //258for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) {259// The material for current face.260int lMaterialIndex = 0;261if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon) {262lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex);263if(lMaterialIndex < 0) {264lMaterialIndex = 0;265}266}267
268subMeshes[lMaterialIndex].triangleCount += 1;269subMeshes[lMaterialIndex].totalIndices += lMesh->GetPolygonSize( lPolygonIndex );270}271
272int toffset = 0;273for( int i = 0; i < subMeshes.size(); i++ ) {274subMeshes[i].indexOffset = toffset;275toffset += subMeshes[i].totalIndices;276}277
278
279
280// cout << "--------------------------------------- " << endl << endl;281
282//ofLogVerbose("ofxFBXMesh") << "sub meshes: " << subMeshes.size();283for( int i = 0; i < subMeshes.size(); i++ ) {284ofLogVerbose("ofxFBXMesh") << i << " submesh totalindicies = " << subMeshes[i].totalIndices << " index offset: " << subMeshes[i].indexOffset << " total verts = " << mesh.getNumVertices() << " polygonos = " << (lPolygonCount*3);285}286ofLogVerbose("ofxFBXMesh") << getName() << " parse complete." << endl;287//ofLogVerbose("ofxFBXMesh ") << "verts: " << mesh.getNumVertices() << " indices: " << mesh.getNumIndices() << " normals: " << mesh.getNumNormals() << " tex coords: " << mesh.getNumTexCoords();288
289veebs.setMesh( mesh, GL_STREAM_DRAW );290original = mesh;291
292if( mesh.hasNormals() ) {293if(fbxMesh->GetControlPointsCount()) {294mNormalsArray = new FbxVector4[ fbxMesh->GetControlPointsCount() ];295populateNormals( mNormalsArray );296}297}298
299// associate the materials with the sub meshes //300int lSubMeshCount = subMeshes.size();301for (int lIndex = 0; lIndex < lSubMeshCount; ++lIndex) {302const FbxSurfaceMaterial * lMaterial = fbxMesh->GetNode()->GetMaterial(lIndex);303if(lMaterial) {304subMeshes[ lIndex ].materialPtr = static_cast<ofxFBXSource::MeshMaterial *>(lMaterial->GetUserDataPtr());305}306}307
308}
309
310//--------------------------------------------------------------
311void Mesh::configureMesh( ofMesh& aMesh ) {312aMesh = mesh;313}
314
315#pragma mark - Update316//--------------------------------------------------------------
317void Mesh::update( FbxTime& pTime, FbxPose* pPose ) {318
319// cout << "ofxFBXSource :: Mesh : update : " << getName() << " has parent: " << ( mFbxNode->GetParent() ? "yes":"no") << endl;
320if( fbxMesh->GetNode() && mFbxNode ) {321if( !mFbxNode->GetParent() ) {322FbxAMatrix lGlobalPosition = GetGlobalPosition(fbxMesh->GetNode(), pTime, NULL );323setLocalTransformMatrix(lGlobalPosition);324} else {325FbxAMatrix lLocalPosition = GetLocalPositionForNode(fbxMesh->GetNode(), pTime, NULL );326setLocalTransformMatrix(lLocalPosition);327}328}329
330// FbxAMatrix lGlobalPosition = GetGlobalPosition( fbxMesh->GetNode(), pTime, NULL );
331// // FbxAMatrix lGlobalPosition = GetLocalPosition( fbxMesh->GetNode(), pTime, NULL );
332// setLocalTransformMatrix(lGlobalPosition);
333// // setTransformMatrix(lGlobalPosition);
334// // glm::mat4 ofgpos = fbxToOf(lGlobalPosition);
335// // setTransformMatrix( ofgpos );
336}
337
338//--------------------------------------------------------------
339void Mesh::update( int aAnimIndex, signed long aMillis ) {340ofxFBXSource::Node::update( aAnimIndex, aMillis );341}
342
343//--------------------------------------------------------------
344void Mesh::update( int aAnimIndex1, signed long aAnim1Millis, int aAnimIndex2, signed long aAnim2Millis, float aMixPct ) {345ofxFBXSource::Node::update( aAnimIndex1, aAnim1Millis, aAnimIndex2, aAnim2Millis, aMixPct );346}
347
348//--------------------------------------------------------------
349void Mesh::_configureMeshFromSrcMesh( ofMesh* aSrcMesh, ofMesh* amesh ) {350if(aSrcMesh == nullptr || amesh == nullptr) return;351if( aSrcMesh->getNumVertices() < 3 ) return;352// ofMesh* srcMesh = &akey.mesh;
353
354if( aSrcMesh != nullptr ) {355if( aSrcMesh->getNumColors() != amesh->getNumColors() ) {356std::copy( aSrcMesh->getColors().begin(), aSrcMesh->getColors().end(), amesh->getColors().begin());357}358if( aSrcMesh->getNumTexCoords() != amesh->getNumTexCoords() ) {359std::copy( aSrcMesh->getTexCoords().begin(), aSrcMesh->getTexCoords().end(), amesh->getTexCoords().begin());360}361if( aSrcMesh->getNumIndices() != amesh->getNumIndices() ) {362std::copy( aSrcMesh->getIndices().begin(), aSrcMesh->getIndices().end(), amesh->getIndices().begin());363}364
365if( aSrcMesh->getNumNormals() != amesh->getNumNormals() && amesh->usingNormals() ) {366std::copy( aSrcMesh->getNormals().begin(), aSrcMesh->getNormals().end(), amesh->getNormals().begin());367}368
369if( aSrcMesh->getNumVertices() != amesh->getNumVertices() ) {370std::copy( aSrcMesh->getVertices().begin(), aSrcMesh->getVertices().end(), amesh->getVertices().begin());371}372}373}
374
375//--------------------------------------------------------------
376void Mesh::_updateMeshFromKeyMesh( ofMesh* aSrcMesh, ofMesh* amesh ) {377if(aSrcMesh == nullptr || amesh == nullptr) return;378_configureMeshFromSrcMesh( aSrcMesh, amesh );379
380if( aSrcMesh->getNumNormals() > 0 && amesh->usingNormals() ) {381std::copy( aSrcMesh->getNormals().begin(), aSrcMesh->getNormals().end(), amesh->getNormals().begin());382}383
384std::copy( aSrcMesh->getVertices().begin(), aSrcMesh->getVertices().end(), amesh->getVertices().begin());385}
386
387//--------------------------------------------------------------
388void Mesh::updateMeshFromKeyframes( ofMesh* amesh, int aAnimIndex, signed long aMillis ) {389if(amesh == nullptr) return;390
391auto& meshKey = getMeshAnimKey( aAnimIndex,aMillis );392if( meshKey.mesh.getNumVertices() < 3 ) return;393
394_updateMeshFromKeyMesh( &meshKey.mesh, amesh );395}
396
397//--------------------------------------------------------------
398void Mesh::updateMeshFromKeyframesBlended( ofMesh* amesh, int aAnimIndex, signed long aMillis ) {399if(amesh == nullptr) return;400
401bool bUpdatedMesh = false;402MeshAnimKeyCollection& tcollection = mMeshKeyCollections[aAnimIndex];403auto& keys = tcollection.meshKeys;404size_t numkeys = keys.size();405for( int i = 0; i < numkeys; i++) {406if(keys[i].millis == aMillis) {407_updateMeshFromKeyMesh( &keys[i].mesh, amesh );408bUpdatedMesh = true;409} else if(keys[i].millis > aMillis) {410if(i > 0) {411_configureMeshFromSrcMesh( &keys[i].mesh, amesh );412bUpdatedMesh = true;413
414signed long delta = aMillis - keys[i-1].millis;415float pct = double(delta) / double(keys[i].millis - keys[i-1].millis);416// should we lerp all of the mesh vertices //417// return keys[i];418// srcMesh = &keys[i].mesh;419//return ofLerp(keys[i-1].value,keys[i].value,pct);420ofMesh& mesh1 = keys[i-1].mesh;421ofMesh& mesh2 = keys[i].mesh;422
423// mix the vertices //424auto& tverts = amesh->getVertices();425auto& srcVerts1 = mesh1.getVertices();426auto& srcVerts2 = mesh2.getVertices();427
428bool bUpdateNormals = amesh->usingNormals() && amesh->getNumNormals() > 0 && (amesh->getNumVertices() == amesh->getNumNormals());429size_t tnumvs = tverts.size();430pct = ofClamp(pct, 0.0, 1.0);431float invpct = 1.0 - pct;432
433for( int i = 0; i < tnumvs; i++ ) {434tverts[i] = srcVerts1[i] * invpct + srcVerts2[i] * pct;435}436
437// calling getNormals flags them as dirty, so lets run through a separate loop //438if(bUpdateNormals) {439auto& tnormals = amesh->getNormals();440auto& srcNormals1 = mesh1.getNormals();441auto& srcNormals2 = mesh2.getNormals();442for( int i = 0; i < tnumvs; i++ ) {443tnormals[i] = srcNormals1[i] * invpct + srcNormals2[i] * pct;444}445}446
447} else {448_updateMeshFromKeyMesh( &keys[0].mesh, amesh );449bUpdatedMesh = true;450}451}452}453
454if(!keys.empty() && !bUpdatedMesh) {455_updateMeshFromKeyMesh( &keys.back().mesh, amesh );456}457
458
459}
460
461//--------------------------------------------------------------
462void Mesh::updateMeshFromKeyframes( ofMesh* amesh, int aAnimIndex1, signed long aAnim1Millis, int aAnimIndex2, signed long aAnim2Millis, float aMixPct ) {463if(amesh == nullptr) return;464auto& key1 = getMeshAnimKey( aAnimIndex1, aAnim1Millis );465auto& key2 = getMeshAnimKey( aAnimIndex2, aAnim2Millis );466if( key1.mesh.getNumVertices() < 3 || key2.mesh.getNumVertices() < 3 ) {467ofLogError("ofxFBXSource::Mesh::updateMeshFromKeyframes: key1.mesh.getNumVertices(): ") << key1.mesh.getNumVertices() << " key2: " << key2.mesh.getNumVertices();468return;469};470
471// set the verts based on the first animation //472updateMeshFromKeyframes( amesh, aAnimIndex1, aAnim1Millis );473
474// mix the vertices //475auto& tverts = amesh->getVertices();476auto& srcVerts = key2.mesh.getVertices();477bool bUpdateNormals = amesh->usingNormals() && amesh->getNumNormals() > 0 && (amesh->getNumVertices() == amesh->getNumNormals());478size_t tnumvs = tverts.size();479aMixPct = ofClamp(aMixPct, 0.0, 1.0);480float invpct = 1.0 - aMixPct;481
482for( int i = 0; i < tnumvs; i++ ) {483tverts[i] = tverts[i] * invpct + srcVerts[i] * aMixPct;484}485// calling getNormals flags them as dirty, so lets run through a separate loop //486if(bUpdateNormals) {487auto& tnormals = amesh->getNormals();488auto& srcNormals = key2.mesh.getNormals();489for( int i = 0; i < tnumvs; i++ ) {490tnormals[i] = tnormals[i] * invpct + srcNormals[i] * aMixPct;491}492}493
494}
495
496//--------------------------------------------------------------
497void Mesh::updateMesh( ofMesh* aMesh, FbxTime& pTime, FbxAnimLayer * pAnimLayer, FbxPose* pPose ) {498const bool lHasShape = fbxMesh->GetShapeCount() > 0;499const bool lHasSkin = fbxMesh->GetDeformerCount(FbxDeformer::eSkin) > 0;500const bool lHasVertexCache = fbxMesh->GetDeformerCount(FbxDeformer::eVertexCache);501const bool lHasDeformation = lHasShape || lHasSkin;502
503const int lVertexCount = fbxMesh->GetControlPointsCount();504
505// cout << "ofxFBXMesh :: " << getName() << " vertices: " << lVertexCount << " has blend shape: " << lHasShape << " has skin: " << lHasSkin << " has def: " << lHasDeformation << " has vertex cache: " << lHasVertexCache << " | " << ofGetFrameNum() << endl;506
507if(!lHasDeformation || lVertexCount < 3) return;508
509FbxAMatrix lGlobalPosition = GetGlobalPosition( fbxMesh->GetNode(), pTime, pPose );510// Geometry offset.511// it is not inherited by the children.512FbxAMatrix lGeometryOffset = GetGeometry( fbxMesh->GetNode() );513FbxAMatrix lGlobalOffPosition = lGlobalPosition * lGeometryOffset;514
515FbxVector4* lVertexArray = NULL;516lVertexArray = new FbxVector4[ lVertexCount ];517memcpy( lVertexArray, fbxMesh->GetControlPoints(), lVertexCount * sizeof(FbxVector4) );518
519FbxVector4* lNormalArray = NULL;520if( aMesh->hasNormals() && aMesh->usingNormals() ) {521if( mNormalsArray != NULL ) {522// cout << "updateMesh :: aMesh " << aMesh->hasNormals() << " using: " << aMesh->usingNormals() << endl;523lNormalArray = new FbxVector4[ lVertexCount ];524memcpy( lNormalArray, mNormalsArray, lVertexCount * sizeof(FbxVector4) );525}526}527
528
529if(lHasShape) {530computeBlendShapes( aMesh, pTime, pAnimLayer );531}532if(lHasSkin) {533//we need to get the number of clusters. which are controlled by bones //534const int lSkinCount = fbxMesh->GetDeformerCount(FbxDeformer::eSkin);535int lClusterCount = 0;536for (int lSkinIndex = 0; lSkinIndex < lSkinCount; ++lSkinIndex) {537lClusterCount += ((FbxSkin *)(fbxMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin)))->GetClusterCount();538}539if (lClusterCount) {540computeSkinDeformation( lGlobalOffPosition, pTime, pAnimLayer, lVertexArray, lNormalArray, pPose );541}542}543// cout << "Calling update mesh lHasShape = " << lHasShape << " skin = " << lHasSkin << " lHasDeformation = " << lHasDeformation << endl;544
545
546vector< glm::vec3 >& amverts = aMesh->getVertices();547vector< glm::vec3 >& amnormals = aMesh->getNormals();548
549bool bUpdateNormals = lNormalArray != NULL && amnormals.size() > 1;550
551const int controlPointCount = fbxMesh->GetControlPointsCount();552// update the vertices //553for(int i = 0; i < controlPointCount; i++ ) {554amverts[i] = glm::vec3( lVertexArray[i][0], lVertexArray[i][1], lVertexArray[i][2] );555}556
557if( bUpdateNormals ) {558if( mNormalMappingMode == FbxGeometryElement::eByControlPoint ) {559for(int i = 0; i < controlPointCount; i++ ) {560amnormals[i] = glm::vec3( lNormalArray[i][0], lNormalArray[i][1], lNormalArray[i][2] );561// amnormals[i].normalize();562}563} else if( mNormalMappingMode == FbxGeometryElement::eByPolygonVertex ) {564const int lPolygonCount = fbxMesh->GetPolygonCount();565int polysize = 3;566
567for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) {568polysize = fbxMesh->GetPolygonSize( lPolygonIndex );569for (int lVerticeIndex = 0; lVerticeIndex < polysize; ++lVerticeIndex) {570
571const int lControlPointIndex = fbxMesh->GetPolygonVertex( lPolygonIndex, lVerticeIndex );572// amverts[lControlPointIndex].set(lVertexArray[lControlPointIndex][0],573// lVertexArray[lControlPointIndex][1],574// lVertexArray[lControlPointIndex][2]);575// if( bUpdateNormals ) {576amnormals[lControlPointIndex] = glm::vec3(lNormalArray[ lControlPointIndex ][0],577lNormalArray[ lControlPointIndex ][1],578lNormalArray[ lControlPointIndex ][2] );579// amnormals[lControlPointIndex].normalize();580// }581}582}583}584}585
586// if(bAllMappedByControlPoint) {587//// cout << "updateMesh :: bAllMappedByControlPoint : " << endl;588// for(int i = 0; i < fbxMesh->GetControlPointsCount(); i++ ) {589// amverts[i].set( lVertexArray[i][0], lVertexArray[i][1], lVertexArray[i][2] );590// if( bUpdateNormals ) {591// amnormals[i].set( lNormalArray[i][0], lNormalArray[i][1], lNormalArray[i][2] );592// amnormals[i].normalize();593// }594// }595// } else {596//// cout << "updateMesh :: !bAllMappedByControlPoint : normals: " << bUpdateNormals << endl;597// const int lPolygonCount = fbxMesh->GetPolygonCount();598// int tvertcount = 0;599// for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) {600// for (int lVerticeIndex = 0; lVerticeIndex < 3; ++lVerticeIndex) {601//602// const int lControlPointIndex = fbxMesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex);603// amverts[lControlPointIndex].set(lVertexArray[lControlPointIndex][0],604// lVertexArray[lControlPointIndex][1],605// lVertexArray[lControlPointIndex][2]);606// if( bUpdateNormals ) {607// amnormals[lControlPointIndex].set(lNormalArray[ lControlPointIndex ][0],608// lNormalArray[ lControlPointIndex ][1],609// lNormalArray[ lControlPointIndex ][2] );610// amnormals[lControlPointIndex].normalize();611// }612//// ++tvertcount;613//614// // WORKING ////////////615//// const int lControlPointIndex = fbxMesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex);616//// amverts[tvertcount].set(lVertexArray[lControlPointIndex][0],617//// lVertexArray[lControlPointIndex][1],618//// lVertexArray[lControlPointIndex][2]);619//// if( bUpdateNormals ) {620//// amnormals[tvertcount].set(lNormalArray[ lControlPointIndex ][0],621//// lNormalArray[ lControlPointIndex ][1],622//// lNormalArray[ lControlPointIndex ][2] );623//// amnormals[tvertcount].normalize();624//// }625//// ++tvertcount;626// // !-- WORKING ///////////////627// }628// }629// }630
631delete [] lVertexArray;632if( lNormalArray != NULL ) {633delete [] lNormalArray;634}635
636}
637
638#pragma mark - Draw639//--------------------------------------------------------------
640void Mesh::draw( ofMesh* aMesh ) {641// cout << "ofxFBXMesh :: " << getName() << " verts: " << aMesh->haveVertsChanged() << " indices: " << aMesh->haveIndicesChanged() << " normals: " << aMesh->haveNormalsChanged() << " tex coords: " << aMesh->haveTexCoordsChanged() << " colors: " << aMesh->haveColorsChanged() << " | " << ofGetFrameNum() << endl;642veebs.updateMesh( *aMesh );643if( aMesh->getNumColors() < 1 || !aMesh->usingColors() ) {644veebs.disableColors();645} else {646veebs.enableColors();647}648
649const int lSubMeshCount = subMeshes.size();650glEnable( GL_NORMALIZE );651
652if(veebs.getIsAllocated()) {653if(lSubMeshCount > 0) {654#ifndef TARGET_OPENGLES655// GLES does not support glPolygonMode656glPolygonMode(GL_FRONT_AND_BACK, GL_FILL );657#endif658
659veebs.bind();660}661for (int lIndex = 0; lIndex < lSubMeshCount; ++lIndex) {662GLsizei lOffset = subMeshes[lIndex].indexOffset * sizeof(unsigned int);663// const GLsizei lElementCount = meshMaterials[lIndex].triangleCount * 3;664const GLsizei lElementCount = subMeshes[lIndex].totalIndices;665glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, veebs.getIndexId() );666// cout << "lElementCount = " << lElementCount << " mesh is using indices = " << mesh.hasIndices() << endl;667
668#ifdef TARGET_OPENGLES669glDrawElements(GL_TRIANGLES, lElementCount, GL_UNSIGNED_SHORT,670(void*)(sizeof(ofIndexType) * subMeshes[lIndex].indexOffset));671#else672glDrawElements( GL_TRIANGLES, lElementCount, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(lOffset));673#endif674
675}676if(lSubMeshCount > 0) veebs.unbind();677}678}
679
680//--------------------------------------------------------------
681void Mesh::draw( ofMesh* aMesh, vector< shared_ptr<ofxFBXMeshMaterial> >& aMats, bool bUpdateTheVeeeeebs ) {682if( aMats.size() == 0 ) {683draw( aMesh );684return;685}686
687// cout << "ofxFBXSrcMesh :: aMesh num verts: " << aMesh->getNumVertices() << " num tcoords: " << aMesh->getNumTexCoords() << " update veebs: " << bUpdateTheVeeeeebs << " veebs num verts: " << veebs.getNumVertices() << " | " << ofGetFrameNum() << endl;
688// cout << "ofxFBXMesh :: " << getName() << " verts: " << aMesh->haveVertsChanged() << " indices: " << aMesh->haveIndicesChanged() << " normals: " << aMesh->haveNormalsChanged() << " tex coords: " << aMesh->haveTexCoordsChanged() << " colors: " << aMesh->haveColorsChanged() << " | " << ofGetFrameNum() << endl;
689// veebs.updateMesh( *aMesh );
690
691
692if(bUpdateTheVeeeeebs || veebs.getNumVertices() < 1) {693if( aMesh->hasVertices() ) {694veebs.updateVertexData( aMesh->getVerticesPointer(), aMesh->getNumVertices() );695}696
697if( aMesh->hasColors() && aMesh->usingColors() ) {698veebs.updateColorData( aMesh->getColorsPointer(), aMesh->getNumColors() );699}700
701if( aMesh->hasNormals() && aMesh->usingNormals() ) {702veebs.updateNormalData(aMesh->getNormalsPointer(),aMesh->getNumNormals());703}704
705if( aMesh->hasTexCoords() && aMesh->usingTextures() ) {706veebs.updateTexCoordData( aMesh->getTexCoordsPointer(), aMesh->getNumTexCoords() );707}708}709
710// if(haveIndicesChanged()){
711// if(getNumIndices()==0){
712// vbo.clearIndices();
713// vboNumIndices = getNumIndices();
714// }else if(vboNumIndices<getNumIndices()){
715// vbo.setIndexData(getIndexPointer(),getNumIndices(),usage);
716// vboNumIndices = getNumIndices();
717// }else{
718// vbo.updateIndexData(getIndexPointer(),getNumIndices());
719// }
720// }
721
722
723if( aMesh->getNumColors() < 1 || !aMesh->usingColors() ) {724veebs.disableColors();725} else {726veebs.enableColors();727}728
729const int lSubMeshCount = subMeshes.size();730if( veebs.getIsAllocated() && lSubMeshCount > 0 ) {731// glEnable( GL_NORMALIZE ); // <-- dont think we need this anymore //
732
733// #ifndef TARGET_OPENGLES
734//// // GLES does not support glPolygonMode
735// glPolygonMode(GL_FRONT_AND_BACK, GL_FILL );
736// #endif
737
738// check to see if all have materials and are enabled so that OF can set the attributes //739// the setAttributes in Programmable renderer is a private method, so the vbo has to bind and unbind740// per sub mesh so we can call that method via ofVbo.drawElements :(741bool bAllMaterialsEnabled = true;742int tnumMatsEnabled = 0;743for( int i = 0; i < aMats.size(); i++ ) {744if( !aMats[i]->isEnabled() ) {745bAllMaterialsEnabled = false;746} else {747tnumMatsEnabled++;748}749}750if( tnumMatsEnabled < 1 ) {751// just draw the whole thing //752veebs.drawElements( GL_TRIANGLES, veebs.getNumIndices() );753} else {754
755if(bAllMaterialsEnabled) {756veebs.bind();757}758
759for( int lIndex = 0; lIndex < lSubMeshCount; ++lIndex ) {760if( lIndex < aMats.size() ) {761aMats[lIndex]->begin();762
763const GLsizei lElementCount = subMeshes[lIndex].totalIndices;764
765if( bAllMaterialsEnabled ) {766// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, veebs.getIndexId() );
767// cout << "lElementCount = " << lElementCount << " mesh is using indices = " << mesh.hasIndices() << endl;768
769#ifdef TARGET_OPENGLES770glDrawElements( GL_TRIANGLES, lElementCount, GL_UNSIGNED_SHORT, (void*)(sizeof(ofIndexType) * subMeshes[lIndex].indexOffset));771#else772GLsizei lOffset = subMeshes[lIndex].indexOffset * sizeof(unsigned int);773glDrawElements( GL_TRIANGLES, lElementCount, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(lOffset));774#endif775} else {776veebs.drawElements( GL_TRIANGLES, lElementCount, subMeshes[lIndex].indexOffset );777}778
779aMats[lIndex]->end();780}781}782
783if(bAllMaterialsEnabled) veebs.unbind();784}785}786}
787
788//--------------------------------------------------------------
789void Mesh::drawMeshKeyframe( int aAnimIndex, signed long aMillis, vector< shared_ptr<ofxFBXMeshMaterial> >& aMats, bool bUpdateTheVeeeeebs ) {790auto& meshKey = getMeshAnimKey( aAnimIndex,aMillis );791if( meshKey.mesh.getNumVertices() < 3 ) return;792draw( &meshKey.mesh, aMats, bUpdateTheVeeeeebs );793}
794
795//--------------------------------------------------------------
796int Mesh::getNumSubMeshes() {797return (int)subMeshes.size();798}
799
800//--------------------------------------------------------------
801bool Mesh::hasClusterDeformation() {802if(fbxMesh == NULL) {803ofLogWarning("ofxFBSMesh :: Set the Node before calling hasClusterDeformation");804return false;805}806return fbxMesh->GetDeformerCount(FbxDeformer::eSkin);807}
808
809#pragma mark - Materials + Textures810//--------------------------------------------------------------
811int Mesh::getNumMaterials() {812return getMaterials().size();813}
814
815//--------------------------------------------------------------
816vector< ofxFBXSource::MeshMaterial* > Mesh::getMaterials() {817vector< ofxFBXSource::MeshMaterial* > rMaterials;818int lSubMeshCount = subMeshes.size();819for (int lIndex = 0; lIndex < lSubMeshCount; ++lIndex) {820const FbxSurfaceMaterial * lMaterial = fbxMesh->GetNode()->GetMaterial(lIndex);821ofxFBXSource::MeshMaterial* lMaterialCache = NULL;822if(lMaterial && lMaterial->GetUserDataPtr() ) {823lMaterialCache = static_cast<ofxFBXSource::MeshMaterial *>(lMaterial->GetUserDataPtr());824rMaterials.push_back( lMaterialCache );825}826
827}828return rMaterials;829}
830
831//--------------------------------------------------------------
832bool Mesh::hasTexture() {833return ( getTextures().size() > 0 );834}
835
836//--------------------------------------------------------------
837vector< shared_ptr<ofxFBXSource::MeshTexture> > Mesh::getTextures() {838auto tmats = getMaterials();839vector< shared_ptr<ofxFBXSource::MeshTexture> > ttexs;840if( tmats.size() == 0 ) return ttexs;841for( auto& tmat : tmats ) {842if( tmat && tmat->hasTexture() ) {843ttexs.push_back( tmat->getTexturePtr() );844}845}846return ttexs;847}
848
849//--------------------------------------------------------------
850ofVbo& Mesh::getVbo() {851return veebs;852}
853
854//--------------------------------------------------------------
855ofMesh& Mesh::getOFMesh() {856return mesh;857}
858
859#pragma mark - Keyframes860//----------------------------------------
861ofxFBXSource::MeshAnimKeyCollection& Mesh::getMeshKeyCollection( int aAnimIndex ) {862if( mMeshKeyCollections.count(aAnimIndex) < 1 ) {863MeshAnimKeyCollection temp;864mMeshKeyCollections[ aAnimIndex ] = temp;865}866return mMeshKeyCollections[aAnimIndex];867}
868
869//----------------------------------------
870bool Mesh::hasMeshKeyCollection( int aAnimIndex ) {871if( mMeshKeyCollections.count(aAnimIndex) < 1 ) return false;872return true;873}
874
875//----------------------------------------
876void Mesh::clearKeyFrames() {877mMeshKeyCollections.clear();878ofxFBXSource::Node::clearKeyFrames();879setUsingCachedMeshes( false );880}
881
882//----------------------------------------
883void Mesh::setUsingCachedMeshes( bool ab ) {884bUsingCachedMeshes = ab;885}
886
887//----------------------------------------
888bool Mesh::isUsingCachedMeshes() {889return bUsingCachedMeshes;890}
891
892//----------------------------------------
893MeshAnimKey& Mesh::getMeshAnimKey( int aAnimIndex, signed long aMillis ) {894MeshAnimKeyCollection& tcollection = mMeshKeyCollections[aAnimIndex];895auto& keys = tcollection.meshKeys;896size_t numkeys = keys.size();897for(int i=0; i < numkeys; i++) {898if(keys[i].millis == aMillis) {899return keys[i];900} else if(keys[i].millis > aMillis) {901if(i > 0){902// signed long delta = aMillis - keys[i-1].millis;
903// float pct = double(delta) / double(keys[i].millis - keys[i-1].millis);
904// should we lerp all of the mesh vertices //905return keys[i];906// srcMesh = &keys[i].mesh;
907//return ofLerp(keys[i-1].value,keys[i].value,pct);908} else {909return keys[0];910}911}912}913
914if(!keys.empty()){915return keys.back();916}917return dummyMeshAnimKey;918}
919
920#pragma mark - Deformations921//--------------------------------------------------------------
922void Mesh::computeBlendShapes( ofMesh* aMesh, FbxTime& pTime, FbxAnimLayer * pAnimLayer ) {923int lBlendShapeDeformerCount = fbxMesh->GetDeformerCount(FbxDeformer::eBlendShape);924// cout << "Computing blendshapes for " << getName() << endl;925for(int lBlendShapeIndex = 0; lBlendShapeIndex<lBlendShapeDeformerCount; ++lBlendShapeIndex) {926FbxBlendShape* lBlendShape = (FbxBlendShape*)fbxMesh->GetDeformer(lBlendShapeIndex, FbxDeformer::eBlendShape);927
928int lBlendShapeChannelCount = lBlendShape->GetBlendShapeChannelCount();929for(int lChannelIndex = 0; lChannelIndex < lBlendShapeChannelCount; ++lChannelIndex) {930FbxBlendShapeChannel* lChannel = lBlendShape->GetBlendShapeChannel(lChannelIndex);931if(lChannel && pAnimLayer) {932// Get the percentage of influence on this channel.933FbxAnimCurve* lFCurve = fbxMesh->GetShapeChannel(lBlendShapeIndex, lChannelIndex, pAnimLayer);934if (!lFCurve) continue;935
936double lWeight = lFCurve->Evaluate(pTime);937// cout << "updateMesh lWeight = " << lWeight << " time = " << pTime.GetMilliSeconds() << endl;938
939int lShapeCount = lChannel->GetTargetShapeCount();940double* lFullWeights = lChannel->GetTargetShapeFullWeights();941
942// Find out which scope the lWeight falls in.943int lStartIndex = -1;944int lEndIndex = -1;945for(int lShapeIndex = 0; lShapeIndex<lShapeCount; ++lShapeIndex) {946if(lWeight > 0 && lWeight <= lFullWeights[0]) {947lEndIndex = 0;948break;949}950if(lWeight > lFullWeights[lShapeIndex] && lWeight < lFullWeights[lShapeIndex+1]) {951lStartIndex = lShapeIndex;952lEndIndex = lShapeIndex + 1;953break;954}955}956
957FbxShape* lStartShape = NULL;958FbxShape* lEndShape = NULL;959if(lStartIndex > -1) {960lStartShape = lChannel->GetTargetShape(lStartIndex);961}962if(lEndIndex > -1) {963lEndShape = lChannel->GetTargetShape(lEndIndex);964}965
966//The weight percentage falls between base geometry and the first target shape.967if(lStartIndex == -1 && lEndShape) {968float lEndWeight = lFullWeights[0];969lWeight = (lWeight/lEndWeight);970
971// cout << "updateMesh : weight = " << lWeight << endl;972for (int j = 0; j < aMesh->getNumVertices(); j++) {973// Add the influence of the shape vertex to the mesh vertex.974glm::vec3 ov = original.getVertices()[j];975glm::vec4 influence = ((fbxToOf(lEndShape->GetControlPoints()[j]) - glm::vec4(ov.x, ov.y, ov.z, 0.0)) * lWeight);976aMesh->getVertices()[j] += glm::vec3(influence.x, influence.y, influence.z);977}978
979} else if(lStartShape && lEndShape) {980float lStartWeight = lFullWeights[lStartIndex];981float lEndWeight = lFullWeights[lEndIndex];982// Calculate the real weight.983lWeight = ofMap(lWeight, lStartWeight, lEndWeight, 0, 1, true);984// cout << "updateMesh : weight = " << lWeight << " lStartWeight " << lStartWeight << " lEndWeight " << lEndWeight << endl;985// lWeight = ((lWeight-lStartWeight)/(lEndWeight-lStartWeight)) * 100;986for (int j = 0; j < aMesh->getNumVertices(); j++) {987// Add the influence of the shape vertex to the mesh vertex.988glm::vec4 influence = (fbxToOf(lEndShape->GetControlPoints()[j] - lStartShape->GetControlPoints()[j] )) * lWeight;989aMesh->getVertices()[j] += glm::vec3(influence.x, influence.y, influence.z);990}991}992
993}994}995}996}
997
998void Mesh::computeSkinDeformation( FbxAMatrix& pGlobalPosition, FbxTime& pTime, FbxAnimLayer* pAnimLayer, FbxVector4* pVertexArray, FbxVector4* pNormalsArray, FbxPose* pPose ) {999FbxSkin * lSkinDeformer = (FbxSkin *)fbxMesh->GetDeformer(0, FbxDeformer::eSkin);1000FbxSkin::EType lSkinningType = lSkinDeformer->GetSkinningType();1001
1002if(lSkinningType == FbxSkin::eLinear || lSkinningType == FbxSkin::eRigid) {1003// cout << "ofxFBXMesh :: computeSkinDeformation :: eRigid " << endl;1004computeLinearDeformation(pGlobalPosition, fbxMesh, pTime, pVertexArray, pPose, false );1005if( pNormalsArray != NULL ) {1006// cout << "ofxFBXMesh :: computeSkinDeformation :: calculate normals array " << endl;1007computeLinearDeformation( pGlobalPosition, fbxMesh, pTime, pNormalsArray, pPose, true );1008}1009} else if(lSkinningType == FbxSkin::eDualQuaternion) {1010// cout << "ofxFBXMesh :: computeSkinDeformation :: eDualQuaternion " << endl;1011computeDualQuaternionDeformation(pGlobalPosition, fbxMesh, pTime, pVertexArray, pPose, false );1012if( pNormalsArray != NULL ) {1013computeLinearDeformation( pGlobalPosition, fbxMesh, pTime, pNormalsArray, pPose, true );1014}1015} else if(lSkinningType == FbxSkin::eBlend) {1016// cout << "ofxFBXMesh :: computeSkinDeformation :: eBlend " << endl;1017int lVertexCount = fbxMesh->GetControlPointsCount();1018FbxVector4* lVertexArrayLinear = new FbxVector4[lVertexCount];1019memcpy(lVertexArrayLinear, fbxMesh->GetControlPoints(), lVertexCount * sizeof(FbxVector4));1020
1021FbxVector4* lVertexArrayDQ = new FbxVector4[lVertexCount];1022memcpy(lVertexArrayDQ, fbxMesh->GetControlPoints(), lVertexCount * sizeof(FbxVector4));1023
1024computeLinearDeformation(pGlobalPosition, fbxMesh, pTime, lVertexArrayLinear, pPose, false );1025computeDualQuaternionDeformation(pGlobalPosition, fbxMesh, pTime, lVertexArrayDQ, pPose, false );1026
1027// To blend the skinning according to the blend weights1028// Final vertex = DQSVertex * blend weight + LinearVertex * (1- blend weight)1029// DQSVertex: vertex that is deformed by dual quaternion skinning method;1030// LinearVertex: vertex that is deformed by classic linear skinning method;1031int lBlendWeightsCount = lSkinDeformer->GetControlPointIndicesCount();1032for(int lBWIndex = 0; lBWIndex<lBlendWeightsCount; ++lBWIndex) {1033double lBlendWeight = lSkinDeformer->GetControlPointBlendWeights()[lBWIndex];1034pVertexArray[lBWIndex] = lVertexArrayDQ[lBWIndex] * lBlendWeight + lVertexArrayLinear[lBWIndex] * (1 - lBlendWeight);1035}1036
1037delete [] lVertexArrayLinear;1038delete [] lVertexArrayDQ;1039
1040if( pNormalsArray != NULL ) {1041FbxVector4* lNormalArrayLinear = new FbxVector4[lVertexCount];1042memcpy( lNormalArrayLinear, mNormalsArray, lVertexCount * sizeof(FbxVector4));1043
1044FbxVector4* lNormalArrayDQ = new FbxVector4[lVertexCount];1045memcpy(lNormalArrayDQ, mNormalsArray, lVertexCount * sizeof(FbxVector4));1046
1047computeLinearDeformation(pGlobalPosition, fbxMesh, pTime, lNormalArrayLinear, pPose, true );1048computeDualQuaternionDeformation(pGlobalPosition, fbxMesh, pTime, lNormalArrayDQ, pPose, true );1049
1050// To blend the skinning according to the blend weights1051// Final vertex = DQSVertex * blend weight + LinearVertex * (1- blend weight)1052// DQSVertex: vertex that is deformed by dual quaternion skinning method;1053// LinearVertex: vertex that is deformed by classic linear skinning method;1054int lBlendWeightsCount = lSkinDeformer->GetControlPointIndicesCount();1055for(int lBWIndex = 0; lBWIndex<lBlendWeightsCount; ++lBWIndex) {1056double lBlendWeight = lSkinDeformer->GetControlPointBlendWeights()[lBWIndex];1057pVertexArray[lBWIndex] = lNormalArrayDQ[lBWIndex] * lBlendWeight + lNormalArrayLinear[lBWIndex] * (1 - lBlendWeight);1058}1059
1060delete [] lNormalArrayLinear;1061delete [] lNormalArrayDQ;1062}1063
1064}1065}
1066
1067// Deform the vertex array in classic linear way.
1068void Mesh::computeLinearDeformation(FbxAMatrix& pGlobalPosition,1069FbxMesh* pMesh,1070FbxTime& pTime,1071FbxVector4* pVertexArray,1072FbxPose* pPose,1073bool bNormals) {1074// All the links must have the same link mode.1075FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)fbxMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode();1076
1077int lVertexCount = pMesh->GetControlPointsCount();1078
1079// cout << "control points count = " << lVertexCount << " mesh verts = " << mesh.getNumVertices() << endl;1080
1081FbxAMatrix* lClusterDeformation = new FbxAMatrix[lVertexCount];1082memset(lClusterDeformation, 0, lVertexCount * sizeof(FbxAMatrix));1083
1084double* lClusterWeight = new double[lVertexCount];1085memset(lClusterWeight, 0, lVertexCount * sizeof(double));1086
1087if (lClusterMode == FbxCluster::eAdditive) {1088for (int i = 0; i < lVertexCount; ++i) {1089lClusterDeformation[i].SetIdentity();1090}1091}1092
1093// For all skins and all clusters, accumulate their deformation and weight1094// on each vertices and store them in lClusterDeformation and lClusterWeight.1095int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);1096
1097// cout << "computeLinearDeformation :: number of skins = " << lSkinCount << endl;1098FbxAMatrix lInfluence;// = lVertexTransformMatrix;1099for ( int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex) {1100FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin);1101
1102int lClusterCount = lSkinDeformer->GetClusterCount();1103for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex) {1104FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex);1105if (!lCluster->GetLink())1106continue;1107
1108// cout << "lClusterIndex: " << lClusterIndex << endl;1109
1110FbxAMatrix lVertexTransformMatrix;1111computeClusterDeformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose, bNormals );1112
1113int lVertexIndexCount = lCluster->GetControlPointIndicesCount();1114for (int k = 0; k < lVertexIndexCount; ++k) {1115int lIndex = lCluster->GetControlPointIndices()[k];1116
1117// Sometimes, the mesh can have less points than at the time of the skinning1118// because a smooth operator was active when skinning but has been deactivated during export.1119if (lIndex >= lVertexCount)1120continue;1121
1122double lWeight = lCluster->GetControlPointWeights()[k];1123
1124if (lWeight == 0.0) {1125continue;1126}1127
1128// Compute the influence of the link on the vertex.1129// FbxAMatrix lInfluence = lVertexTransformMatrix;1130lInfluence = lVertexTransformMatrix;1131MatrixScale(lInfluence, lWeight);1132
1133if (lClusterMode == FbxCluster::eAdditive) {1134// cout << "computeLinearDeformation :: clustermode = eAdditive" << endl;1135// Multiply with the product of the deformations on the vertex.1136MatrixAddToDiagonal(lInfluence, 1.0 - lWeight);1137lClusterDeformation[lIndex] = lInfluence * lClusterDeformation[lIndex];1138
1139// Set the link to 1.0 just to know this vertex is influenced by a link.1140lClusterWeight[lIndex] = 1.0;1141} else // lLinkMode == FbxCluster::eNormalize || lLinkMode == FbxCluster::eTotalOne1142{1143// cout << "computeLinearDeformation :: clustermode = !!eAdditive" << endl;1144// if(k == 0) cout << "computeLinearDeformation :: clustermode != eAdditive " << lInfluence << endl;1145// Add to the sum of the deformations on the vertex.1146MatrixAdd(lClusterDeformation[lIndex], lInfluence);1147
1148// Add to the sum of weights to either normalize or complete the vertex.1149lClusterWeight[lIndex] += lWeight;1150}1151}//For each vertex1152}//lClusterCount1153}1154
1155//Actually deform each vertices here by information stored in lClusterDeformation and lClusterWeight1156// cout << "going to deform the vertices now " << endl;1157FbxVector4 lSrcVertex;1158for (int i = 0; i < lVertexCount; i++) {1159lSrcVertex = pVertexArray[i];1160FbxVector4& lDstVertex = pVertexArray[i];1161
1162double lWeight = lClusterWeight[i];1163
1164// Deform the vertex if there was at least a link with an influence on the vertex,1165if (lWeight != 0.0) {1166lDstVertex = lClusterDeformation[i].MultT(lSrcVertex);1167if (lClusterMode == FbxCluster::eNormalize) {1168// In the normalized link mode, a vertex is always totally influenced by the links.1169// cout << i << " weight: " << lWeight << " enormalize " << endl;1170lDstVertex /= lWeight;1171} else if (lClusterMode == FbxCluster::eTotalOne) {1172// In the total 1 link mode, a vertex can be partially influenced by the links.1173// cout << i << " weight: " << lWeight << " eTotalOne " << endl;1174lSrcVertex *= (1.0 - lWeight);1175lDstVertex += lSrcVertex;1176}1177} else {1178// cout << i << " weight is zero!! " << endl;1179}1180}1181
1182delete [] lClusterDeformation;1183delete [] lClusterWeight;1184}
1185
1186
1187// Deform the vertex array in Dual Quaternion Skinning way.
1188void Mesh::computeDualQuaternionDeformation(FbxAMatrix& pGlobalPosition,1189FbxMesh* pMesh,1190FbxTime& pTime,1191FbxVector4* pVertexArray,1192FbxPose* pPose,1193bool bNormals) {1194// All the links must have the same link mode.1195FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode();1196
1197int lVertexCount = pMesh->GetControlPointsCount();1198int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);1199
1200FbxDualQuaternion* lDQClusterDeformation = new FbxDualQuaternion[lVertexCount];1201memset(lDQClusterDeformation, 0, lVertexCount * sizeof(FbxDualQuaternion));1202
1203double* lClusterWeight = new double[lVertexCount];1204memset(lClusterWeight, 0, lVertexCount * sizeof(double));1205
1206// For all skins and all clusters, accumulate their deformation and weight1207// on each vertices and store them in lClusterDeformation and lClusterWeight.1208for ( int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex)1209{1210FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin);1211int lClusterCount = lSkinDeformer->GetClusterCount();1212for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex)1213{1214FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex);1215if (!lCluster->GetLink())1216continue;1217
1218FbxAMatrix lVertexTransformMatrix;1219computeClusterDeformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose, bNormals );1220
1221FbxQuaternion lQ = lVertexTransformMatrix.GetQ();1222FbxVector4 lT = lVertexTransformMatrix.GetT();1223FbxDualQuaternion lDualQuaternion(lQ, lT);1224
1225int lVertexIndexCount = lCluster->GetControlPointIndicesCount();1226for (int k = 0; k < lVertexIndexCount; ++k)1227{1228int lIndex = lCluster->GetControlPointIndices()[k];1229
1230// Sometimes, the mesh can have less points than at the time of the skinning1231// because a smooth operator was active when skinning but has been deactivated during export.1232if (lIndex >= lVertexCount)1233continue;1234
1235double lWeight = lCluster->GetControlPointWeights()[k];1236
1237if (lWeight == 0.0)1238continue;1239
1240// Compute the influence of the link on the vertex.1241FbxDualQuaternion lInfluence = lDualQuaternion * lWeight;1242if (lClusterMode == FbxCluster::eAdditive)1243{1244// Simply influenced by the dual quaternion.1245lDQClusterDeformation[lIndex] = lInfluence;1246
1247// Set the link to 1.0 just to know this vertex is influenced by a link.1248lClusterWeight[lIndex] = 1.0;1249}1250else // lLinkMode == FbxCluster::eNormalize || lLinkMode == FbxCluster::eTotalOne1251{1252if(lClusterIndex == 0)1253{1254lDQClusterDeformation[lIndex] = lInfluence;1255}1256else1257{1258// Add to the sum of the deformations on the vertex.1259// Make sure the deformation is accumulated in the same rotation direction.1260// Use dot product to judge the sign.1261double lSign = lDQClusterDeformation[lIndex].GetFirstQuaternion().DotProduct(lDualQuaternion.GetFirstQuaternion());1262if( lSign >= 0.0 )1263{1264lDQClusterDeformation[lIndex] += lInfluence;1265}1266else1267{1268lDQClusterDeformation[lIndex] -= lInfluence;1269}1270}1271// Add to the sum of weights to either normalize or complete the vertex.1272lClusterWeight[lIndex] += lWeight;1273}1274}//For each vertex1275}//lClusterCount1276}1277
1278//Actually deform each vertices here by information stored in lClusterDeformation and lClusterWeight1279for (int i = 0; i < lVertexCount; i++) {1280FbxVector4 lSrcVertex = pVertexArray[i];1281FbxVector4& lDstVertex = pVertexArray[i];1282
1283double lWeightSum = lClusterWeight[i];1284
1285// Deform the vertex if there was at least a link with an influence on the vertex,1286if (lWeightSum != 0.0)1287{1288lDQClusterDeformation[i].Normalize();1289lDstVertex = lDQClusterDeformation[i].Deform(lDstVertex);1290
1291if (lClusterMode == FbxCluster::eNormalize)1292{1293// In the normalized link mode, a vertex is always totally influenced by the links.1294lDstVertex /= lWeightSum;1295}1296else if (lClusterMode == FbxCluster::eTotalOne)1297{1298// In the total 1 link mode, a vertex can be partially influenced by the links.1299lSrcVertex *= (1.0 - lWeightSum);1300lDstVertex += lSrcVertex;1301}1302}1303}1304
1305delete [] lDQClusterDeformation;1306delete [] lClusterWeight;1307}
1308
1309
1310//Compute the transform matrix that the cluster will transform the vertex.
1311void Mesh::computeClusterDeformation(FbxAMatrix& pGlobalPosition,1312FbxMesh* pMesh,1313FbxCluster* pCluster,1314FbxAMatrix& pVertexTransformMatrix,1315FbxTime pTime,1316FbxPose* pPose, bool bNormal ) {1317
1318FbxCluster::ELinkMode lClusterMode = pCluster->GetLinkMode();1319
1320ofxFBXSource::Bone* bone = NULL;1321ofxFBXSource::Cluster* cluster = NULL;1322FbxNode* boneNode = pCluster->GetLink();1323
1324if(boneNode) {1325if(boneNode->GetUserDataPtr()) {1326bone = static_cast<ofxFBXSource::Bone *>(boneNode->GetUserDataPtr());1327}1328}1329
1330if(bone != NULL) {1331if(pCluster->GetUserDataPtr()) {1332cluster = static_cast<ofxFBXSource::Cluster *>(pCluster->GetUserDataPtr());1333// cluster->update( pTime, pPose );1334}1335}1336
1337if( bone != NULL && cluster != NULL ) {1338// cout << "computeClusterDeformation: bone != NULL && cluster != NULL " << bone->getName() << endl;1339// cout << "We have cached cluster and bone! " << bone->getName() << endl;1340// pVertexTransformMatrix = cluster->preTrans * bone->fbxTransform * cluster->postTrans;1341// pVertexTransformMatrix = cluster->preTrans * bone->fbxTransform * cluster->postTrans;1342pVertexTransformMatrix = cluster->preTrans * bone->fbxTransform * cluster->postTrans;1343if( bNormal ) {1344// cout << "We have cached cluster andNORMAL bone! " << bone->getName() << endl;1345pVertexTransformMatrix = pVertexTransformMatrix.Inverse();1346pVertexTransformMatrix = pVertexTransformMatrix.Transpose();1347}1348} else {1349
1350FbxAMatrix lReferenceGlobalInitPosition;1351FbxAMatrix lReferenceGlobalCurrentPosition;1352FbxAMatrix lAssociateGlobalInitPosition;1353FbxAMatrix lAssociateGlobalCurrentPosition;1354FbxAMatrix lClusterGlobalInitPosition;1355FbxAMatrix lClusterGlobalCurrentPosition;1356
1357FbxAMatrix lReferenceGeometry;1358FbxAMatrix lAssociateGeometry;1359FbxAMatrix lClusterGeometry;1360
1361FbxAMatrix lClusterRelativeInitPosition;1362FbxAMatrix lClusterRelativeCurrentPositionInverse;1363
1364// nothing is setup for the control of the bones, so we are just doing animation1365// right now, can't do animation and control the bones at the same time.1366if (lClusterMode == FbxCluster::eAdditive && pCluster->GetAssociateModel()) {1367
1368// cout << "computeClusterDeformation: FbxCluster::eAdditive " << endl;1369
1370pCluster->GetTransformAssociateModelMatrix(lAssociateGlobalInitPosition);1371// Geometric transform of the model1372lAssociateGeometry = GetGeometry(pCluster->GetAssociateModel());1373lAssociateGlobalInitPosition *= lAssociateGeometry;1374lAssociateGlobalCurrentPosition = GetGlobalPosition(pCluster->GetAssociateModel(), pTime, pPose);1375
1376pCluster->GetTransformMatrix(lReferenceGlobalInitPosition);1377// Multiply lReferenceGlobalInitPosition by Geometric Transformation1378lReferenceGeometry = GetGeometry(pMesh->GetNode());1379lReferenceGlobalInitPosition *= lReferenceGeometry;1380lReferenceGlobalCurrentPosition = pGlobalPosition;1381
1382// Get the link initial global position and the link current global position.1383pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition);1384// Multiply lClusterGlobalInitPosition by Geometric Transformation1385lClusterGeometry = GetGeometry(pCluster->GetLink());1386lClusterGlobalInitPosition *= lClusterGeometry;1387lClusterGlobalCurrentPosition = GetGlobalPosition(pCluster->GetLink(), pTime, pPose);1388
1389// Compute the shift of the link relative to the reference.1390//ModelM-1 * AssoM * AssoGX-1 * LinkGX * LinkM-1*ModelM1391pVertexTransformMatrix = lReferenceGlobalInitPosition.Inverse() * lAssociateGlobalInitPosition * lAssociateGlobalCurrentPosition.Inverse() *1392lClusterGlobalCurrentPosition * lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition;1393} else {1394
1395// cout << "computeClusterDeformation: !!FbxCluster::eAdditive " << endl;1396
1397pCluster->GetTransformMatrix(lReferenceGlobalInitPosition);1398lReferenceGlobalCurrentPosition = pGlobalPosition;1399// Multiply lReferenceGlobalInitPosition by Geometric Transformation1400lReferenceGeometry = GetGeometry(pMesh->GetNode());1401lReferenceGlobalInitPosition *= lReferenceGeometry;1402
1403// Get the link initial global position and the link current global position.1404pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition);1405lClusterGlobalCurrentPosition = GetGlobalPosition(pCluster->GetLink(), pTime, pPose);1406
1407// Compute the initial position of the link relative to the reference.1408lClusterRelativeInitPosition = lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition;1409
1410// Compute the current position of the link relative to the reference.1411lClusterRelativeCurrentPositionInverse = lReferenceGlobalCurrentPosition.Inverse() * lClusterGlobalCurrentPosition;1412
1413// Compute the shift of the link relative to the reference.1414pVertexTransformMatrix = lClusterRelativeCurrentPositionInverse * lClusterRelativeInitPosition;1415}1416}1417}
1418
1419//--------------------------------------------------------------
1420void Mesh::populateNormals( FbxVector4* pNormalsArray ) {1421
1422const int lVertexCount = fbxMesh->GetControlPointsCount();1423
1424//get the normal element1425FbxGeometryElementNormal* lNormalElement = fbxMesh->GetElementNormal();1426if(lNormalElement)1427{1428//mapping mode is by control points. The mesh should be smooth and soft.1429//we can get normals by retrieving each control point1430if( lNormalElement->GetMappingMode() == FbxGeometryElement::eByControlPoint )1431{1432//Let's get normals of each vertex, since the mapping mode of normal element is by control point1433for(int lVertexIndex = 0; lVertexIndex < fbxMesh->GetControlPointsCount(); lVertexIndex++)1434{1435int lNormalIndex = 0;1436//reference mode is direct, the normal index is same as vertex index.1437//get normals by the index of control vertex1438if( lNormalElement->GetReferenceMode() == FbxGeometryElement::eDirect )1439lNormalIndex = lVertexIndex;1440
1441//reference mode is index-to-direct, get normals by the index-to-direct1442if(lNormalElement->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)1443lNormalIndex = lNormalElement->GetIndexArray().GetAt(lVertexIndex);1444
1445//Got normals of each vertex.1446//void KFbxMesh::GetPolygonVertexNormal( int pPolyIndex, int pVertexIndex, KFbxVector4 &pNormal) const;1447//void KFbxMesh::GetPolygonVertexNormal( int pPolyIndex, int pVertexIndex, KFbxVector4 &pNormal) const;1448FbxVector4 lNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex);1449pNormalsArray[ lVertexIndex ] = lNormal;1450// lNormals->GetDirectArray().Release((void**)&lFbxNormals)1451// if( gVerbose ) FBXSDK_printf("normals for vertex[%d]: %f %f %f %f \n", lVertexIndex, lNormal[0], lNormal[1], lNormal[2], lNormal[3]);1452
1453//add your custom code here, to output normals or get them into a list, such as KArrayTemplate<FbxVector4>1454//. . .1455}//end for lVertexIndex1456}//end eByControlPoint1457//mapping mode is by polygon-vertex.1458//we can get normals by retrieving polygon-vertex.1459else if(lNormalElement->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)1460{1461int lIndexByPolygonVertex = 0;1462//Let's get normals of each polygon, since the mapping mode of normal element is by polygon-vertex.1463for(int lPolygonIndex = 0; lPolygonIndex < fbxMesh->GetPolygonCount(); lPolygonIndex++)1464{1465//get polygon size, you know how many vertices in current polygon.1466int lPolygonSize = fbxMesh->GetPolygonSize(lPolygonIndex);1467//retrieve each vertex of current polygon.1468for(int i = 0; i < lPolygonSize; i++)1469{1470int lNormalIndex = 0;1471//reference mode is direct, the normal index is same as lIndexByPolygonVertex.1472if( lNormalElement->GetReferenceMode() == FbxGeometryElement::eDirect )1473lNormalIndex = lIndexByPolygonVertex;1474
1475//reference mode is index-to-direct, get normals by the index-to-direct1476if(lNormalElement->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)1477lNormalIndex = lNormalElement->GetIndexArray().GetAt(lIndexByPolygonVertex);1478
1479//Got normals of each polygon-vertex.1480FbxVector4 lNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex);1481const int lControlPointIndex = fbxMesh->GetPolygonVertex( lPolygonIndex, i );1482pNormalsArray[ lControlPointIndex ] = lNormal;1483
1484// if( gVerbose ) FBXSDK_printf("normals for polygon[%d]vertex[%d]: %f %f %f %f \n",1485// lPolygonIndex, i, lNormal[0], lNormal[1], lNormal[2], lNormal[3]);1486
1487
1488
1489//add your custom code here, to output normals or get them into a list, such as KArrayTemplate<FbxVector4>1490//. . .1491
1492lIndexByPolygonVertex++;1493}//end for i //lPolygonSize1494}//end for lPolygonIndex //PolygonCount1495
1496}//end eByPolygonVertex1497}//end if lNormalElement1498}
1499