Drop 0-100 assumptions. Let influences go wild.

This commit is contained in:
Par Winzell 2017-11-03 23:36:59 -07:00
parent ec303a3b8a
commit 9520c26649
3 changed files with 52 additions and 41 deletions

View File

@ -470,28 +470,28 @@ private:
class FbxBlendShapesAccess class FbxBlendShapesAccess
{ {
public: public:
struct TargetShape
{
TargetShape(
double fullWeight,
const std::vector<FbxVector4> &positions,
const std::vector<FbxVector4> &normals,
const std::vector<FbxVector4> &tangents
) : fullWeight(fullWeight),
positions(positions),
normals(normals),
tangents(tangents) {}
const double fullWeight;
const std::vector<FbxVector4> positions;
const std::vector<FbxVector4> normals;
const std::vector<FbxVector4> tangents;
};
struct BlendChannel { struct BlendChannel {
explicit BlendChannel(FbxDouble defaultDeform) : explicit BlendChannel(FbxDouble defaultDeform) :
defaultDeform(defaultDeform) defaultDeform(defaultDeform)
{} {}
struct TargetShape {
TargetShape(
double fullWeight,
const std::vector<FbxVector4> &positions,
const std::vector<FbxVector4> &normals,
const std::vector<FbxVector4> &tangents
) : fullWeight(fullWeight),
positions(positions),
normals(normals),
tangents(tangents)
{}
const double fullWeight;
const std::vector<FbxVector4> positions;
const std::vector<FbxVector4> normals;
const std::vector<FbxVector4> tangents;
};
const FbxDouble defaultDeform; const FbxDouble defaultDeform;
// one for each FbxShape // one for each FbxShape
@ -510,7 +510,7 @@ public:
return channels.at(channelIx).defaultDeform; return channels.at(channelIx).defaultDeform;
} }
size_t GetTargetShapeCount(size_t channelIx) const { return channels[channelIx].targetShapes.size(); } size_t GetTargetShapeCount(size_t channelIx) const { return channels[channelIx].targetShapes.size(); }
const BlendChannel::TargetShape &GetTargetShape(size_t channelIx, size_t targetShapeIx) const { const TargetShape &GetTargetShape(size_t channelIx, size_t targetShapeIx) const {
return channels.at(channelIx).targetShapes[targetShapeIx]; return channels.at(channelIx).targetShapes[targetShapeIx];
} }
size_t GetAnimCount(size_t channelIx) const { return channels.at(channelIx).animations.size(); } size_t GetAnimCount(size_t channelIx) const { return channels.at(channelIx).animations.size(); }
@ -589,7 +589,7 @@ private:
#endif #endif
// finally combine all this into a TargetShape and add it to our work-in-progress BlendChannel // finally combine all this into a TargetShape and add it to our work-in-progress BlendChannel
shape.targetShapes.push_back( shape.targetShapes.push_back(
BlendChannel::TargetShape(fullWeights[targetShapeIx], positions, normals, tangents) TargetShape(fullWeights[targetShapeIx], positions, normals, tangents)
); );
} }
@ -712,12 +712,14 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
} }
rawSurface.blendChannels.clear(); rawSurface.blendChannels.clear();
std::vector<const FbxBlendShapesAccess::TargetShape *> targetShapes;
for (size_t shapeIx = 0; shapeIx < blendShapes.GetChannelCount(); shapeIx ++) { for (size_t shapeIx = 0; shapeIx < blendShapes.GetChannelCount(); shapeIx ++) {
for (size_t targetIx = 0; targetIx < blendShapes.GetTargetShapeCount(shapeIx); targetIx ++) { for (size_t targetIx = 0; targetIx < blendShapes.GetTargetShapeCount(shapeIx); targetIx ++) {
const auto &shape = blendShapes.GetTargetShape(shapeIx, targetIx); const FbxBlendShapesAccess::TargetShape &shape = blendShapes.GetTargetShape(shapeIx, targetIx);
float defaultDeform = static_cast<float>(blendShapes.GetDefaultDeform(shapeIx)); targetShapes.push_back(&shape);
rawSurface.blendChannels.push_back(RawBlendChannel { rawSurface.blendChannels.push_back(RawBlendChannel {
defaultDeform, static_cast<float>(blendShapes.GetDefaultDeform(shapeIx)),
!shape.normals.empty(), !shape.normals.empty(),
!shape.tangents.empty() !shape.tangents.empty()
}); });
@ -824,21 +826,22 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
rawSurface.bounds.AddPoint(vertex.position); rawSurface.bounds.AddPoint(vertex.position);
for (size_t shapeIx = 0; shapeIx < blendShapes.GetChannelCount(); shapeIx ++) { if (!targetShapes.empty()) {
for (size_t targetIx = 0; targetIx < blendShapes.GetTargetShapeCount(shapeIx); targetIx ++) { vertex.blendSurfaceIx = rawSurfaceIndex;
const auto &shape = blendShapes.GetTargetShape(shapeIx, targetIx); for (const auto *targetShape : targetShapes) {
RawBlendVertex blendVertex; RawBlendVertex blendVertex;
// the morph target positions must be transformed just as with the vertex positions above // the morph target positions must be transformed just as with the vertex positions above
blendVertex.position = toVec3(transform.MultNormalize(shape.positions[controlPointIndex])); blendVertex.position = toVec3f(transform.MultNormalize(targetShape->positions[controlPointIndex]));
if (!shape.normals.empty()) { if (!targetShape->normals.empty()) {
blendVertex.normal = toVec3(shape.normals[controlPointIndex]); blendVertex.normal = toVec3f(targetShape->normals[controlPointIndex]);
} }
if (!shape.tangents.empty()) { if (!targetShape->tangents.empty()) {
blendVertex.tangent = toVec4(shape.tangents[controlPointIndex]); blendVertex.tangent = toVec4f(targetShape->tangents[controlPointIndex]);
} }
vertex.blends.push_back(blendVertex); vertex.blends.push_back(blendVertex);
} }
} else {
vertex.blendSurfaceIx = -1;
} }
if (skinning.IsSkinned()) { if (skinning.IsSkinned()) {
@ -1138,20 +1141,25 @@ static void ReadAnimations(RawModel &raw, FbxScene *pScene)
// the target shape 'fullWeight' values are a strictly ascending list of floats (between // the target shape 'fullWeight' values are a strictly ascending list of floats (between
// 0 and 100), forming a sequence of intervals -- this convenience function figures out if // 0 and 100), forming a sequence of intervals -- this convenience function figures out if
// 'p' lays between some certain target fullWeights, and if so where (from 0 to 1). // 'p' lays between some certain target fullWeights, and if so where (from 0 to 1).
auto findInInterval = [&](double p, int n) { auto findInInterval = [&](const double p, const int n) {
if (n >= targetCount) { if (n >= targetCount) {
// p is certainly completely left of this interval // p is certainly completely left of this interval
return NAN; return NAN;
} }
double leftWeight = (n >= 0) ? blendShapes.GetTargetShape(channelIx, n).fullWeight : 0; double leftWeight = 0;
if (p < leftWeight) { if (n >= 0) {
return NAN; leftWeight = blendShapes.GetTargetShape(channelIx, n).fullWeight;
if (p < leftWeight) {
return NAN;
}
// the first interval implicitly includes all lesser influence values
} }
double rightWeight = (n < targetCount-1) ? blendShapes.GetTargetShape(channelIx, n+1).fullWeight : 100; double rightWeight = blendShapes.GetTargetShape(channelIx, n+1).fullWeight;
if (p > rightWeight) { if (p > rightWeight && n+1 < targetCount-1) {
return NAN; return NAN;
// the last interval implicitly includes all greater influence values
} }
// at this point leftWeight <= p <= rightWeight, return [0, 1] // transform p linearly such that [leftWeight, rightWeight] => [0, 1]
return static_cast<float>((p - leftWeight) / (rightWeight - leftWeight)); return static_cast<float>((p - leftWeight) / (rightWeight - leftWeight));
}; };

View File

@ -38,6 +38,7 @@ bool RawVertex::operator==(const RawVertex &other) const
(jointIndices == other.jointIndices) && (jointIndices == other.jointIndices) &&
(jointWeights == other.jointWeights) && (jointWeights == other.jointWeights) &&
(polarityUv0 == other.polarityUv0) && (polarityUv0 == other.polarityUv0) &&
(blendSurfaceIx == other.blendSurfaceIx) &&
(blends == other.blends); (blends == other.blends);
} }

View File

@ -58,9 +58,11 @@ struct RawVertex
Vec2f uv1 { 0.0f }; Vec2f uv1 { 0.0f };
Vec4i jointIndices { 0, 0, 0, 0 }; Vec4i jointIndices { 0, 0, 0, 0 };
Vec4f jointWeights { 0.0f }; Vec4f jointWeights { 0.0f };
// end of members that directly correspond to vertex attributes
// each vertex can have many alternate positions, normals and tangents -- one set per blend shape target. // if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh; otherwise, -1
// the size of this vector is always identical to the size of RawSurface.blendChannels int blendSurfaceIx = -1;
// the size of this vector is always identical to the size of the corresponding RawSurface.blendChannels
std::vector<RawBlendVertex> blends { }; std::vector<RawBlendVertex> blends { };
bool polarityUv0; bool polarityUv0;