Browse Source

Merge pull request #89418 from lyuma/gltf_vertex_packing

Only store vertices referenced by the indices per surface in the glTF importer
Rémi Verschelde 1 year ago
parent
commit
21b33c5ea4
2 changed files with 148 additions and 69 deletions
  1. 138 64
      modules/gltf/gltf_document.cpp
  2. 10 5
      modules/gltf/gltf_document.h

+ 138 - 64
modules/gltf/gltf_document.cpp

@@ -1568,7 +1568,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state,
 	return p_state->accessors.size() - 1;
 	return p_state->accessors.size() - 1;
 }
 }
 
 
-Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	Vector<int> ret;
 	Vector<int> ret;
 
 
@@ -1577,17 +1577,23 @@ Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> p_state, const
 	}
 	}
 
 
 	const double *attribs_ptr = attribs.ptr();
 	const double *attribs_ptr = attribs.ptr();
-	const int ret_size = attribs.size();
+	int ret_size = attribs.size();
+	if (!p_packed_vertex_ids.is_empty()) {
+		ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
+		ret_size = p_packed_vertex_ids.size();
+	}
 	ret.resize(ret_size);
 	ret.resize(ret_size);
-	{
-		for (int i = 0; i < ret_size; i++) {
-			ret.write[i] = int(attribs_ptr[i]);
+	for (int i = 0; i < ret_size; i++) {
+		int src_i = i;
+		if (!p_packed_vertex_ids.is_empty()) {
+			src_i = p_packed_vertex_ids[i];
 		}
 		}
+		ret.write[i] = int(attribs_ptr[src_i]);
 	}
 	}
 	return ret;
 	return ret;
 }
 }
 
 
-Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	Vector<float> ret;
 	Vector<float> ret;
 
 
@@ -1596,12 +1602,18 @@ Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> p_state, c
 	}
 	}
 
 
 	const double *attribs_ptr = attribs.ptr();
 	const double *attribs_ptr = attribs.ptr();
-	const int ret_size = attribs.size();
+	int ret_size = attribs.size();
+	if (!p_packed_vertex_ids.is_empty()) {
+		ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
+		ret_size = p_packed_vertex_ids.size();
+	}
 	ret.resize(ret_size);
 	ret.resize(ret_size);
-	{
-		for (int i = 0; i < ret_size; i++) {
-			ret.write[i] = float(attribs_ptr[i]);
+	for (int i = 0; i < ret_size; i++) {
+		int src_i = i;
+		if (!p_packed_vertex_ids.is_empty()) {
+			src_i = p_packed_vertex_ids[i];
 		}
 		}
+		ret.write[i] = float(attribs_ptr[src_i]);
 	}
 	}
 	return ret;
 	return ret;
 }
 }
@@ -1874,7 +1886,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> p
 	return p_state->accessors.size() - 1;
 	return p_state->accessors.size() - 1;
 }
 }
 
 
-Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	Vector<Vector2> ret;
 	Vector<Vector2> ret;
 
 
@@ -1884,12 +1896,18 @@ Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> p_state, c
 
 
 	ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret);
 	ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret);
 	const double *attribs_ptr = attribs.ptr();
 	const double *attribs_ptr = attribs.ptr();
-	const int ret_size = attribs.size() / 2;
+	int ret_size = attribs.size() / 2;
+	if (!p_packed_vertex_ids.is_empty()) {
+		ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
+		ret_size = p_packed_vertex_ids.size();
+	}
 	ret.resize(ret_size);
 	ret.resize(ret_size);
-	{
-		for (int i = 0; i < ret_size; i++) {
-			ret.write[i] = Vector2(attribs_ptr[i * 2 + 0], attribs_ptr[i * 2 + 1]);
+	for (int i = 0; i < ret_size; i++) {
+		int src_i = i;
+		if (!p_packed_vertex_ids.is_empty()) {
+			src_i = p_packed_vertex_ids[i];
 		}
 		}
+		ret.write[i] = Vector2(attribs_ptr[src_i * 2 + 0], attribs_ptr[src_i * 2 + 1]);
 	}
 	}
 	return ret;
 	return ret;
 }
 }
@@ -2162,7 +2180,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> p_state
 	return p_state->accessors.size() - 1;
 	return p_state->accessors.size() - 1;
 }
 }
 
 
-Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	Vector<Vector3> ret;
 	Vector<Vector3> ret;
 
 
@@ -2172,17 +2190,23 @@ Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> p_state, c
 
 
 	ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret);
 	ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret);
 	const double *attribs_ptr = attribs.ptr();
 	const double *attribs_ptr = attribs.ptr();
-	const int ret_size = attribs.size() / 3;
+	int ret_size = attribs.size() / 3;
+	if (!p_packed_vertex_ids.is_empty()) {
+		ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
+		ret_size = p_packed_vertex_ids.size();
+	}
 	ret.resize(ret_size);
 	ret.resize(ret_size);
-	{
-		for (int i = 0; i < ret_size; i++) {
-			ret.write[i] = Vector3(attribs_ptr[i * 3 + 0], attribs_ptr[i * 3 + 1], attribs_ptr[i * 3 + 2]);
+	for (int i = 0; i < ret_size; i++) {
+		int src_i = i;
+		if (!p_packed_vertex_ids.is_empty()) {
+			src_i = p_packed_vertex_ids[i];
 		}
 		}
+		ret.write[i] = Vector3(attribs_ptr[src_i * 3 + 0], attribs_ptr[src_i * 3 + 1], attribs_ptr[src_i * 3 + 2]);
 	}
 	}
 	return ret;
 	return ret;
 }
 }
 
 
-Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
 	Vector<Color> ret;
 	Vector<Color> ret;
 
 
@@ -2199,12 +2223,18 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> p_state, co
 
 
 	ERR_FAIL_COND_V(attribs.size() % vec_len != 0, ret);
 	ERR_FAIL_COND_V(attribs.size() % vec_len != 0, ret);
 	const double *attribs_ptr = attribs.ptr();
 	const double *attribs_ptr = attribs.ptr();
-	const int ret_size = attribs.size() / vec_len;
+	int ret_size = attribs.size() / vec_len;
+	if (!p_packed_vertex_ids.is_empty()) {
+		ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
+		ret_size = p_packed_vertex_ids.size();
+	}
 	ret.resize(ret_size);
 	ret.resize(ret_size);
-	{
-		for (int i = 0; i < ret_size; i++) {
-			ret.write[i] = Color(attribs_ptr[i * vec_len + 0], attribs_ptr[i * vec_len + 1], attribs_ptr[i * vec_len + 2], vec_len == 4 ? attribs_ptr[i * 4 + 3] : 1.0);
+	for (int i = 0; i < ret_size; i++) {
+		int src_i = i;
+		if (!p_packed_vertex_ids.is_empty()) {
+			src_i = p_packed_vertex_ids[i];
 		}
 		}
+		ret.write[i] = Color(attribs_ptr[src_i * vec_len + 0], attribs_ptr[src_i * vec_len + 1], attribs_ptr[src_i * vec_len + 2], vec_len == 4 ? attribs_ptr[src_i * 4 + 3] : 1.0);
 	}
 	}
 	return ret;
 	return ret;
 }
 }
@@ -2547,7 +2577,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
 				Vector<int32_t> mesh_indices = array[Mesh::ARRAY_INDEX];
 				Vector<int32_t> mesh_indices = array[Mesh::ARRAY_INDEX];
 				if (mesh_indices.size()) {
 				if (mesh_indices.size()) {
 					if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) {
 					if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) {
-						//swap around indices, convert ccw to cw for front face
+						// Swap around indices, convert ccw to cw for front face.
 						const int is = mesh_indices.size();
 						const int is = mesh_indices.size();
 						for (int k = 0; k < is; k += 3) {
 						for (int k = 0; k < is; k += 3) {
 							SWAP(mesh_indices.write[k + 0], mesh_indices.write[k + 2]);
 							SWAP(mesh_indices.write[k + 0], mesh_indices.write[k + 2]);
@@ -2556,7 +2586,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
 					primitive["indices"] = _encode_accessor_as_ints(p_state, mesh_indices, false, 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.
 						const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX];
 						const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX];
 						Ref<SurfaceTool> st;
 						Ref<SurfaceTool> st;
 						st.instantiate();
 						st.instantiate();
@@ -2579,7 +2609,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
 
 
 			primitive["attributes"] = attributes;
 			primitive["attributes"] = attributes;
 
 
-			//blend shapes
+			// Blend shapes
 			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();
@@ -2767,24 +2797,72 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 				primitive = primitives2[mode];
 				primitive = primitives2[mode];
 			}
 			}
 
 
+			int32_t orig_vertex_num = 0;
 			ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR);
 			ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR);
-			int32_t vertex_num = 0;
 			if (a.has("POSITION")) {
 			if (a.has("POSITION")) {
 				PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], true);
 				PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], true);
 				array[Mesh::ARRAY_VERTEX] = vertices;
 				array[Mesh::ARRAY_VERTEX] = vertices;
-				vertex_num = vertices.size();
+				orig_vertex_num = vertices.size();
+			}
+			int32_t vertex_num = orig_vertex_num;
+
+			Vector<int> indices;
+			Vector<int> indices_mapping;
+			Vector<int> indices_rev_mapping;
+			Vector<int> indices_vec4_mapping;
+			if (p.has("indices")) {
+				indices = _decode_accessor_as_ints(p_state, p["indices"], false);
+				const int is = indices.size();
+
+				if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
+					// Swap around indices, convert ccw to cw for front face.
+
+					int *w = indices.ptrw();
+					for (int k = 0; k < is; k += 3) {
+						SWAP(w[k + 1], w[k + 2]);
+					}
+				}
+
+				const int *indices_w = indices.ptrw();
+				Vector<bool> used_indices;
+				used_indices.resize_zeroed(orig_vertex_num);
+				bool *used_w = used_indices.ptrw();
+				for (int idx_i = 0; idx_i < is; idx_i++) {
+					ERR_FAIL_INDEX_V(indices_w[idx_i], orig_vertex_num, ERR_INVALID_DATA);
+					used_w[indices_w[idx_i]] = true;
+				}
+				indices_rev_mapping.resize_zeroed(orig_vertex_num);
+				int *rev_w = indices_rev_mapping.ptrw();
+				vertex_num = 0;
+				for (int vert_i = 0; vert_i < orig_vertex_num; vert_i++) {
+					if (used_w[vert_i]) {
+						rev_w[vert_i] = indices_mapping.size();
+						indices_mapping.push_back(vert_i);
+						indices_vec4_mapping.push_back(vert_i * 4 + 0);
+						indices_vec4_mapping.push_back(vert_i * 4 + 1);
+						indices_vec4_mapping.push_back(vert_i * 4 + 2);
+						indices_vec4_mapping.push_back(vert_i * 4 + 3);
+						vertex_num++;
+					}
+				}
+			}
+			ERR_FAIL_COND_V(vertex_num <= 0, ERR_INVALID_DECLARATION);
+
+			if (a.has("POSITION")) {
+				PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], true, indices_mapping);
+				array[Mesh::ARRAY_VERTEX] = vertices;
 			}
 			}
 			if (a.has("NORMAL")) {
 			if (a.has("NORMAL")) {
-				array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(p_state, a["NORMAL"], true);
+				array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(p_state, a["NORMAL"], true, indices_mapping);
 			}
 			}
 			if (a.has("TANGENT")) {
 			if (a.has("TANGENT")) {
-				array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(p_state, a["TANGENT"], true);
+				array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(p_state, a["TANGENT"], true, indices_vec4_mapping);
 			}
 			}
 			if (a.has("TEXCOORD_0")) {
 			if (a.has("TEXCOORD_0")) {
-				array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_0"], true);
+				array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_0"], true, indices_mapping);
 			}
 			}
 			if (a.has("TEXCOORD_1")) {
 			if (a.has("TEXCOORD_1")) {
-				array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_1"], true);
+				array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_1"], true, indices_mapping);
 			}
 			}
 			for (int custom_i = 0; custom_i < 3; custom_i++) {
 			for (int custom_i = 0; custom_i < 3; custom_i++) {
 				Vector<float> cur_custom;
 				Vector<float> cur_custom;
@@ -2795,12 +2873,12 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 				String gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i);
 				String gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i);
 				int num_channels = 0;
 				int num_channels = 0;
 				if (a.has(gltf_texcoord_key)) {
 				if (a.has(gltf_texcoord_key)) {
-					texcoord_first = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true);
+					texcoord_first = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true, indices_mapping);
 					num_channels = 2;
 					num_channels = 2;
 				}
 				}
 				gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1);
 				gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1);
 				if (a.has(gltf_texcoord_key)) {
 				if (a.has(gltf_texcoord_key)) {
-					texcoord_second = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true);
+					texcoord_second = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true, indices_mapping);
 					num_channels = 4;
 					num_channels = 4;
 				}
 				}
 				if (!num_channels) {
 				if (!num_channels) {
@@ -2841,15 +2919,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 				}
 				}
 			}
 			}
 			if (a.has("COLOR_0")) {
 			if (a.has("COLOR_0")) {
-				array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(p_state, a["COLOR_0"], true);
+				array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(p_state, a["COLOR_0"], true, indices_mapping);
 				has_vertex_color = true;
 				has_vertex_color = true;
 			}
 			}
 			if (a.has("JOINTS_0") && !a.has("JOINTS_1")) {
 			if (a.has("JOINTS_0") && !a.has("JOINTS_1")) {
-				array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true);
+				PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true, indices_vec4_mapping);
+				ERR_FAIL_COND_V(joints_0.size() != 4 * vertex_num, ERR_INVALID_DATA);
+				array[Mesh::ARRAY_BONES] = joints_0;
 			} else if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
 			} else if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
-				PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true);
-				PackedInt32Array joints_1 = _decode_accessor_as_ints(p_state, a["JOINTS_1"], true);
+				PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true, indices_vec4_mapping);
+				PackedInt32Array joints_1 = _decode_accessor_as_ints(p_state, a["JOINTS_1"], true, indices_vec4_mapping);
 				ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA);
 				ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA);
+				ERR_FAIL_COND_V(joints_0.size() != 4 * vertex_num, ERR_INVALID_DATA);
 				int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
 				int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
 				Vector<int> joints;
 				Vector<int> joints;
 				joints.resize(vertex_num * weight_8_count);
 				joints.resize(vertex_num * weight_8_count);
@@ -2866,8 +2947,9 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 				array[Mesh::ARRAY_BONES] = joints;
 				array[Mesh::ARRAY_BONES] = joints;
 			}
 			}
 			if (a.has("WEIGHTS_0") && !a.has("WEIGHTS_1")) {
 			if (a.has("WEIGHTS_0") && !a.has("WEIGHTS_1")) {
-				Vector<float> weights = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true);
-				{ //gltf does not seem to normalize the weights for some reason..
+				Vector<float> weights = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true, indices_vec4_mapping);
+				ERR_FAIL_COND_V(weights.size() != 4 * vertex_num, ERR_INVALID_DATA);
+				{ // glTF does not seem to normalize the weights for some reason.
 					int wc = weights.size();
 					int wc = weights.size();
 					float *w = weights.ptrw();
 					float *w = weights.ptrw();
 
 
@@ -2887,10 +2969,11 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 				}
 				}
 				array[Mesh::ARRAY_WEIGHTS] = weights;
 				array[Mesh::ARRAY_WEIGHTS] = weights;
 			} else if (a.has("WEIGHTS_0") && a.has("WEIGHTS_1")) {
 			} else if (a.has("WEIGHTS_0") && a.has("WEIGHTS_1")) {
-				Vector<float> weights_0 = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true);
-				Vector<float> weights_1 = _decode_accessor_as_floats(p_state, a["WEIGHTS_1"], true);
+				Vector<float> weights_0 = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true, indices_vec4_mapping);
+				Vector<float> weights_1 = _decode_accessor_as_floats(p_state, a["WEIGHTS_1"], true, indices_vec4_mapping);
 				Vector<float> weights;
 				Vector<float> weights;
 				ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA);
 				ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA);
+				ERR_FAIL_COND_V(weights_0.size() != 4 * vertex_num, ERR_INVALID_DATA);
 				int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
 				int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
 				weights.resize(vertex_num * weight_8_count);
 				weights.resize(vertex_num * weight_8_count);
 				for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) {
 				for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) {
@@ -2903,7 +2986,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 					weights.write[vertex_i * weight_8_count + 6] = weights_1[vertex_i * JOINT_GROUP_SIZE + 2];
 					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];
 					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..
+				{ // glTF does not seem to normalize the weights for some reason.
 					int wc = weights.size();
 					int wc = weights.size();
 					float *w = weights.ptrw();
 					float *w = weights.ptrw();
 
 
@@ -2932,25 +3015,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 				array[Mesh::ARRAY_WEIGHTS] = weights;
 				array[Mesh::ARRAY_WEIGHTS] = weights;
 			}
 			}
 
 
-			if (p.has("indices")) {
-				Vector<int> indices = _decode_accessor_as_ints(p_state, p["indices"], false);
-
-				if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
-					//swap around indices, convert ccw to cw for front face
-
-					const int is = indices.size();
-					int *w = indices.ptrw();
-					for (int k = 0; k < is; k += 3) {
-						SWAP(w[k + 1], w[k + 2]);
-					}
+			if (!indices.is_empty()) {
+				int *w = indices.ptrw();
+				const int is = indices.size();
+				for (int ind_i = 0; ind_i < is; ind_i++) {
+					w[ind_i] = indices_rev_mapping[indices[ind_i]];
 				}
 				}
 				array[Mesh::ARRAY_INDEX] = indices;
 				array[Mesh::ARRAY_INDEX] = indices;
 
 
 			} else if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
 			} else if (primitive == 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.
 				const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX];
 				const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX];
 				ERR_FAIL_COND_V(vertices.is_empty(), ERR_PARSE_ERROR);
 				ERR_FAIL_COND_V(vertices.is_empty(), ERR_PARSE_ERROR);
-				Vector<int> indices;
 				const int vs = vertices.size();
 				const int vs = vertices.size();
 				indices.resize(vs);
 				indices.resize(vs);
 				{
 				{
@@ -3014,13 +3090,11 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 			}
 			}
 
 
 			Array morphs;
 			Array morphs;
-			//blend shapes
+			// Blend shapes
 			if (p.has("targets")) {
 			if (p.has("targets")) {
 				print_verbose("glTF: Mesh has targets");
 				print_verbose("glTF: Mesh has targets");
 				const Array &targets = p["targets"];
 				const Array &targets = p["targets"];
 
 
-				//ideally BLEND_SHAPE_MODE_RELATIVE since gltf2 stores in displacement
-				//but it could require a larger refactor?
 				import_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
 				import_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
 
 
 				if (j == 0) {
 				if (j == 0) {
@@ -3047,7 +3121,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 					}
 					}
 
 
 					if (t.has("POSITION")) {
 					if (t.has("POSITION")) {
-						Vector<Vector3> varr = _decode_accessor_as_vec3(p_state, t["POSITION"], true);
+						Vector<Vector3> varr = _decode_accessor_as_vec3(p_state, t["POSITION"], true, indices_mapping);
 						const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
 						const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
 						const int size = src_varr.size();
 						const int size = src_varr.size();
 						ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
 						ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
@@ -3069,7 +3143,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 						array_copy[Mesh::ARRAY_VERTEX] = varr;
 						array_copy[Mesh::ARRAY_VERTEX] = varr;
 					}
 					}
 					if (t.has("NORMAL")) {
 					if (t.has("NORMAL")) {
-						Vector<Vector3> narr = _decode_accessor_as_vec3(p_state, t["NORMAL"], true);
+						Vector<Vector3> narr = _decode_accessor_as_vec3(p_state, t["NORMAL"], true, indices_mapping);
 						const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
 						const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
 						int size = src_narr.size();
 						int size = src_narr.size();
 						ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
 						ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
@@ -3091,7 +3165,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 						array_copy[Mesh::ARRAY_NORMAL] = narr;
 						array_copy[Mesh::ARRAY_NORMAL] = narr;
 					}
 					}
 					if (t.has("TANGENT")) {
 					if (t.has("TANGENT")) {
-						const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(p_state, t["TANGENT"], true);
+						const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(p_state, t["TANGENT"], true, indices_mapping);
 						const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT];
 						const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT];
 						ERR_FAIL_COND_V(src_tangents.is_empty(), ERR_PARSE_ERROR);
 						ERR_FAIL_COND_V(src_tangents.is_empty(), ERR_PARSE_ERROR);
 
 

+ 10 - 5
modules/gltf/gltf_document.h

@@ -148,19 +148,24 @@ private:
 			const bool p_for_vertex);
 			const bool p_for_vertex);
 	Vector<float> _decode_accessor_as_floats(Ref<GLTFState> p_state,
 	Vector<float> _decode_accessor_as_floats(Ref<GLTFState> p_state,
 			const GLTFAccessorIndex p_accessor,
 			const GLTFAccessorIndex p_accessor,
-			const bool p_for_vertex);
+			const bool p_for_vertex,
+			const Vector<int> &p_packed_vertex_ids = Vector<int>());
 	Vector<int> _decode_accessor_as_ints(Ref<GLTFState> p_state,
 	Vector<int> _decode_accessor_as_ints(Ref<GLTFState> p_state,
 			const GLTFAccessorIndex p_accessor,
 			const GLTFAccessorIndex p_accessor,
-			const bool p_for_vertex);
+			const bool p_for_vertex,
+			const Vector<int> &p_packed_vertex_ids = Vector<int>());
 	Vector<Vector2> _decode_accessor_as_vec2(Ref<GLTFState> p_state,
 	Vector<Vector2> _decode_accessor_as_vec2(Ref<GLTFState> p_state,
 			const GLTFAccessorIndex p_accessor,
 			const GLTFAccessorIndex p_accessor,
-			const bool p_for_vertex);
+			const bool p_for_vertex,
+			const Vector<int> &p_packed_vertex_ids = Vector<int>());
 	Vector<Vector3> _decode_accessor_as_vec3(Ref<GLTFState> p_state,
 	Vector<Vector3> _decode_accessor_as_vec3(Ref<GLTFState> p_state,
 			const GLTFAccessorIndex p_accessor,
 			const GLTFAccessorIndex p_accessor,
-			const bool p_for_vertex);
+			const bool p_for_vertex,
+			const Vector<int> &p_packed_vertex_ids = Vector<int>());
 	Vector<Color> _decode_accessor_as_color(Ref<GLTFState> p_state,
 	Vector<Color> _decode_accessor_as_color(Ref<GLTFState> p_state,
 			const GLTFAccessorIndex p_accessor,
 			const GLTFAccessorIndex p_accessor,
-			const bool p_for_vertex);
+			const bool p_for_vertex,
+			const Vector<int> &p_packed_vertex_ids = Vector<int>());
 	Vector<Quaternion> _decode_accessor_as_quaternion(Ref<GLTFState> p_state,
 	Vector<Quaternion> _decode_accessor_as_quaternion(Ref<GLTFState> p_state,
 			const GLTFAccessorIndex p_accessor,
 			const GLTFAccessorIndex p_accessor,
 			const bool p_for_vertex);
 			const bool p_for_vertex);