Missing files for commit a7b9f8, adding up to 16 bone influences.
This commit is contained in:
parent
a7b9f80e32
commit
b6d7fd04f2
|
@ -140,11 +140,24 @@ int main(int argc, char* argv[]) {
|
||||||
gltfOptions.useBlendShapeTangents,
|
gltfOptions.useBlendShapeTangents,
|
||||||
"Include blend shape tangents, if reported present by the FBX SDK.");
|
"Include blend shape tangents, if reported present by the FBX SDK.");
|
||||||
|
|
||||||
|
app.add_flag(
|
||||||
|
"--normalize-weights",
|
||||||
|
gltfOptions.normalizeSkinningWeights,
|
||||||
|
"Normalize skinning weights.");
|
||||||
|
|
||||||
|
app.add_option(
|
||||||
|
"--skinning-weights",
|
||||||
|
gltfOptions.maxSkinningWeights,
|
||||||
|
"How many joint influences per vertex are allowed.",
|
||||||
|
true)
|
||||||
|
->check(CLI::Range(1, RawModel::MAX_SUPPORTED_WEIGHTS));
|
||||||
|
|
||||||
app.add_option(
|
app.add_option(
|
||||||
"-k,--keep-attribute",
|
"-k,--keep-attribute",
|
||||||
[&](std::vector<std::string> attributes) -> bool {
|
[&](std::vector<std::string> attributes) -> bool {
|
||||||
gltfOptions.keepAttribs =
|
gltfOptions.keepAttribs =
|
||||||
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0 | RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1;
|
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0 | RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1 |
|
||||||
|
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES2 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS2 | RAW_VERTEX_ATTRIBUTE_JOINT_INDICES3 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS3;
|
||||||
for (std::string attribute : attributes) {
|
for (std::string attribute : attributes) {
|
||||||
if (attribute == "position") {
|
if (attribute == "position") {
|
||||||
gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
||||||
|
@ -204,7 +217,7 @@ int main(int argc, char* argv[]) {
|
||||||
app.add_option(
|
app.add_option(
|
||||||
"--draco-bits-for-normals",
|
"--draco-bits-for-normals",
|
||||||
gltfOptions.draco.quantBitsNormal,
|
gltfOptions.draco.quantBitsNormal,
|
||||||
"How many bits to quantize nornals to.",
|
"How many bits to quantize normals to.",
|
||||||
true)
|
true)
|
||||||
->check(CLI::Range(1, 32))
|
->check(CLI::Range(1, 32))
|
||||||
->group("Draco");
|
->group("Draco");
|
||||||
|
@ -310,7 +323,7 @@ int main(int argc, char* argv[]) {
|
||||||
if (!texturesTransforms.empty()) {
|
if (!texturesTransforms.empty()) {
|
||||||
raw.TransformTextures(texturesTransforms);
|
raw.TransformTextures(texturesTransforms);
|
||||||
}
|
}
|
||||||
raw.Condense();
|
raw.Condense(gltfOptions.maxSkinningWeights, gltfOptions.normalizeSkinningWeights);
|
||||||
raw.TransformGeometry(gltfOptions.computeNormals);
|
raw.TransformGeometry(gltfOptions.computeNormals);
|
||||||
|
|
||||||
std::ofstream outStream; // note: auto-flushes in destructor
|
std::ofstream outStream; // note: auto-flushes in destructor
|
||||||
|
|
|
@ -99,6 +99,10 @@ struct GltfOptions
|
||||||
bool useBlendShapeNormals { false };
|
bool useBlendShapeNormals { false };
|
||||||
/** Whether to include blend shape tangents, if present according to the SDK. */
|
/** Whether to include blend shape tangents, if present according to the SDK. */
|
||||||
bool useBlendShapeTangents { false };
|
bool useBlendShapeTangents { false };
|
||||||
|
/** Whether to normalized skinning weights. */
|
||||||
|
bool normalizeSkinningWeights { true };
|
||||||
|
/** Maximum number of bone influences per vertex. */
|
||||||
|
int maxSkinningWeights { 4 };
|
||||||
/** When to compute vertex normals from geometry. */
|
/** When to compute vertex normals from geometry. */
|
||||||
ComputeNormalsOption computeNormals = ComputeNormalsOption::BROKEN;
|
ComputeNormalsOption computeNormals = ComputeNormalsOption::BROKEN;
|
||||||
/** When to use 32-bit indices. */
|
/** When to use 32-bit indices. */
|
||||||
|
|
|
@ -69,18 +69,18 @@ static RawMaterialType GetMaterialType(
|
||||||
return skinned ? RAW_MATERIAL_TYPE_SKINNED_OPAQUE : RAW_MATERIAL_TYPE_OPAQUE;
|
return skinned ? RAW_MATERIAL_TYPE_SKINNED_OPAQUE : RAW_MATERIAL_TYPE_OPAQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calcMinMax(RawSurface& rawSurface, const FbxSkinningAccess& skinning, const FbxVector4& globalPosition, const Vec4i& indices, const Vec4f& weights) {
|
static void calcMinMax(RawSurface& rawSurface, const FbxSkinningAccess& skinning, const FbxVector4& globalPosition, const std::vector<RawVertexSkinningInfo>& indicesAndWeights) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < indicesAndWeights.size(); i++) {
|
||||||
if (weights[i] > 0.0f) {
|
if (indicesAndWeights[i].jointWeight > 0.0f) {
|
||||||
const FbxVector4 localPosition =
|
const FbxVector4 localPosition =
|
||||||
skinning.GetJointInverseGlobalTransforms(indices[i]).MultNormalize(globalPosition);
|
skinning.GetJointInverseGlobalTransforms(indicesAndWeights[i].jointIndex).MultNormalize(globalPosition);
|
||||||
|
|
||||||
Vec3f& mins = rawSurface.jointGeometryMins[indices[i]];
|
Vec3f& mins = rawSurface.jointGeometryMins[indicesAndWeights[i].jointIndex];
|
||||||
mins[0] = std::min(mins[0], (float)localPosition[0]);
|
mins[0] = std::min(mins[0], (float)localPosition[0]);
|
||||||
mins[1] = std::min(mins[1], (float)localPosition[1]);
|
mins[1] = std::min(mins[1], (float)localPosition[1]);
|
||||||
mins[2] = std::min(mins[2], (float)localPosition[2]);
|
mins[2] = std::min(mins[2], (float)localPosition[2]);
|
||||||
|
|
||||||
Vec3f& maxs = rawSurface.jointGeometryMaxs[indices[i]];
|
Vec3f& maxs = rawSurface.jointGeometryMaxs[indicesAndWeights[i].jointIndex];
|
||||||
maxs[0] = std::max(maxs[0], (float)localPosition[0]);
|
maxs[0] = std::max(maxs[0], (float)localPosition[0]);
|
||||||
maxs[1] = std::max(maxs[1], (float)localPosition[1]);
|
maxs[1] = std::max(maxs[1], (float)localPosition[1]);
|
||||||
maxs[2] = std::max(maxs[2], (float)localPosition[2]);
|
maxs[2] = std::max(maxs[2], (float)localPosition[2]);
|
||||||
|
@ -179,17 +179,6 @@ static void ReadMesh(
|
||||||
if (uvLayer1.LayerPresent()) {
|
if (uvLayer1.LayerPresent()) {
|
||||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_UV1);
|
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_UV1);
|
||||||
}
|
}
|
||||||
if (skinning.IsSkinned()) {
|
|
||||||
FBX_ASSERT(skinning.MaxWeights() <= 8); // output only supports up to 8
|
|
||||||
|
|
||||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0);
|
|
||||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0);
|
|
||||||
if (skinning.MaxWeights() > 4) {
|
|
||||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1);
|
|
||||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
RawSurface& rawSurface = raw.GetSurface(rawSurfaceIndex);
|
RawSurface& rawSurface = raw.GetSurface(rawSurfaceIndex);
|
||||||
|
|
||||||
|
@ -370,10 +359,11 @@ static void ReadMesh(
|
||||||
vertex.uv0[1] = (float)fbxUV0[1];
|
vertex.uv0[1] = (float)fbxUV0[1];
|
||||||
vertex.uv1[0] = (float)fbxUV1[0];
|
vertex.uv1[0] = (float)fbxUV1[0];
|
||||||
vertex.uv1[1] = (float)fbxUV1[1];
|
vertex.uv1[1] = (float)fbxUV1[1];
|
||||||
vertex.jointIndices0 = skinning.GetVertexIndices(controlPointIndex, 0);
|
const std::vector<FbxVertexSkinningInfo> skinningInfo = skinning.GetVertexSkinningInfo(controlPointIndex);
|
||||||
vertex.jointWeights0 = skinning.GetVertexWeights(controlPointIndex, 0);
|
for (int skinningIndex = 0; skinningIndex < skinningInfo.size(); skinningIndex++) {
|
||||||
vertex.jointIndices1 = skinning.GetVertexIndices(controlPointIndex, 1);
|
const FbxVertexSkinningInfo& sourceSkinningInfo = skinningInfo[skinningIndex];
|
||||||
vertex.jointWeights1 = skinning.GetVertexWeights(controlPointIndex, 1);
|
vertex.skinningInfo.push_back(RawVertexSkinningInfo{ sourceSkinningInfo.jointId, sourceSkinningInfo.weight });
|
||||||
|
}
|
||||||
vertex.polarityUv0 = false;
|
vertex.polarityUv0 = false;
|
||||||
|
|
||||||
// flag this triangle as transparent if any of its corner vertices substantially deviates from
|
// flag this triangle as transparent if any of its corner vertices substantially deviates from
|
||||||
|
@ -418,14 +408,11 @@ static void ReadMesh(
|
||||||
|
|
||||||
if (skinning.IsSkinned()) {
|
if (skinning.IsSkinned()) {
|
||||||
FbxMatrix skinningMatrix = FbxMatrix() * 0.0;
|
FbxMatrix skinningMatrix = FbxMatrix() * 0.0;
|
||||||
for (int j = 0; j < 4; j++)
|
for (int j = 0; j < vertex.skinningInfo.size(); j++)
|
||||||
skinningMatrix += skinning.GetJointSkinningTransform(vertex.jointIndices0[j]) * vertex.jointWeights0[j];
|
skinningMatrix += skinning.GetJointSkinningTransform(vertex.skinningInfo[j].jointIndex) * vertex.skinningInfo[j].jointWeight;
|
||||||
for (int j = 0; j < 4; j++)
|
|
||||||
skinningMatrix += skinning.GetJointSkinningTransform(vertex.jointIndices1[j]) * vertex.jointWeights1[j];
|
|
||||||
|
|
||||||
const FbxVector4 globalPosition = skinningMatrix.MultNormalize(fbxPosition);
|
const FbxVector4 globalPosition = skinningMatrix.MultNormalize(fbxPosition);
|
||||||
calcMinMax(rawSurface, skinning, globalPosition, vertex.jointIndices0, vertex.jointWeights0);
|
calcMinMax(rawSurface, skinning, globalPosition, vertex.skinningInfo);
|
||||||
calcMinMax(rawSurface, skinning, globalPosition, vertex.jointIndices1, vertex.jointWeights1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,7 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, Fbx
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int controlPointCount = pMesh->GetControlPointsCount();
|
int controlPointCount = pMesh->GetControlPointsCount();
|
||||||
vertexJointIndices.resize(controlPointCount);
|
vertexSkinning.resize(controlPointCount);
|
||||||
vertexJointWeights.resize(controlPointCount);
|
|
||||||
|
|
||||||
for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) {
|
for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) {
|
||||||
FbxCluster* cluster = skin->GetCluster(clusterIndex);
|
FbxCluster* cluster = skin->GetCluster(clusterIndex);
|
||||||
|
@ -55,33 +54,18 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, Fbx
|
||||||
if (clusterIndices[i] < 0 || clusterIndices[i] >= controlPointCount) {
|
if (clusterIndices[i] < 0 || clusterIndices[i] >= controlPointCount) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (clusterWeights[i] <= 0.0 || vertexJointWeights[clusterIndices[i]].size() >= MAX_WEIGHTS) {
|
if (clusterWeights[i] <= 0.0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
vertexJointIndices[clusterIndices[i]].push_back(clusterIndex);
|
|
||||||
vertexJointWeights[clusterIndices[i]].push_back((float)clusterWeights[i]);
|
vertexSkinning[clusterIndices[i]].push_back(FbxVertexSkinningInfo{(int) clusterIndex, (float)clusterWeights[i]});
|
||||||
for (int j = vertexJointWeights[clusterIndices[i]].size() - 1; j > 0; j--) {
|
|
||||||
if (vertexJointWeights[clusterIndices[i]][j - 1] >=
|
|
||||||
vertexJointWeights[clusterIndices[i]][j]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
std::swap(
|
|
||||||
vertexJointIndices[clusterIndices[i]][j - 1],
|
|
||||||
vertexJointIndices[clusterIndices[i]][j]);
|
|
||||||
std::swap(
|
|
||||||
vertexJointWeights[clusterIndices[i]][j - 1],
|
|
||||||
vertexJointWeights[clusterIndices[i]][j]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < controlPointCount; i++) {
|
|
||||||
float weightSum = 0.0;
|
for (int i = 0; i < vertexSkinning.size(); i++)
|
||||||
for (int w = 0; w < vertexJointWeights[i].size(); ++w)
|
maxBoneInfluences = std::max((int) vertexSkinning[i].size(), maxBoneInfluences);
|
||||||
weightSum += vertexJointWeights[i][w];
|
|
||||||
float weightSumRcp = 1.0 / weightSum;
|
|
||||||
for (int w = 0; w < vertexJointWeights[i].size(); ++w)
|
|
||||||
vertexJointWeights[i][w] *= weightSumRcp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,19 +19,21 @@
|
||||||
|
|
||||||
#include "FBX2glTF.h"
|
#include "FBX2glTF.h"
|
||||||
|
|
||||||
|
struct FbxVertexSkinningInfo {
|
||||||
|
int jointId;
|
||||||
|
float weight;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class FbxSkinningAccess {
|
class FbxSkinningAccess {
|
||||||
public:
|
public:
|
||||||
static const int MAX_WEIGHTS = 8;
|
|
||||||
|
|
||||||
FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, FbxNode* pNode);
|
FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, FbxNode* pNode);
|
||||||
|
|
||||||
bool IsSkinned() const {
|
bool IsSkinned() const {
|
||||||
return (vertexJointWeights.size() > 0);
|
return (vertexSkinning.size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MaxWeights() const {
|
|
||||||
return MAX_WEIGHTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetNodeCount() const {
|
int GetNodeCount() const {
|
||||||
return (int)jointNodes.size();
|
return (int)jointNodes.size();
|
||||||
|
@ -61,32 +63,18 @@ class FbxSkinningAccess {
|
||||||
const FbxAMatrix& GetInverseBindMatrix(const int jointIndex) const {
|
const FbxAMatrix& GetInverseBindMatrix(const int jointIndex) const {
|
||||||
return inverseBindMatrices[jointIndex];
|
return inverseBindMatrices[jointIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Vec4i GetVertexIndices(const int controlPointIndex, const int subset) const {
|
|
||||||
if (vertexJointIndices.empty())
|
|
||||||
return Vec4i(0, 0, 0, 0);
|
|
||||||
Vec4i indices(0, 0, 0, 0);
|
|
||||||
for (int k = subset * 4; k < subset * 4 + 4 && k < vertexJointIndices[controlPointIndex].size(); k++)
|
|
||||||
indices[k - subset * 4] = vertexJointIndices[controlPointIndex][k];
|
|
||||||
return indices;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vec4f GetVertexWeights(const int controlPointIndex, const int subset) const {
|
const std::vector<FbxVertexSkinningInfo> GetVertexSkinningInfo(const int controlPointIndex) const {
|
||||||
if (vertexJointWeights.empty())
|
return vertexSkinning[controlPointIndex];
|
||||||
return Vec4f(0.0f);
|
|
||||||
Vec4f weights(0.0f);
|
|
||||||
for (int k = subset * 4; k < subset * 4 + 4 && k < vertexJointWeights[controlPointIndex].size(); k++)
|
|
||||||
weights[k - subset * 4] = vertexJointWeights[controlPointIndex][k];
|
|
||||||
return weights;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int rootIndex;
|
int rootIndex;
|
||||||
|
int maxBoneInfluences;
|
||||||
std::vector<long> jointIds;
|
std::vector<long> jointIds;
|
||||||
std::vector<FbxNode*> jointNodes;
|
std::vector<FbxNode*> jointNodes;
|
||||||
std::vector<FbxMatrix> jointSkinningTransforms;
|
std::vector<FbxMatrix> jointSkinningTransforms;
|
||||||
std::vector<FbxMatrix> jointInverseGlobalTransforms;
|
std::vector<FbxMatrix> jointInverseGlobalTransforms;
|
||||||
std::vector<FbxAMatrix> inverseBindMatrices;
|
std::vector<FbxAMatrix> inverseBindMatrices;
|
||||||
std::vector<std::vector<uint16_t>> vertexJointIndices;
|
std::vector<std::vector<FbxVertexSkinningInfo>> vertexSkinning;
|
||||||
std::vector<std::vector<float>> vertexJointWeights;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -123,6 +123,38 @@ class GltfModel {
|
||||||
return accessor;
|
return accessor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::shared_ptr<AccessorData> AddArrayAttributeToPrimitive(
|
||||||
|
BufferData& buffer,
|
||||||
|
const RawModel& surfaceModel,
|
||||||
|
PrimitiveData& primitive,
|
||||||
|
const AttributeDefinition<T>& attrDef) {
|
||||||
|
// copy attribute data into vector
|
||||||
|
std::vector<std::vector<T>> attribArr;
|
||||||
|
surfaceModel.GetAttributeArray<T>(attribArr, attrDef.rawAttributeIx);
|
||||||
|
|
||||||
|
const AttributeDefinition<Vec4f> ATTR_WEIGHTS(
|
||||||
|
"WEIGHTS_0",
|
||||||
|
&RawVertex::jointWeights,
|
||||||
|
attrDef.glType,
|
||||||
|
attrDef.dracoAttribute,
|
||||||
|
draco::DT_FLOAT32);
|
||||||
|
|
||||||
|
std::shared_ptr<AccessorData> accessor;
|
||||||
|
if (attrDef.dracoComponentType != draco::DT_INVALID && primitive.dracoMesh != nullptr) {
|
||||||
|
primitive.AddDracoAttrib(attrDef, attribArr);
|
||||||
|
|
||||||
|
accessor = accessors.hold(new AccessorData(attrDef.glType));
|
||||||
|
accessor->count = attribArr.size();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER);
|
||||||
|
accessor = AddAccessorWithView(*bufferView, attrDef.glType, attribArr, std::string(""));
|
||||||
|
}
|
||||||
|
primitive.AddAttrib(attrDef.gltfName, *accessor);
|
||||||
|
return accessor;
|
||||||
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void serializeHolder(json& glTFJson, std::string key, const Holder<T> holder) {
|
void serializeHolder(json& glTFJson, std::string key, const Holder<T> holder) {
|
||||||
if (!holder.ptrs.empty()) {
|
if (!holder.ptrs.empty()) {
|
||||||
|
|
|
@ -550,23 +550,59 @@ ModelData* Raw2Gltf(
|
||||||
draco::DT_FLOAT32);
|
draco::DT_FLOAT32);
|
||||||
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1) != 0) {
|
||||||
const AttributeDefinition<Vec4i> ATTR_JOINTS(
|
const AttributeDefinition<Vec4i> ATTR_JOINTS(
|
||||||
"JOINTS_1",
|
"JOINTS_1",
|
||||||
&RawVertex::jointIndices1,
|
&RawVertex::jointIndices1,
|
||||||
GLT_VEC4I,
|
GLT_VEC4I,
|
||||||
draco::GeometryAttribute::GENERIC,
|
draco::GeometryAttribute::GENERIC,
|
||||||
draco::DT_UINT16);
|
draco::DT_UINT16);
|
||||||
gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS);
|
gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS);
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1) != 0) {
|
||||||
const AttributeDefinition<Vec4f> ATTR_WEIGHTS(
|
const AttributeDefinition<Vec4f> ATTR_WEIGHTS(
|
||||||
"WEIGHTS_1",
|
"WEIGHTS_1",
|
||||||
&RawVertex::jointWeights1,
|
&RawVertex::jointWeights1,
|
||||||
GLT_VEC4F,
|
GLT_VEC4F,
|
||||||
draco::GeometryAttribute::GENERIC,
|
draco::GeometryAttribute::GENERIC,
|
||||||
draco::DT_FLOAT32);
|
draco::DT_FLOAT32);
|
||||||
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
||||||
|
}
|
||||||
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES2) != 0) {
|
||||||
|
const AttributeDefinition<Vec4i> ATTR_JOINTS(
|
||||||
|
"JOINTS_0",
|
||||||
|
&RawVertex::jointIndices2,
|
||||||
|
GLT_VEC4I,
|
||||||
|
draco::GeometryAttribute::GENERIC,
|
||||||
|
draco::DT_UINT16);
|
||||||
|
gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS);
|
||||||
|
}
|
||||||
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS2) != 0) {
|
||||||
|
const AttributeDefinition<Vec4f> ATTR_WEIGHTS(
|
||||||
|
"WEIGHTS_0",
|
||||||
|
&RawVertex::jointWeights2,
|
||||||
|
GLT_VEC4F,
|
||||||
|
draco::GeometryAttribute::GENERIC,
|
||||||
|
draco::DT_FLOAT32);
|
||||||
|
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
||||||
|
}
|
||||||
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES3) != 0) {
|
||||||
|
const AttributeDefinition<Vec4i> ATTR_JOINTS(
|
||||||
|
"JOINTS_0",
|
||||||
|
&RawVertex::jointIndices3,
|
||||||
|
GLT_VEC4I,
|
||||||
|
draco::GeometryAttribute::GENERIC,
|
||||||
|
draco::DT_UINT16);
|
||||||
|
gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS);
|
||||||
|
}
|
||||||
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS3) != 0) {
|
||||||
|
const AttributeDefinition<Vec4f> ATTR_WEIGHTS(
|
||||||
|
"WEIGHTS_0",
|
||||||
|
&RawVertex::jointWeights3,
|
||||||
|
GLT_VEC4F,
|
||||||
|
draco::GeometryAttribute::GENERIC,
|
||||||
|
draco::DT_FLOAT32);
|
||||||
|
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// each channel present in the mesh always ends up a target in the primitive
|
// each channel present in the mesh always ends up a target in the primitive
|
||||||
|
|
|
@ -56,22 +56,22 @@ size_t RawVertex::Difference(const RawVertex& other) const {
|
||||||
attributes |= RAW_VERTEX_ATTRIBUTE_UV1;
|
attributes |= RAW_VERTEX_ATTRIBUTE_UV1;
|
||||||
}
|
}
|
||||||
// Always need both or neither.
|
// Always need both or neither.
|
||||||
if (jointIndices0 != other.jointIndices0) {
|
if (jointIndices0 != other.jointIndices0 || jointWeights0 != other.jointWeights0) {
|
||||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0;
|
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0;
|
||||||
}
|
}
|
||||||
if (jointWeights0 != other.jointWeights0) {
|
if (jointIndices1 != other.jointIndices1 || jointWeights1 != other.jointWeights1) {
|
||||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0;
|
|
||||||
}
|
|
||||||
if (jointIndices1 != other.jointIndices1) {
|
|
||||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1;
|
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1;
|
||||||
}
|
}
|
||||||
if (jointWeights1 != other.jointWeights1) {
|
if (jointIndices2 != other.jointIndices2 || jointWeights2 != other.jointWeights2) {
|
||||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1;
|
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES2 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS2;
|
||||||
|
}
|
||||||
|
if (jointIndices3 != other.jointIndices3 || jointWeights3 != other.jointWeights3) {
|
||||||
|
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES3 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS3;
|
||||||
}
|
}
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
RawModel::RawModel() : vertexAttributes(0) {}
|
RawModel::RawModel() : vertexAttributes(0){}
|
||||||
|
|
||||||
void RawModel::AddVertexAttribute(const RawVertexAttribute attrib) {
|
void RawModel::AddVertexAttribute(const RawVertexAttribute attrib) {
|
||||||
vertexAttributes |= attrib;
|
vertexAttributes |= attrib;
|
||||||
|
@ -334,7 +334,7 @@ int RawModel::AddNode(const long id, const char* name, const long parentId) {
|
||||||
return (int)nodes.size() - 1;
|
return (int)nodes.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawModel::Condense() {
|
void RawModel::Condense(const int maxSkinningWeights, const bool normalizeWeights) {
|
||||||
// Only keep surfaces that are referenced by one or more triangles.
|
// Only keep surfaces that are referenced by one or more triangles.
|
||||||
{
|
{
|
||||||
std::vector<RawSurface> oldSurfaces = surfaces;
|
std::vector<RawSurface> oldSurfaces = surfaces;
|
||||||
|
@ -404,6 +404,81 @@ void RawModel::Condense() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int globalMaxWeights = 0;
|
||||||
|
for (auto& vertex: vertices) {
|
||||||
|
|
||||||
|
// Sort from largest to smallest weight.
|
||||||
|
std::sort(vertex.skinningInfo.begin(), vertex.skinningInfo.end(), std::greater<RawVertexSkinningInfo>());
|
||||||
|
|
||||||
|
// Reduce to fit the requirements.
|
||||||
|
if (maxSkinningWeights < vertex.skinningInfo.size())
|
||||||
|
vertex.skinningInfo.resize(maxSkinningWeights);
|
||||||
|
globalMaxWeights = std::max(globalMaxWeights, (int) vertex.skinningInfo.size());
|
||||||
|
|
||||||
|
// Normalize weights if requested.
|
||||||
|
if (normalizeWeights) {
|
||||||
|
float weightSum = 0;
|
||||||
|
for (auto& jointWeight : vertex.skinningInfo)
|
||||||
|
weightSum += jointWeight.jointWeight;
|
||||||
|
const float weightSumRcp = 1.0 / weightSum;
|
||||||
|
for (auto& jointWeight : vertex.skinningInfo)
|
||||||
|
jointWeight.jointWeight *= weightSumRcp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globalMaxWeights > 0) {
|
||||||
|
AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0);
|
||||||
|
AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0);
|
||||||
|
}
|
||||||
|
if (globalMaxWeights > 1) {
|
||||||
|
AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1);
|
||||||
|
AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1);
|
||||||
|
}
|
||||||
|
if (globalMaxWeights > 2) {
|
||||||
|
AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_INDICES2);
|
||||||
|
AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS2);
|
||||||
|
}
|
||||||
|
if (globalMaxWeights > 3) {
|
||||||
|
AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_INDICES3);
|
||||||
|
AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS3);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(globalMaxWeights <= RawModel::MAX_SUPPORTED_WEIGHTS);
|
||||||
|
// Copy to gltf friendly structure
|
||||||
|
for (auto& vertex : vertices) {
|
||||||
|
for (int i = 0; i < globalMaxWeights; i += 4) { // Ensure all vertices have the same number of streams
|
||||||
|
Vec4f weights{0.0};
|
||||||
|
Vec4i jointIds{0,0,0,0};
|
||||||
|
for (int j = i; j < i + 4 && j < vertex.skinningInfo.size(); j++) {
|
||||||
|
weights[j - i] = vertex.skinningInfo[j].jointWeight;
|
||||||
|
jointIds[j - i] = vertex.skinningInfo[j].jointIndex;
|
||||||
|
}
|
||||||
|
const int vertexStream = i / 4;
|
||||||
|
switch (vertexStream) {
|
||||||
|
case 0:
|
||||||
|
vertex.jointIndices0 = jointIds;
|
||||||
|
vertex.jointWeights0 = weights;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
vertex.jointIndices1 = jointIds;
|
||||||
|
vertex.jointWeights1 = weights;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
vertex.jointIndices2 = jointIds;
|
||||||
|
vertex.jointWeights2 = weights;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
vertex.jointIndices3 = jointIds;
|
||||||
|
vertex.jointWeights3 = weights;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawModel::TransformGeometry(ComputeNormalsOption normals) {
|
void RawModel::TransformGeometry(ComputeNormalsOption normals) {
|
||||||
|
@ -580,7 +655,8 @@ void RawModel::CreateMaterialModels(
|
||||||
if (keepAttribs != -1) {
|
if (keepAttribs != -1) {
|
||||||
int keep = keepAttribs;
|
int keep = keepAttribs;
|
||||||
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
|
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
|
||||||
keep |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0 | RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1;
|
keep |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0 | RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1 |
|
||||||
|
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES2 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS2 | RAW_VERTEX_ATTRIBUTE_JOINT_INDICES3 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS3;
|
||||||
}
|
}
|
||||||
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_AUTO) != 0) {
|
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_AUTO) != 0) {
|
||||||
keep |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
keep |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
||||||
|
@ -633,6 +709,18 @@ void RawModel::CreateMaterialModels(
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1) == 0) {
|
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1) == 0) {
|
||||||
vertex.jointWeights1 = defaultVertex.jointWeights1;
|
vertex.jointWeights1 = defaultVertex.jointWeights1;
|
||||||
}
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES2) == 0) {
|
||||||
|
vertex.jointIndices2 = defaultVertex.jointIndices2;
|
||||||
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS2) == 0) {
|
||||||
|
vertex.jointWeights2 = defaultVertex.jointWeights2;
|
||||||
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES3) == 0) {
|
||||||
|
vertex.jointIndices3 = defaultVertex.jointIndices3;
|
||||||
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS3) == 0) {
|
||||||
|
vertex.jointWeights3 = defaultVertex.jointWeights3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verts[j] = model->AddVertex(vertex);
|
verts[j] = model->AddVertex(vertex);
|
||||||
|
|
|
@ -27,6 +27,10 @@ enum RawVertexAttribute {
|
||||||
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0 = 1 << 8,
|
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0 = 1 << 8,
|
||||||
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 = 1 << 9,
|
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 = 1 << 9,
|
||||||
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1 = 1 << 10,
|
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1 = 1 << 10,
|
||||||
|
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES2 = 1 << 11,
|
||||||
|
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS2 = 1 << 12,
|
||||||
|
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES3 = 1 << 13,
|
||||||
|
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS3 = 1 << 14,
|
||||||
|
|
||||||
RAW_VERTEX_ATTRIBUTE_AUTO = 1 << 31
|
RAW_VERTEX_ATTRIBUTE_AUTO = 1 << 31
|
||||||
};
|
};
|
||||||
|
@ -41,6 +45,16 @@ struct RawBlendVertex {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RawVertexSkinningInfo
|
||||||
|
{
|
||||||
|
int jointIndex;
|
||||||
|
float jointWeight;
|
||||||
|
|
||||||
|
bool operator>(const RawVertexSkinningInfo& rjw) const {
|
||||||
|
return jointWeight > rjw.jointWeight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct RawVertex {
|
struct RawVertex {
|
||||||
RawVertex() : polarityUv0(false), pad1(false), pad2(false), pad3(false) {}
|
RawVertex() : polarityUv0(false), pad1(false), pad2(false), pad3(false) {}
|
||||||
|
|
||||||
|
@ -51,10 +65,16 @@ struct RawVertex {
|
||||||
Vec4f color{0.0f};
|
Vec4f color{0.0f};
|
||||||
Vec2f uv0{0.0f};
|
Vec2f uv0{0.0f};
|
||||||
Vec2f uv1{0.0f};
|
Vec2f uv1{0.0f};
|
||||||
Vec4i jointIndices0{0,0,0,0};
|
Vec4i jointIndices0{0,0,0,0};
|
||||||
Vec4i jointIndices1{0,0,0,0};
|
Vec4i jointIndices1{0,0,0,0};
|
||||||
Vec4f jointWeights0{0.0f};
|
Vec4i jointIndices2{0,0,0,0};
|
||||||
|
Vec4i jointIndices3{0,0,0,0};
|
||||||
|
Vec4f jointWeights0{0.0f};
|
||||||
Vec4f jointWeights1{0.0f};
|
Vec4f jointWeights1{0.0f};
|
||||||
|
Vec4f jointWeights2{0.0f};
|
||||||
|
Vec4f jointWeights3{0.0f};
|
||||||
|
|
||||||
|
std::vector<RawVertexSkinningInfo> skinningInfo;
|
||||||
// end of members that directly correspond to vertex attributes
|
// end of members that directly correspond to vertex attributes
|
||||||
|
|
||||||
// if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh;
|
// if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh;
|
||||||
|
@ -361,6 +381,8 @@ struct RawNode {
|
||||||
|
|
||||||
class RawModel {
|
class RawModel {
|
||||||
public:
|
public:
|
||||||
|
static const int MAX_SUPPORTED_WEIGHTS = 16;
|
||||||
|
|
||||||
RawModel();
|
RawModel();
|
||||||
|
|
||||||
// Add geometry.
|
// Add geometry.
|
||||||
|
@ -421,7 +443,7 @@ class RawModel {
|
||||||
|
|
||||||
// Remove unused vertices, textures or materials after removing vertex attributes, textures,
|
// Remove unused vertices, textures or materials after removing vertex attributes, textures,
|
||||||
// materials or surfaces.
|
// materials or surfaces.
|
||||||
void Condense();
|
void Condense(const int maxSkinningWeights, const bool normalizeWeights);
|
||||||
|
|
||||||
void TransformGeometry(ComputeNormalsOption);
|
void TransformGeometry(ComputeNormalsOption);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue