Skip to content

Commit

Permalink
Merge pull request #22 from AndreaCatania/fbx
Browse files Browse the repository at this point in the history
Truncate and normalize the weights
  • Loading branch information
RevoluPowered authored Jul 14, 2020
2 parents fa35649 + 19c839c commit 64fdf8c
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 37 deletions.
103 changes: 73 additions & 30 deletions modules/fbx_importer/data/fbx_mesh_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,6 @@
#include "thirdparty/misc/triangulator.h"
#include <algorithm>

void VertexMapping::get_validated_bone_weight_info(Vector<int> &out_bones, Vector<real_t> &out_weights, int max_bones) const {
ERR_FAIL_COND_MSG(bones.size() != weights.size(), "[doc] Error unable to handle incorrect bone weight info.");
ERR_FAIL_COND_MSG(out_bones.size() > 0 && out_weights.size() > 0, "[doc] Error input must be empty before using this function, accidental re-use?");
for (int idx = 0; idx < max_bones; idx += 1) {
real_t weight = 0.0;
Ref<FBXBone> bone;
if (idx < bones.size()) {
weight = weights[idx];
bone = bones[idx];
}
if (bone.is_valid()) {
out_weights.push_back(weight);
out_bones.push_back(bone->godot_bone_id);
// print_verbose("[" + itos(idx) + "] valid bone weight: " + itos(bone->godot_bone_id) + " weight: " + rtos(weight));
} else {
out_weights.push_back(0.0);
out_bones.push_back(0);
}
}
}

template <class T>
T collect_first(const Vector<VertexData<T> > *p_data, T p_fall_back) {
if (p_data->empty()) {
Expand Down Expand Up @@ -166,6 +145,8 @@ MeshInstance *FBXMeshData::create_fbx_mesh(const ImportState &state, const Assim
// TODO please add skinning.
//mesh_id = mesh_geometry->ID();

sanitize_vertex_weights();

// Re organize polygon vertices to to correctly take into account strange
// UVs.
reorganize_vertices(
Expand Down Expand Up @@ -364,6 +345,70 @@ MeshInstance *FBXMeshData::create_fbx_mesh(const ImportState &state, const Assim
return godot_mesh;
}

void FBXMeshData::sanitize_vertex_weights() {
const int max_bones = VS::ARRAY_WEIGHTS_SIZE;

for (const Vertex *v = vertex_weights.next(nullptr); v != nullptr; v = vertex_weights.next(v)) {
VertexMapping *vm = vertex_weights.getptr(*v);
ERR_CONTINUE(vm->bones.size() != vm->weights.size()); // No message, already checked.
ERR_CONTINUE(vm->bones_ref.size() != vm->weights.size()); // No message, already checked.

const int initial_size = vm->weights.size();

{
// Init bone id
int *bones_ptr = vm->bones.ptrw();
Ref<FBXBone> *bones_ref_ptr = vm->bones_ref.ptrw();

for (int i = 0; i < vm->weights.size(); i += 1) {
// At this point this is not possible because the skeleton is already initialized.
CRASH_COND(bones_ref_ptr[i]->godot_bone_id == -2);
bones_ptr[i] = bones_ref_ptr[i]->godot_bone_id;
}

// From this point on the data is no more valid.
vm->bones_ref.clear();
}

{
// Sort
real_t *weights_ptr = vm->weights.ptrw();
int *bones_ptr = vm->bones.ptrw();
for (int i = 0; i < vm->weights.size(); i += 1) {
for (int x = i + 1; x < vm->weights.size(); x += 1) {
if (weights_ptr[i] < weights_ptr[x]) {
SWAP(weights_ptr[i], weights_ptr[x]);
SWAP(bones_ptr[i], bones_ptr[x]);
}
}
}
}

{
// Resize
vm->weights.resize(max_bones);
vm->bones.resize(max_bones);
real_t *weights_ptr = vm->weights.ptrw();
int *bones_ptr = vm->bones.ptrw();
for (int i = initial_size; i < max_bones; i += 1) {
weights_ptr[i] = 0.0;
bones_ptr[i] = 0;
}

// Normalize
real_t sum = 0.0;
for (int i = 0; i < max_bones; i += 1) {
sum += weights_ptr[i];
}
if (sum > 0.0) {
for (int i = 0; i < vm->weights.size(); i += 1) {
weights_ptr[i] = weights_ptr[i] / sum;
}
}
}
}
}

void FBXMeshData::reorganize_vertices(
std::vector<int> &r_polygon_indices,
std::vector<Vector3> &r_vertices,
Expand Down Expand Up @@ -716,27 +761,25 @@ void FBXMeshData::gen_weight_info(Ref<SurfaceTool> st, Vertex vertex_id) const {
return;
}

Vector<real_t> valid_weights;
Vector<int> valid_bone_ids;

// Godot only supports 4.
const int max_bones = VS::ARRAY_WEIGHTS_SIZE;

if (vertex_weights.has(vertex_id)) {
// Let's extract the weight info.
const VertexMapping *vm = vertex_weights.getptr(vertex_id);
vm->get_validated_bone_weight_info(valid_bone_ids, valid_weights, max_bones);
st->add_weights(vm->weights);
st->add_bones(vm->bones);
} else {
// This vertex doesn't have any bone info, while the model is using the
// bones.
const int max_bones = VS::ARRAY_WEIGHTS_SIZE;
Vector<real_t> valid_weights;
Vector<int> valid_bone_ids;
for (int i = 0; i < max_bones; i += 1) {
valid_weights.push_back(0.0f);
valid_bone_ids.push_back(0);
}
st->add_weights(valid_weights);
st->add_bones(valid_bone_ids);
}

st->add_weights(valid_weights);
st->add_bones(valid_bone_ids);
print_verbose("[doc] Triangle added weights to mesh for bones");
}

Expand Down
12 changes: 7 additions & 5 deletions modules/fbx_importer/data/fbx_mesh_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,13 @@ struct FBXSplitBySurfaceVertexMapping {
}
};

// TODO reneme to VertexWeightMapping
struct VertexMapping {
Vector<real_t> weights;
Vector<Ref<FBXBone> > bones;

/// Will only add a vertex weight if it has been validated that it exists in
/// godot.
void get_validated_bone_weight_info(Vector<int> &out_bones, Vector<float> &out_weights, int p_max_bones) const;
Vector<int> bones;
// This extra vector is used because the bone id is computed in a second step.
// TODO Get rid of this extra step is a good idea.
Vector<Ref<FBXBone> > bones_ref;
};

template <class T>
Expand Down Expand Up @@ -238,6 +238,8 @@ struct FBXMeshData : Reference {
MeshInstance *godot_mesh_instance = nullptr;

private:
void sanitize_vertex_weights();

/// Make sure to reorganize the vertices so that the correct UV is taken.
/// This step is needed because differently from the normal, that can be
/// combined, the UV may need its own triangle because sometimes they have
Expand Down
5 changes: 3 additions & 2 deletions modules/fbx_importer/editor_scene_importer_fbx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1380,14 +1380,15 @@ void EditorSceneImporterFBX::CacheNodeInformation(Ref<FBXBone> p_parent_bone,

for (size_t idx = 0; idx < indexes.size(); idx++) {

size_t vertex_index = indexes[idx];
const size_t vertex_index = indexes[idx];
//print_verbose("vertex index: " + itos(vertex_index));

const real_t influence_weight = weights[idx];

VertexMapping &vm = mesh_vertex_data->vertex_weights[vertex_index];
vm.weights.push_back(influence_weight);
vm.bones.push_back(bone_element);
vm.bones.push_back(0);
vm.bones_ref.push_back(bone_element);
//print_verbose("Weight debug: " + rtos(influence_weight) + " bone id:" + bone_element->bone_name);
}

Expand Down

0 comments on commit 64fdf8c

Please sign in to comment.