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
{
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 {
explicit BlendChannel(FbxDouble 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;
// one for each FbxShape
@ -510,7 +510,7 @@ public:
return channels.at(channelIx).defaultDeform;
}
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];
}
size_t GetAnimCount(size_t channelIx) const { return channels.at(channelIx).animations.size(); }
@ -589,7 +589,7 @@ private:
#endif
// finally combine all this into a TargetShape and add it to our work-in-progress BlendChannel
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();
std::vector<const FbxBlendShapesAccess::TargetShape *> targetShapes;
for (size_t shapeIx = 0; shapeIx < blendShapes.GetChannelCount(); shapeIx ++) {
for (size_t targetIx = 0; targetIx < blendShapes.GetTargetShapeCount(shapeIx); targetIx ++) {
const auto &shape = blendShapes.GetTargetShape(shapeIx, targetIx);
float defaultDeform = static_cast<float>(blendShapes.GetDefaultDeform(shapeIx));
const FbxBlendShapesAccess::TargetShape &shape = blendShapes.GetTargetShape(shapeIx, targetIx);
targetShapes.push_back(&shape);
rawSurface.blendChannels.push_back(RawBlendChannel {
defaultDeform,
static_cast<float>(blendShapes.GetDefaultDeform(shapeIx)),
!shape.normals.empty(),
!shape.tangents.empty()
});
@ -824,21 +826,22 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
rawSurface.bounds.AddPoint(vertex.position);
for (size_t shapeIx = 0; shapeIx < blendShapes.GetChannelCount(); shapeIx ++) {
for (size_t targetIx = 0; targetIx < blendShapes.GetTargetShapeCount(shapeIx); targetIx ++) {
const auto &shape = blendShapes.GetTargetShape(shapeIx, targetIx);
if (!targetShapes.empty()) {
vertex.blendSurfaceIx = rawSurfaceIndex;
for (const auto *targetShape : targetShapes) {
RawBlendVertex blendVertex;
// the morph target positions must be transformed just as with the vertex positions above
blendVertex.position = toVec3(transform.MultNormalize(shape.positions[controlPointIndex]));
if (!shape.normals.empty()) {
blendVertex.normal = toVec3(shape.normals[controlPointIndex]);
blendVertex.position = toVec3f(transform.MultNormalize(targetShape->positions[controlPointIndex]));
if (!targetShape->normals.empty()) {
blendVertex.normal = toVec3f(targetShape->normals[controlPointIndex]);
}
if (!shape.tangents.empty()) {
blendVertex.tangent = toVec4(shape.tangents[controlPointIndex]);
if (!targetShape->tangents.empty()) {
blendVertex.tangent = toVec4f(targetShape->tangents[controlPointIndex]);
}
vertex.blends.push_back(blendVertex);
}
} else {
vertex.blendSurfaceIx = -1;
}
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
// 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).
auto findInInterval = [&](double p, int n) {
auto findInInterval = [&](const double p, const int n) {
if (n >= targetCount) {
// p is certainly completely left of this interval
return NAN;
}
double leftWeight = (n >= 0) ? blendShapes.GetTargetShape(channelIx, n).fullWeight : 0;
if (p < leftWeight) {
return NAN;
double leftWeight = 0;
if (n >= 0) {
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;
if (p > rightWeight) {
double rightWeight = blendShapes.GetTargetShape(channelIx, n+1).fullWeight;
if (p > rightWeight && n+1 < targetCount-1) {
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));
};

View File

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

View File

@ -58,9 +58,11 @@ struct RawVertex
Vec2f uv1 { 0.0f };
Vec4i jointIndices { 0, 0, 0, 0 };
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.
// the size of this vector is always identical to the size of RawSurface.blendChannels
// if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh; otherwise, -1
int blendSurfaceIx = -1;
// the size of this vector is always identical to the size of the corresponding RawSurface.blendChannels
std::vector<RawBlendVertex> blends { };
bool polarityUv0;