Expose gltf2 eight weights.

This commit is contained in:
K. S. Ernest (iFire) Lee 2020-12-28 11:51:48 -08:00
parent e11be74856
commit dff1d8d7b0
3 changed files with 153 additions and 14 deletions

View File

@ -29,6 +29,9 @@
/*************************************************************************/
#include "gltf_document.h"
#include "core/error/error_list.h"
#include "core/error/error_macros.h"
#include "core/variant/variant.h"
#include "gltf_accessor.h"
#include "gltf_animation.h"
#include "gltf_camera.h"
@ -2199,33 +2202,81 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
}
}
{
Array a = array[Mesh::ARRAY_BONES];
if (a.size()) {
const int ret_size = a.size() / 4;
const Array &a = array[Mesh::ARRAY_BONES];
const Vector<Vector3> &vertex_array = array[Mesh::ARRAY_VERTEX];
if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) {
const int ret_size = a.size() / JOINT_GROUP_SIZE;
Vector<Color> attribs;
attribs.resize(ret_size);
{
for (int array_i = 0; array_i < attribs.size(); array_i++) {
int32_t joint_0 = a[(array_i * 4) + 0];
int32_t joint_1 = a[(array_i * 4) + 1];
int32_t joint_2 = a[(array_i * 4) + 2];
int32_t joint_3 = a[(array_i * 4) + 3];
int32_t joint_0 = a[(array_i * JOINT_GROUP_SIZE) + 0];
int32_t joint_1 = a[(array_i * JOINT_GROUP_SIZE) + 1];
int32_t joint_2 = a[(array_i * JOINT_GROUP_SIZE) + 2];
int32_t joint_3 = a[(array_i * JOINT_GROUP_SIZE) + 3];
attribs.write[array_i] = Color(joint_0, joint_1, joint_2, joint_3);
}
}
attributes["JOINTS_0"] = _encode_accessor_as_joints(state, attribs, true);
} else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) {
int32_t vertex_count = vertex_array.size();
Vector<Color> joints_0;
joints_0.resize(vertex_count);
Vector<Color> joints_1;
joints_1.resize(vertex_count);
int32_t weights_8_count = JOINT_GROUP_SIZE * 2;
for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
Color joint_0;
joint_0.r = a[vertex_i * weights_8_count + 0];
joint_0.g = a[vertex_i * weights_8_count + 1];
joint_0.b = a[vertex_i * weights_8_count + 2];
joint_0.a = a[vertex_i * weights_8_count + 3];
joints_0.write[vertex_i] = joint_0;
Color joint_1;
joint_1.r = a[vertex_i * weights_8_count + 4];
joint_1.g = a[vertex_i * weights_8_count + 5];
joint_1.b = a[vertex_i * weights_8_count + 6];
joint_1.a = a[vertex_i * weights_8_count + 7];
joints_1.write[vertex_i] = joint_1;
}
attributes["JOINTS_0"] = _encode_accessor_as_joints(state, joints_0, true);
attributes["JOINTS_1"] = _encode_accessor_as_joints(state, joints_1, true);
}
}
{
Array a = array[Mesh::ARRAY_WEIGHTS];
if (a.size()) {
const int ret_size = a.size() / 4;
const Array &a = array[Mesh::ARRAY_WEIGHTS];
const Vector<Vector3> &vertex_array = array[Mesh::ARRAY_VERTEX];
if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) {
const int ret_size = a.size() / JOINT_GROUP_SIZE;
Vector<Color> attribs;
attribs.resize(ret_size);
for (int i = 0; i < ret_size; i++) {
attribs.write[i] = Color(a[(i * 4) + 0], a[(i * 4) + 1], a[(i * 4) + 2], a[(i * 4) + 3]);
attribs.write[i] = Color(a[(i * JOINT_GROUP_SIZE) + 0], a[(i * JOINT_GROUP_SIZE) + 1], a[(i * JOINT_GROUP_SIZE) + 2], a[(i * JOINT_GROUP_SIZE) + 3]);
}
attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, attribs, true);
} else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) {
int32_t vertex_count = vertex_array.size();
Vector<Color> weights_0;
weights_0.resize(vertex_count);
Vector<Color> weights_1;
weights_1.resize(vertex_count);
int32_t weights_8_count = JOINT_GROUP_SIZE * 2;
for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
Color weight_0;
weight_0.r = a[vertex_i * weights_8_count + 0];
weight_0.g = a[vertex_i * weights_8_count + 1];
weight_0.b = a[vertex_i * weights_8_count + 2];
weight_0.a = a[vertex_i * weights_8_count + 3];
weights_0.write[vertex_i] = weight_0;
Color weight_1;
weight_1.r = a[vertex_i * weights_8_count + 4];
weight_1.g = a[vertex_i * weights_8_count + 5];
weight_1.b = a[vertex_i * weights_8_count + 6];
weight_1.a = a[vertex_i * weights_8_count + 7];
weights_1.write[vertex_i] = weight_1;
}
attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, weights_0, true);
attributes["WEIGHTS_1"] = _encode_accessor_as_weights(state, weights_1, true);
}
}
{
@ -2428,10 +2479,29 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true);
has_vertex_color = true;
}
if (a.has("JOINTS_0")) {
if (a.has("JOINTS_0") && !a.has("JOINTS_1")) {
array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true);
} else if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
PackedInt32Array joints_0 = _decode_accessor_as_ints(state, a["JOINTS_0"], true);
PackedInt32Array joints_1 = _decode_accessor_as_ints(state, a["JOINTS_1"], true);
ERR_FAIL_COND_V(joints_0.size() != joints_0.size(), ERR_INVALID_DATA);
int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
int32_t vertex_count = joints_0.size() / JOINT_GROUP_SIZE;
Vector<int> joints;
joints.resize(vertex_count * weight_8_count);
for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
joints.write[vertex_i * weight_8_count + 0] = joints_0[vertex_i * JOINT_GROUP_SIZE + 0];
joints.write[vertex_i * weight_8_count + 1] = joints_0[vertex_i * JOINT_GROUP_SIZE + 1];
joints.write[vertex_i * weight_8_count + 2] = joints_0[vertex_i * JOINT_GROUP_SIZE + 2];
joints.write[vertex_i * weight_8_count + 3] = joints_0[vertex_i * JOINT_GROUP_SIZE + 3];
joints.write[vertex_i * weight_8_count + 4] = joints_1[vertex_i * JOINT_GROUP_SIZE + 0];
joints.write[vertex_i * weight_8_count + 5] = joints_1[vertex_i * JOINT_GROUP_SIZE + 1];
joints.write[vertex_i * weight_8_count + 6] = joints_1[vertex_i * JOINT_GROUP_SIZE + 2];
joints.write[vertex_i * weight_8_count + 7] = joints_1[vertex_i * JOINT_GROUP_SIZE + 3];
}
array[Mesh::ARRAY_BONES] = joints;
}
if (a.has("WEIGHTS_0")) {
if (a.has("WEIGHTS_0") && !a.has("WEIGHTS_1")) {
Vector<float> weights = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true);
{ //gltf does not seem to normalize the weights for some reason..
int wc = weights.size();
@ -2452,6 +2522,51 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
}
array[Mesh::ARRAY_WEIGHTS] = weights;
} else if (a.has("WEIGHTS_0") && a.has("WEIGHTS_1")) {
Vector<float> weights_0 = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true);
Vector<float> weights_1 = _decode_accessor_as_floats(state, a["WEIGHTS_1"], true);
Vector<float> weights;
ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA);
int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
int32_t vertex_count = weights_0.size() / JOINT_GROUP_SIZE;
weights.resize(vertex_count * weight_8_count);
for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
weights.write[vertex_i * weight_8_count + 0] = weights_0[vertex_i * JOINT_GROUP_SIZE + 0];
weights.write[vertex_i * weight_8_count + 1] = weights_0[vertex_i * JOINT_GROUP_SIZE + 1];
weights.write[vertex_i * weight_8_count + 2] = weights_0[vertex_i * JOINT_GROUP_SIZE + 2];
weights.write[vertex_i * weight_8_count + 3] = weights_0[vertex_i * JOINT_GROUP_SIZE + 3];
weights.write[vertex_i * weight_8_count + 4] = weights_1[vertex_i * JOINT_GROUP_SIZE + 0];
weights.write[vertex_i * weight_8_count + 5] = weights_1[vertex_i * JOINT_GROUP_SIZE + 1];
weights.write[vertex_i * weight_8_count + 6] = weights_1[vertex_i * JOINT_GROUP_SIZE + 2];
weights.write[vertex_i * weight_8_count + 7] = weights_1[vertex_i * JOINT_GROUP_SIZE + 3];
}
{ //gltf does not seem to normalize the weights for some reason..
int wc = weights.size();
float *w = weights.ptrw();
for (int k = 0; k < wc; k += weight_8_count) {
float total = 0.0;
total += w[k + 0];
total += w[k + 1];
total += w[k + 2];
total += w[k + 3];
total += w[k + 4];
total += w[k + 5];
total += w[k + 6];
total += w[k + 7];
if (total > 0.0) {
w[k + 0] /= total;
w[k + 1] /= total;
w[k + 2] /= total;
w[k + 3] /= total;
w[k + 4] /= total;
w[k + 5] /= total;
w[k + 6] /= total;
w[k + 7] /= total;
}
}
}
array[Mesh::ARRAY_WEIGHTS] = weights;
}
if (p.has("indices")) {
@ -2492,6 +2607,9 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
//must generate mikktspace tangents.. ergh..
Ref<SurfaceTool> st;
st.instance();
if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
}
st->create_from_triangle_arrays(array);
st->generate_tangents();
array = st->commit_to_arrays();
@ -2608,6 +2726,9 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
if (generate_tangents) {
Ref<SurfaceTool> st;
st.instance();
if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
}
st->create_from_triangle_arrays(array_copy);
st->deindex();
st->generate_tangents();
@ -2649,6 +2770,9 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
if (d.has("weights")) {
const Array &weights = d["weights"];
for (int j = 0; j < weights.size(); j++) {
if (j >= blend_weights.size()) {
break;
}
blend_weights.write[j] = weights[j];
}
mesh->set_blend_weights(blend_weights);

View File

@ -71,6 +71,7 @@ class GLTFDocument : public Resource {
friend class GLTFSkeleton;
public:
const int32_t JOINT_GROUP_SIZE = 4;
enum GLTFType {
TYPE_SCALAR,
TYPE_VEC2,

View File

@ -865,8 +865,22 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
ERR_FAIL_V(ERR_INVALID_DATA);
} break;
}
ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA);
} else if (i == RS::ARRAY_BONES) {
switch (p_arrays[i].get_type()) {
case Variant::PACKED_INT32_ARRAY: {
Vector<Vector3> vertexes = p_arrays[RS::ARRAY_VERTEX];
Vector<int32_t> bones = p_arrays[i];
int32_t bone_8_group_count = bones.size() / (ARRAY_WEIGHTS_SIZE * 2);
int32_t vertex_count = vertexes.size();
if (vertex_count == bone_8_group_count) {
format |= RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
}
} break;
default: {
ERR_FAIL_V(ERR_INVALID_DATA);
} break;
}
} else if (i == RS::ARRAY_INDEX) {
index_array_len = PackedInt32Array(p_arrays[i]).size();
}