Forráskód Böngészése

Update buffer view target handling, encode sparse accessors as vec3.

Co-authored-by: Lyuma <[email protected]>
K. S. Ernest (iFire) Lee 1 éve
szülő
commit
1e63a2a132
2 módosított fájl, 187 hozzáadás és 46 törlés
  1. 185 39
      modules/gltf/gltf_document.cpp
  2. 2 7
      modules/gltf/gltf_document.h

+ 185 - 39
modules/gltf/gltf_document.cpp

@@ -884,42 +884,40 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) {
 		d["componentType"] = accessor->component_type;
 		d["count"] = accessor->count;
 		d["type"] = _get_accessor_type_name(accessor->type);
-		d["byteOffset"] = accessor->byte_offset;
 		d["normalized"] = accessor->normalized;
 		d["max"] = accessor->max;
 		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);
 	}
 
@@ -1026,8 +1024,6 @@ Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) {
 		}
 
 		if (d.has("sparse")) {
-			//eeh..
-
 			const Dictionary &s = d["sparse"];
 
 			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;
 	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) {
 		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));
 
-	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
 	bv->byte_offset = gltf_buffer.size();
 	if (p_for_vertex_indices) {
 		bv->indices = true;
 	} else if (p_for_vertex) {
 		bv->vertex_attributes = true;
+		bv->byte_stride = stride;
 	}
 
 	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((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();
 	p_state->buffer_views.push_back(bv);
 	return OK;
@@ -1519,8 +1521,12 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state,
 	type_max.resize(element_count);
 	Vector<double> type_min;
 	type_min.resize(element_count);
+	int max_index = 0;
 	for (int i = 0; i < p_attribs.size(); i++) {
 		attribs.write[i] = p_attribs[i];
+		if (p_attribs[i] > max_index) {
+			max_index = p_attribs[i];
+		}
 		if (i == 0) {
 			for (int32_t type_i = 0; type_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;
 	int64_t size = p_state->buffers[0].size();
 	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->min = type_min;
@@ -1976,6 +1987,106 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> p_state,
 	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 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];
+		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);
+		bool is_different = false;
+		if (i < p_reference_attribs.size()) {
+			is_different = !attrib.is_equal_approx(p_reference_attribs[i]);
+		} else {
+			is_different = !attrib.is_zero_approx();
+		}
+		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) {
 	if (p_attribs.size() == 0) {
 		return -1;
@@ -2436,7 +2547,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
 							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 {
 					if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) {
 						//generate indices because they need to be swapped for CW/CCW
@@ -2455,7 +2566,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
 								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,6 +2577,23 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
 			print_verbose("glTF: Mesh has targets");
 			if (import_mesh->get_blend_shape_count()) {
 				ArrayMesh::BlendShapeMode shape_mode = import_mesh->get_blend_shape_mode();
+				Vector<Vector3> reference_vertex_array = array[Mesh::ARRAY_VERTEX];
+				Vector<Vector3> reference_normal_array = array[Mesh::ARRAY_NORMAL];
+				Vector<Vector3> reference_tangent_array;
+				{
+					Vector<real_t> tarr = array[Mesh::ARRAY_TANGENT];
+					if (tarr.size()) {
+						const int ret_size = tarr.size() / 4;
+						reference_tangent_array.resize(ret_size);
+						for (int i = 0; i < ret_size; i++) {
+							Vector3 vec3;
+							vec3.x = tarr[(i * 4) + 0];
+							vec3.y = tarr[(i * 4) + 1];
+							vec3.z = tarr[(i * 4) + 2];
+							reference_tangent_array.write[i] = vec3;
+						}
+					}
+				}
 				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);
 					Dictionary t;
@@ -2479,13 +2607,24 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
 								varr.write[blend_i] = Vector3(varr[blend_i]) - src_varr[blend_i];
 							}
 						}
-
-						t["POSITION"] = _encode_accessor_as_vec3(p_state, varr, true);
+						GLTFAccessorIndex position_accessor = attributes["POSITION"];
+						if (position_accessor != -1) {
+							int new_accessor = _encode_sparse_accessor_as_vec3(p_state, varr, reference_vertex_array, true, position_accessor);
+							if (new_accessor != -1) {
+								t["POSITION"] = new_accessor;
+							}
+						}
 					}
 
 					Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL];
 					if (narr.size()) {
-						t["NORMAL"] = _encode_accessor_as_vec3(p_state, narr, true);
+						GLTFAccessorIndex normal_accessor = attributes["NORMAL"];
+						if (normal_accessor != -1) {
+							int new_accessor = _encode_sparse_accessor_as_vec3(p_state, narr, reference_normal_array, true, normal_accessor);
+							if (new_accessor != -1) {
+								t["NORMAL"] = new_accessor;
+							}
+						}
 					}
 					Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT];
 					if (tarr.size()) {
@@ -2497,8 +2636,15 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
 							vec3.x = tarr[(i * 4) + 0];
 							vec3.y = tarr[(i * 4) + 1];
 							vec3.z = 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, reference_tangent_array, true, tangent_accessor);
+							if (new_accessor != -1) {
+								t["TANGENT"] = new_accessor;
+							}
 						}
-						t["TANGENT"] = _encode_accessor_as_vec3(p_state, attribs, true);
 					}
 					targets.push_back(t);
 				}

+ 2 - 7
modules/gltf/gltf_document.h

@@ -57,13 +57,6 @@ public:
 		ARRAY_BUFFER = 34962,
 		ELEMENT_ARRAY_BUFFER = 34963,
 
-		TYPE_BYTE = 5120,
-		TYPE_UNSIGNED_BYTE = 5121,
-		TYPE_SHORT = 5122,
-		TYPE_UNSIGNED_SHORT = 5123,
-		TYPE_UNSIGNED_INT = 5125,
-		TYPE_FLOAT = 5126,
-
 		COMPONENT_TYPE_BYTE = 5120,
 		COMPONENT_TYPE_UNSIGNED_BYTE = 5121,
 		COMPONENT_TYPE_SHORT = 5122,
@@ -255,6 +248,7 @@ private:
 	GLTFAccessorIndex _encode_accessor_as_vec3(Ref<GLTFState> p_state,
 			const Vector<Vector3> p_attribs,
 			const bool p_for_vertex);
+	GLTFAccessorIndex _encode_sparse_accessor_as_vec3(Ref<GLTFState> p_state, const Vector<Vector3> p_attribs, const Vector<Vector3> p_reference_attribs, const bool p_for_vertex, const GLTFAccessorIndex p_reference_accessor);
 	GLTFAccessorIndex _encode_accessor_as_color(Ref<GLTFState> p_state,
 			const Vector<Color> p_attribs,
 			const bool p_for_vertex);
@@ -273,6 +267,7 @@ private:
 			const int p_component_type, const bool p_normalized,
 			const int p_byte_offset, const bool p_for_vertex,
 			GLTFBufferViewIndex &r_accessor, const bool p_for_indices = false);
+
 	Error _encode_accessors(Ref<GLTFState> p_state);
 	Error _encode_buffer_views(Ref<GLTFState> p_state);
 	Error _serialize_materials(Ref<GLTFState> p_state);