Hi again,
I have a problem in reading the normals info stored per Morph targets.
This is the code that I'm using, from the samples:
int lBlendShapeCount, lBlendShapeChannelCount, lTargetShapeCount; FbxBlendShape* lBlendShape; FbxBlendShapeChannel* lBlendShapeChannel; FbxShape* lShape; for (int lBlendShapeIndex = 0; lBlendShapeIndex < lBlendShapeCount; ++lBlendShapeIndex) { lBlendShape = (FbxBlendShape*)pMesh->GetDeformer(lBlendShapeIndex, FbxDeformer::eBlendShape); lBlendShapeChannelCount = lBlendShape->GetBlendShapeChannelCount(); for (int lBlendShapeChannelIndex = 0; lBlendShapeChannelIndex < lBlendShapeChannelCount; ++lBlendShapeChannelIndex) { lBlendShapeChannel = lBlendShape->GetBlendShapeChannel(lBlendShapeChannelIndex); lTargetShapeCount = lBlendShapeChannel->GetTargetShapeCount(); for (int lTargetShapeIndex = 0; lTargetShapeIndex < lTargetShapeCount; ++lTargetShapeIndex) { lShape = lBlendShapeChannel->GetTargetShape(lTargetShapeIndex); int j, lControlPointsCount = lShape->GetControlPointsCount(); FbxVector4* lControlPoints = lShape->GetControlPoints(); FbxLayerElementArrayTemplate<FbxVector4>* lNormals = NULL;
bool lStatus = lShape->GetNormals(&lNormals);
[...]
The problem is:
lStatus always returns true, but the values are all 0.0!
I check the ASCII version of my FBX file and there are non 0 values in the propriety "normals" of each shape!
Where is my error?
There is a related issue here:
http://forums.autodesk.com/t5/fbx-sdk/normals-and-morph-targets/td-p/5878531
The FBX file is 90MB, so it might bounce if it was sent via email. It will not upload to the forrm because it is too big. Do you have another method for receiving files?
I can send you by email the link for downloading it from my Google Drive. If that is ok.
Hi Kors,
Could you figure out answer to your problem? Because I am stuck at the same error. It would be great help if you can help me with solution.
I made a phenomenon that morph target Normals is wrong.
The first post different phenomenon, but I think the trouble.
model is 4 square simple.
Morph target has moved only one vertex, and turn the normal 90 degrees.
State is the normal line of the move vertices, which was fixed to the lock.
FBX is write in Ascii.
Seem to correctly value is in the field of looking at the contents [Normals].
Dump Then in ImportScene that the FBX in [FBX SDK \ 2016.1.1 \ samples \], re-calculated the normal is in the target.
The Export information and Import information is misaligned, than there is a problem with the SDK?
Hey all. I've struggled with this the last few days, going through much the same steps as others have in this thread.
So the situation is that we've got an FbxBlendShape deformer; we've iterated over its FbxBlendShapeChannels, and we now have on our hands some number of actual FbxShape instances, where all the real data is kept.
We know we can easily get positional data from fbxShape->GetControlPoints(). That's defined in the FbxGeometryBase superclass. So is the function GetNormals() (although it's in the WARNING!! DO NOT USE! section, which should perhaps be a tip-off that we're in dangerous waters) which works fine for FbxMesh, but yields only zeroes for FbxShape.
And yeah, when you eyeball the file -- easiest with an ASCII export -- the normals are clearly there.
The access method that does seem to work is:
FbxGeometryElementNormal* shapeNormals = fbxShape->GetElementNormal();
which is more annoying to work with than GetNormals(), and requires checking shapeNormals->GetMappingMode() and shapeNormals->GetReferenceMode() and adjusting accordingly. The mapping mode will be eNone if there are no normals, or it can be eByControlPoint or ePolygonVertex and perhaps others. The reference mode can be either eDirect or eIndexToDirect. There's lots of examples of code around on how to deal with mapping mode and reference mode, but ultimately you're going to end up doing something like
fbxShape->GetElementNormal()->GetIndexArray()->GetAt(someIx)
and as far as I can tell, this does actually return us the normal we're looking for.
I'll be adding a (hopefully) working implementation of this to https://github.com/facebookincubator/FBX2glTF shortly, if anybody wants to see it in action.
One final wrinkle to all this:
The only conclusion that makes sense to me is that the FBX SDK actually computes normals (and maybe tangents) from the underlying geometry. While this is a nice service, it would be great if I had been told about it. There's a huge difference between author-originated normals and computed normals -- especially in the context of blend shapes.
I would still love any insight into whether Maya ever maintains normals for Blend Shapes, and/or whether they're lost in the export, and especially whether the FBX SDK computes them from geometry when they're requested using the method outlined in the previous post.
Hi,
the normals stored in the shapes (on disk) are ... deltas (the same way the vertices are) from the "base" geometry. This means that if you have a huge model but only one vertex has a displacement in the target shape, you will find only one value stored in the file. Upon reading the FBX file, the shape target is constructed by adding the deltas to the geometry base.
The correct method to access the normals on the shape, as par.winzell found out, is to go through the FbxShape:
FbxMesh* m = n->GetMesh(); int nbShapes = m->GetDeformerCount(FbxDeformer::eBlendShape); for (int s = 0; s < nbShapes; s++) { FbxBlendShape* lBS = FbxCast<FbxBlendShape>(m->GetDeformer(s, FbxDeformer::eBlendShape)); if (lBS) { for (int bsc = 0, bscc = lBS->GetBlendShapeChannelCount(); bsc < bscc; bsc++) { FbxBlendShapeChannel* lBSC = lBS->GetBlendShapeChannel(bsc); for (int sc = 0, scc = lBSC->GetTargetShapeCount(); sc < scc; sc++) { FbxShape* lShape = lBSC->GetTargetShape(sc); for (int n = 0, nc = lShape->GetElementNormalCount(); n < nc; n++) { FbxLayerElementNormal* lN = (FbxLayerElementNormal*)lShape->GetElementNormal(n); // should check what is the mapping so we can access the data accordingly // if (lN->GetMappingMode() == FbxLayerElement::eByPolygonVertex) ... for (int i = 0; i < lN->GetDirectArray().GetCount(); i++) { FbxVector4 v = lN->GetDirectArray()[i]; printf("%3d: %f %f %f\n", i, v[0], v[1], v[2]); } } } } } }
Can't find what you're looking for? Ask the community or share your knowledge.