|
@@ -884,42 +884,40 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) {
|
|
d["componentType"] = accessor->component_type;
|
|
d["componentType"] = accessor->component_type;
|
|
d["count"] = accessor->count;
|
|
d["count"] = accessor->count;
|
|
d["type"] = _get_accessor_type_name(accessor->type);
|
|
d["type"] = _get_accessor_type_name(accessor->type);
|
|
- d["byteOffset"] = accessor->byte_offset;
|
|
|
|
d["normalized"] = accessor->normalized;
|
|
d["normalized"] = accessor->normalized;
|
|
d["max"] = accessor->max;
|
|
d["max"] = accessor->max;
|
|
d["min"] = accessor->min;
|
|
d["min"] = accessor->min;
|
|
- d["bufferView"] = accessor->buffer_view; //optional because it may be sparse...
|
|
|
|
-
|
|
|
|
- // Dictionary s;
|
|
|
|
- // s["count"] = accessor->sparse_count;
|
|
|
|
- // ERR_FAIL_COND_V(!s.has("count"), ERR_PARSE_ERROR);
|
|
|
|
-
|
|
|
|
- // s["indices"] = accessor->sparse_accessors;
|
|
|
|
- // ERR_FAIL_COND_V(!s.has("indices"), ERR_PARSE_ERROR);
|
|
|
|
-
|
|
|
|
- // Dictionary si;
|
|
|
|
|
|
+ if (accessor->buffer_view != -1) {
|
|
|
|
+ // bufferView may be omitted to zero-initialize the buffer. When this happens, byteOffset MUST also be omitted.
|
|
|
|
+ d["byteOffset"] = accessor->byte_offset;
|
|
|
|
+ d["bufferView"] = accessor->buffer_view;
|
|
|
|
+ }
|
|
|
|
|
|
- // si["bufferView"] = accessor->sparse_indices_buffer_view;
|
|
|
|
|
|
+ if (accessor->sparse_count > 0) {
|
|
|
|
+ Dictionary s;
|
|
|
|
+ s["count"] = accessor->sparse_count;
|
|
|
|
|
|
- // ERR_FAIL_COND_V(!si.has("bufferView"), ERR_PARSE_ERROR);
|
|
|
|
- // si["componentType"] = accessor->sparse_indices_component_type;
|
|
|
|
|
|
+ Dictionary si;
|
|
|
|
+ si["bufferView"] = accessor->sparse_indices_buffer_view;
|
|
|
|
+ si["componentType"] = accessor->sparse_indices_component_type;
|
|
|
|
+ if (accessor->sparse_indices_byte_offset != -1) {
|
|
|
|
+ si["byteOffset"] = accessor->sparse_indices_byte_offset;
|
|
|
|
+ }
|
|
|
|
+ ERR_FAIL_COND_V(!si.has("bufferView") || !si.has("componentType"), ERR_PARSE_ERROR);
|
|
|
|
+ s["indices"] = si;
|
|
|
|
|
|
- // if (si.has("byteOffset")) {
|
|
|
|
- // si["byteOffset"] = accessor->sparse_indices_byte_offset;
|
|
|
|
- // }
|
|
|
|
|
|
+ Dictionary sv;
|
|
|
|
+ sv["bufferView"] = accessor->sparse_values_buffer_view;
|
|
|
|
+ if (accessor->sparse_values_byte_offset != -1) {
|
|
|
|
+ sv["byteOffset"] = accessor->sparse_values_byte_offset;
|
|
|
|
+ }
|
|
|
|
+ ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR);
|
|
|
|
+ s["values"] = sv;
|
|
|
|
|
|
- // ERR_FAIL_COND_V(!si.has("componentType"), ERR_PARSE_ERROR);
|
|
|
|
- // s["indices"] = si;
|
|
|
|
- // Dictionary sv;
|
|
|
|
|
|
+ ERR_FAIL_COND_V(!s.has("count") || !s.has("indices") || !s.has("values"), ERR_PARSE_ERROR);
|
|
|
|
+ d["sparse"] = s;
|
|
|
|
+ }
|
|
|
|
|
|
- // sv["bufferView"] = accessor->sparse_values_buffer_view;
|
|
|
|
- // if (sv.has("byteOffset")) {
|
|
|
|
- // sv["byteOffset"] = accessor->sparse_values_byte_offset;
|
|
|
|
- // }
|
|
|
|
- // ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR);
|
|
|
|
- // s["values"] = sv;
|
|
|
|
- // ERR_FAIL_COND_V(!s.has("values"), ERR_PARSE_ERROR);
|
|
|
|
- // d["sparse"] = s;
|
|
|
|
accessors.push_back(d);
|
|
accessors.push_back(d);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1026,8 +1024,6 @@ Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) {
|
|
}
|
|
}
|
|
|
|
|
|
if (d.has("sparse")) {
|
|
if (d.has("sparse")) {
|
|
- //eeh..
|
|
|
|
-
|
|
|
|
const Dictionary &s = d["sparse"];
|
|
const Dictionary &s = d["sparse"];
|
|
|
|
|
|
ERR_FAIL_COND_V(!s.has("count"), ERR_PARSE_ERROR);
|
|
ERR_FAIL_COND_V(!s.has("count"), ERR_PARSE_ERROR);
|
|
@@ -1143,7 +1139,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_
|
|
const uint32_t offset = bv->byte_offset = p_byte_offset;
|
|
const uint32_t offset = bv->byte_offset = p_byte_offset;
|
|
Vector<uint8_t> &gltf_buffer = p_state->buffers.write[0];
|
|
Vector<uint8_t> &gltf_buffer = p_state->buffers.write[0];
|
|
|
|
|
|
- int stride = _get_component_type_size(p_component_type);
|
|
|
|
|
|
+ int stride = component_count * component_size;
|
|
if (p_for_vertex && stride % 4) {
|
|
if (p_for_vertex && stride % 4) {
|
|
stride += 4 - (stride % 4); //according to spec must be multiple of 4
|
|
stride += 4 - (stride % 4); //according to spec must be multiple of 4
|
|
}
|
|
}
|
|
@@ -1152,13 +1148,14 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_
|
|
|
|
|
|
print_verbose("glTF: encoding accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(gltf_buffer.size()) + " view len " + itos(bv->byte_length));
|
|
print_verbose("glTF: encoding accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(gltf_buffer.size()) + " view len " + itos(bv->byte_length));
|
|
|
|
|
|
- const int buffer_end = (stride * (p_count - 1)) + _get_component_type_size(p_component_type);
|
|
|
|
|
|
+ const int buffer_end = (stride * (p_count - 1)) + component_size;
|
|
// TODO define bv->byte_stride
|
|
// TODO define bv->byte_stride
|
|
bv->byte_offset = gltf_buffer.size();
|
|
bv->byte_offset = gltf_buffer.size();
|
|
if (p_for_vertex_indices) {
|
|
if (p_for_vertex_indices) {
|
|
bv->indices = true;
|
|
bv->indices = true;
|
|
} else if (p_for_vertex) {
|
|
} else if (p_for_vertex) {
|
|
bv->vertex_attributes = true;
|
|
bv->vertex_attributes = true;
|
|
|
|
+ bv->byte_stride = stride;
|
|
}
|
|
}
|
|
|
|
|
|
switch (p_component_type) {
|
|
switch (p_component_type) {
|
|
@@ -1300,6 +1297,11 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_
|
|
ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_INVALID_DATA);
|
|
ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_INVALID_DATA);
|
|
|
|
|
|
ERR_FAIL_COND_V((int)(offset + buffer_end) > gltf_buffer.size(), ERR_INVALID_DATA);
|
|
ERR_FAIL_COND_V((int)(offset + buffer_end) > gltf_buffer.size(), ERR_INVALID_DATA);
|
|
|
|
+ int pad_bytes = (4 - gltf_buffer.size()) & 3;
|
|
|
|
+ for (int i = 0; i < pad_bytes; i++) {
|
|
|
|
+ gltf_buffer.push_back(0);
|
|
|
|
+ }
|
|
|
|
+
|
|
r_accessor = bv->buffer = p_state->buffer_views.size();
|
|
r_accessor = bv->buffer = p_state->buffer_views.size();
|
|
p_state->buffer_views.push_back(bv);
|
|
p_state->buffer_views.push_back(bv);
|
|
return OK;
|
|
return OK;
|
|
@@ -1519,8 +1521,12 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state,
|
|
type_max.resize(element_count);
|
|
type_max.resize(element_count);
|
|
Vector<double> type_min;
|
|
Vector<double> type_min;
|
|
type_min.resize(element_count);
|
|
type_min.resize(element_count);
|
|
|
|
+ int max_index = 0;
|
|
for (int i = 0; i < p_attribs.size(); i++) {
|
|
for (int i = 0; i < p_attribs.size(); i++) {
|
|
attribs.write[i] = p_attribs[i];
|
|
attribs.write[i] = p_attribs[i];
|
|
|
|
+ if (p_attribs[i] > max_index) {
|
|
|
|
+ max_index = p_attribs[i];
|
|
|
|
+ }
|
|
if (i == 0) {
|
|
if (i == 0) {
|
|
for (int32_t type_i = 0; type_i < element_count; type_i++) {
|
|
for (int32_t type_i = 0; type_i < element_count; type_i++) {
|
|
type_max.write[type_i] = attribs[(i * element_count) + type_i];
|
|
type_max.write[type_i] = attribs[(i * element_count) + type_i];
|
|
@@ -1539,7 +1545,12 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state,
|
|
GLTFBufferIndex buffer_view_i;
|
|
GLTFBufferIndex buffer_view_i;
|
|
int64_t size = p_state->buffers[0].size();
|
|
int64_t size = p_state->buffers[0].size();
|
|
const GLTFType type = GLTFType::TYPE_SCALAR;
|
|
const GLTFType type = GLTFType::TYPE_SCALAR;
|
|
- const int component_type = GLTFDocument::COMPONENT_TYPE_INT;
|
|
|
|
|
|
+ int component_type;
|
|
|
|
+ if (max_index > 65535 || p_for_vertex) {
|
|
|
|
+ component_type = GLTFDocument::COMPONENT_TYPE_INT;
|
|
|
|
+ } else {
|
|
|
|
+ component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT;
|
|
|
|
+ }
|
|
|
|
|
|
accessor->max = type_max;
|
|
accessor->max = type_max;
|
|
accessor->min = type_min;
|
|
accessor->min = type_min;
|
|
@@ -1976,6 +1987,112 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> p_state,
|
|
return p_state->accessors.size() - 1;
|
|
return p_state->accessors.size() - 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+GLTFAccessorIndex GLTFDocument::_encode_sparse_accessor_as_vec3(Ref<GLTFState> p_state, const Vector<Vector3> p_attribs, const Vector<Vector3> p_reference_attribs, const float p_reference_multiplier, const bool p_for_vertex, const GLTFAccessorIndex p_reference_accessor) {
|
|
|
|
+ if (p_attribs.size() == 0) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const int element_count = 3;
|
|
|
|
+ Vector<double> attribs;
|
|
|
|
+ Vector<double> type_max;
|
|
|
|
+ Vector<double> type_min;
|
|
|
|
+ attribs.resize(p_attribs.size() * element_count);
|
|
|
|
+ type_max.resize(element_count);
|
|
|
|
+ type_min.resize(element_count);
|
|
|
|
+
|
|
|
|
+ Vector<double> changed_indices;
|
|
|
|
+ Vector<double> changed_values;
|
|
|
|
+ int max_changed_index = 0;
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < p_attribs.size(); i++) {
|
|
|
|
+ Vector3 attrib = p_attribs[i];
|
|
|
|
+ bool is_different = false;
|
|
|
|
+ if (i < p_reference_attribs.size()) {
|
|
|
|
+ is_different = !(attrib * p_reference_multiplier).is_equal_approx(p_reference_attribs[i]);
|
|
|
|
+ if (!is_different) {
|
|
|
|
+ attrib = p_reference_attribs[i];
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ is_different = !(attrib * p_reference_multiplier).is_zero_approx();
|
|
|
|
+ if (!is_different) {
|
|
|
|
+ attrib = Vector3();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ attribs.write[(i * element_count) + 0] = _filter_number(attrib.x);
|
|
|
|
+ attribs.write[(i * element_count) + 1] = _filter_number(attrib.y);
|
|
|
|
+ attribs.write[(i * element_count) + 2] = _filter_number(attrib.z);
|
|
|
|
+ if (is_different) {
|
|
|
|
+ changed_indices.push_back(i);
|
|
|
|
+ if (i > max_changed_index) {
|
|
|
|
+ max_changed_index = i;
|
|
|
|
+ }
|
|
|
|
+ changed_values.push_back(_filter_number(attrib.x));
|
|
|
|
+ changed_values.push_back(_filter_number(attrib.y));
|
|
|
|
+ changed_values.push_back(_filter_number(attrib.z));
|
|
|
|
+ }
|
|
|
|
+ _calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
|
|
|
|
+ }
|
|
|
|
+ _round_min_max_components(type_min, type_max);
|
|
|
|
+
|
|
|
|
+ if (attribs.size() % element_count != 0) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ref<GLTFAccessor> sparse_accessor;
|
|
|
|
+ sparse_accessor.instantiate();
|
|
|
|
+ int64_t size = p_state->buffers[0].size();
|
|
|
|
+ const GLTFType type = GLTFType::TYPE_VEC3;
|
|
|
|
+ const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
|
|
|
|
+
|
|
|
|
+ sparse_accessor->normalized = false;
|
|
|
|
+ sparse_accessor->count = p_attribs.size();
|
|
|
|
+ sparse_accessor->type = type;
|
|
|
|
+ sparse_accessor->component_type = component_type;
|
|
|
|
+ if (p_reference_accessor < p_state->accessors.size() && p_reference_accessor >= 0 && p_state->accessors[p_reference_accessor].is_valid()) {
|
|
|
|
+ sparse_accessor->byte_offset = p_state->accessors[p_reference_accessor]->byte_offset;
|
|
|
|
+ sparse_accessor->buffer_view = p_state->accessors[p_reference_accessor]->buffer_view;
|
|
|
|
+ }
|
|
|
|
+ sparse_accessor->max = type_max;
|
|
|
|
+ sparse_accessor->min = type_min;
|
|
|
|
+ int sparse_accessor_index_stride = max_changed_index > 65535 ? 4 : 2;
|
|
|
|
+
|
|
|
|
+ int sparse_accessor_storage_size = changed_indices.size() * (sparse_accessor_index_stride + element_count * sizeof(float));
|
|
|
|
+ int conventional_storage_size = p_attribs.size() * element_count * sizeof(float);
|
|
|
|
+
|
|
|
|
+ if (changed_indices.size() > 0 && sparse_accessor_storage_size < conventional_storage_size) {
|
|
|
|
+ // It must be worthwhile to use a sparse accessor.
|
|
|
|
+
|
|
|
|
+ GLTFBufferIndex buffer_view_i_indices = -1;
|
|
|
|
+ GLTFBufferIndex buffer_view_i_values = -1;
|
|
|
|
+ if (sparse_accessor_index_stride == 4) {
|
|
|
|
+ sparse_accessor->sparse_indices_component_type = GLTFDocument::COMPONENT_TYPE_INT;
|
|
|
|
+ } else {
|
|
|
|
+ sparse_accessor->sparse_indices_component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT;
|
|
|
|
+ }
|
|
|
|
+ if (_encode_buffer_view(p_state, changed_indices.ptr(), changed_indices.size(), GLTFType::TYPE_SCALAR, sparse_accessor->sparse_indices_component_type, sparse_accessor->normalized, sparse_accessor->sparse_indices_byte_offset, false, buffer_view_i_indices) != OK) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ // We use changed_indices.size() here, because we must pass the number of vec3 values rather than the number of components.
|
|
|
|
+ if (_encode_buffer_view(p_state, changed_values.ptr(), changed_indices.size(), sparse_accessor->type, sparse_accessor->component_type, sparse_accessor->normalized, sparse_accessor->sparse_values_byte_offset, false, buffer_view_i_values) != OK) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ sparse_accessor->sparse_indices_buffer_view = buffer_view_i_indices;
|
|
|
|
+ sparse_accessor->sparse_values_buffer_view = buffer_view_i_values;
|
|
|
|
+ sparse_accessor->sparse_count = changed_indices.size();
|
|
|
|
+ } else if (changed_indices.size() > 0) {
|
|
|
|
+ GLTFBufferIndex buffer_view_i;
|
|
|
|
+ sparse_accessor->byte_offset = 0;
|
|
|
|
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, sparse_accessor->normalized, size, p_for_vertex, buffer_view_i);
|
|
|
|
+ if (err != OK) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ sparse_accessor->buffer_view = buffer_view_i;
|
|
|
|
+ }
|
|
|
|
+ p_state->accessors.push_back(sparse_accessor);
|
|
|
|
+
|
|
|
|
+ return p_state->accessors.size() - 1;
|
|
|
|
+}
|
|
|
|
+
|
|
GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> p_state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) {
|
|
GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> p_state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) {
|
|
if (p_attribs.size() == 0) {
|
|
if (p_attribs.size() == 0) {
|
|
return -1;
|
|
return -1;
|
|
@@ -2436,7 +2553,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
|
|
SWAP(mesh_indices.write[k + 0], mesh_indices.write[k + 2]);
|
|
SWAP(mesh_indices.write[k + 0], mesh_indices.write[k + 2]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- primitive["indices"] = _encode_accessor_as_ints(p_state, mesh_indices, true, true);
|
|
|
|
|
|
+ primitive["indices"] = _encode_accessor_as_ints(p_state, mesh_indices, false, true);
|
|
} else {
|
|
} else {
|
|
if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) {
|
|
if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) {
|
|
//generate indices because they need to be swapped for CW/CCW
|
|
//generate indices because they need to be swapped for CW/CCW
|
|
@@ -2455,7 +2572,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
|
|
generated_indices.write[k + 2] = k + 1;
|
|
generated_indices.write[k + 2] = k + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- primitive["indices"] = _encode_accessor_as_ints(p_state, generated_indices, true, true);
|
|
|
|
|
|
+ primitive["indices"] = _encode_accessor_as_ints(p_state, generated_indices, false, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -2466,39 +2583,66 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
|
|
print_verbose("glTF: Mesh has targets");
|
|
print_verbose("glTF: Mesh has targets");
|
|
if (import_mesh->get_blend_shape_count()) {
|
|
if (import_mesh->get_blend_shape_count()) {
|
|
ArrayMesh::BlendShapeMode shape_mode = import_mesh->get_blend_shape_mode();
|
|
ArrayMesh::BlendShapeMode shape_mode = import_mesh->get_blend_shape_mode();
|
|
|
|
+ const float normal_tangent_sparse_rounding = 0.001;
|
|
for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) {
|
|
for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) {
|
|
Array array_morph = import_mesh->get_surface_blend_shape_arrays(surface_i, morph_i);
|
|
Array array_morph = import_mesh->get_surface_blend_shape_arrays(surface_i, morph_i);
|
|
Dictionary t;
|
|
Dictionary t;
|
|
Vector<Vector3> varr = array_morph[Mesh::ARRAY_VERTEX];
|
|
Vector<Vector3> varr = array_morph[Mesh::ARRAY_VERTEX];
|
|
|
|
+ Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
|
|
Array mesh_arrays = import_mesh->get_surface_arrays(surface_i);
|
|
Array mesh_arrays = import_mesh->get_surface_arrays(surface_i);
|
|
- if (varr.size()) {
|
|
|
|
- Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
|
|
|
|
|
|
+ if (varr.size() && varr.size() == src_varr.size()) {
|
|
if (shape_mode == ArrayMesh::BlendShapeMode::BLEND_SHAPE_MODE_NORMALIZED) {
|
|
if (shape_mode == ArrayMesh::BlendShapeMode::BLEND_SHAPE_MODE_NORMALIZED) {
|
|
const int max_idx = src_varr.size();
|
|
const int max_idx = src_varr.size();
|
|
for (int blend_i = 0; blend_i < max_idx; blend_i++) {
|
|
for (int blend_i = 0; blend_i < max_idx; blend_i++) {
|
|
- varr.write[blend_i] = Vector3(varr[blend_i]) - src_varr[blend_i];
|
|
|
|
|
|
+ varr.write[blend_i] = varr[blend_i] - src_varr[blend_i];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ GLTFAccessorIndex position_accessor = attributes["POSITION"];
|
|
|
|
+ if (position_accessor != -1) {
|
|
|
|
+ int new_accessor = _encode_sparse_accessor_as_vec3(p_state, varr, Vector<Vector3>(), 1.0, true, -1);
|
|
|
|
+ if (new_accessor != -1) {
|
|
|
|
+ t["POSITION"] = new_accessor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- t["POSITION"] = _encode_accessor_as_vec3(p_state, varr, true);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL];
|
|
Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL];
|
|
- if (narr.size()) {
|
|
|
|
- t["NORMAL"] = _encode_accessor_as_vec3(p_state, narr, true);
|
|
|
|
|
|
+ Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
|
|
|
|
+ if (narr.size() && narr.size() == src_narr.size()) {
|
|
|
|
+ if (shape_mode == ArrayMesh::BlendShapeMode::BLEND_SHAPE_MODE_NORMALIZED) {
|
|
|
|
+ const int max_idx = src_narr.size();
|
|
|
|
+ for (int blend_i = 0; blend_i < max_idx; blend_i++) {
|
|
|
|
+ narr.write[blend_i] = narr[blend_i] - src_narr[blend_i];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ GLTFAccessorIndex normal_accessor = attributes["NORMAL"];
|
|
|
|
+ if (normal_accessor != -1) {
|
|
|
|
+ int new_accessor = _encode_sparse_accessor_as_vec3(p_state, narr, Vector<Vector3>(), normal_tangent_sparse_rounding, true, -1);
|
|
|
|
+ if (new_accessor != -1) {
|
|
|
|
+ t["NORMAL"] = new_accessor;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT];
|
|
Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT];
|
|
- if (tarr.size()) {
|
|
|
|
|
|
+ Vector<real_t> src_tarr = array[Mesh::ARRAY_TANGENT];
|
|
|
|
+ if (tarr.size() && tarr.size() == src_tarr.size()) {
|
|
const int ret_size = tarr.size() / 4;
|
|
const int ret_size = tarr.size() / 4;
|
|
Vector<Vector3> attribs;
|
|
Vector<Vector3> attribs;
|
|
attribs.resize(ret_size);
|
|
attribs.resize(ret_size);
|
|
for (int i = 0; i < ret_size; i++) {
|
|
for (int i = 0; i < ret_size; i++) {
|
|
Vector3 vec3;
|
|
Vector3 vec3;
|
|
- vec3.x = tarr[(i * 4) + 0];
|
|
|
|
- vec3.y = tarr[(i * 4) + 1];
|
|
|
|
- vec3.z = tarr[(i * 4) + 2];
|
|
|
|
|
|
+ vec3.x = tarr[(i * 4) + 0] - src_tarr[(i * 4) + 0];
|
|
|
|
+ vec3.y = tarr[(i * 4) + 1] - src_tarr[(i * 4) + 1];
|
|
|
|
+ vec3.z = tarr[(i * 4) + 2] - src_tarr[(i * 4) + 2];
|
|
|
|
+ attribs.write[i] = vec3;
|
|
|
|
+ }
|
|
|
|
+ GLTFAccessorIndex tangent_accessor = attributes["TANGENT"];
|
|
|
|
+ if (tangent_accessor != -1) {
|
|
|
|
+ int new_accessor = _encode_sparse_accessor_as_vec3(p_state, attribs, Vector<Vector3>(), normal_tangent_sparse_rounding, true, -1);
|
|
|
|
+ if (new_accessor != -1) {
|
|
|
|
+ t["TANGENT"] = new_accessor;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- t["TANGENT"] = _encode_accessor_as_vec3(p_state, attribs, true);
|
|
|
|
}
|
|
}
|
|
targets.push_back(t);
|
|
targets.push_back(t);
|
|
}
|
|
}
|