2
0
Эх сурвалжийг харах

Merge pull request #44305 from RevoluPowered/fbx-update-plugin

[fbx] Implement ColorIndex for Vertex Colors to ensure they are correct and duplicate vertexes correctly for multiple color attributes.
Rémi Verschelde 4 жил өмнө
parent
commit
65c1db3131

+ 80 - 12
modules/fbx/data/fbx_mesh_data.cpp

@@ -172,13 +172,14 @@ MeshInstance *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDo
 			&collect_all,
 			HashMap<int, Vector2>());
 
-	HashMap<int, Color> colors = extract_per_vertex_data(
+	HashMap<int, Color> colors;
+	HashMap<int, HashMap<int, Color> > colors_raw = extract_per_vertex_data(
 			vertices.size(),
 			mesh_geometry->get_edge_map(),
 			polygon_indices,
 			mesh_geometry->get_colors(),
-			&collect_first,
-			Color());
+			&collect_all,
+			HashMap<int, Color>());
 
 	// TODO what about tangents?
 	// TODO what about bi-nomials?
@@ -209,15 +210,21 @@ MeshInstance *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDo
 			colors,
 			morphs,
 			normals_raw,
+			colors_raw,
 			uvs_0_raw,
 			uvs_1_raw);
 
+	const int color_count = colors.size();
+	print_verbose("Vertex color count: " + itos(color_count));
+
 	// Make sure that from this moment on the mesh_geometry is no used anymore.
 	// This is a safety step, because the mesh_geometry data are no more valid
 	// at this point.
 
 	const int vertex_count = vertices.size();
 
+	print_verbose("Vertex count: " + itos(vertex_count));
+
 	// The map key is the material allocator id that is also used as surface id.
 	HashMap<SurfaceId, SurfaceData> surfaces;
 
@@ -267,7 +274,7 @@ MeshInstance *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDo
 		for (size_t polygon_vertex = 0; polygon_vertex < polygon_indices.size(); polygon_vertex += 1) {
 			if (is_start_of_polygon(polygon_indices, polygon_vertex)) {
 				polygon_index += 1;
-				ERR_FAIL_COND_V_MSG(polygon_surfaces.has(polygon_index) == false, nullptr, "The FBX file is currupted, This surface_index is not expected.");
+				ERR_FAIL_COND_V_MSG(polygon_surfaces.has(polygon_index) == false, nullptr, "The FBX file is corrupted, This surface_index is not expected.");
 				surface_id = polygon_surfaces[polygon_index];
 				surface_data = surfaces.getptr(surface_id);
 				CRASH_COND(surface_data == nullptr); // Can't be null.
@@ -385,7 +392,10 @@ MeshInstance *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDo
 	for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) {
 		SurfaceData *surface = surfaces.getptr(*surface_id);
 
-		surface->surface_tool->generate_tangents();
+		// you can't generate them without a valid uv map.
+		if (uvs_0_raw.size() > 0) {
+			surface->surface_tool->generate_tangents();
+		}
 
 		mesh->add_surface_from_arrays(
 				Mesh::PRIMITIVE_TRIANGLES,
@@ -496,6 +506,7 @@ void FBXMeshData::reorganize_vertices(
 		HashMap<int, Color> &r_color,
 		HashMap<String, MorphVertexData> &r_morphs,
 		HashMap<int, HashMap<int, Vector3> > &r_normals_raw,
+		HashMap<int, HashMap<int, Color> > &r_colors_raw,
 		HashMap<int, HashMap<int, Vector2> > &r_uv_1_raw,
 		HashMap<int, HashMap<int, Vector2> > &r_uv_2_raw) {
 
@@ -513,6 +524,7 @@ void FBXMeshData::reorganize_vertices(
 		Vector2 this_vert_poly_uv1 = Vector2();
 		Vector2 this_vert_poly_uv2 = Vector2();
 		Vector3 this_vert_poly_normal = Vector3();
+		Color this_vert_poly_color = Color();
 
 		// Take the normal and see if we need to duplicate this polygon.
 		if (r_normals_raw.has(index)) {
@@ -548,6 +560,41 @@ void FBXMeshData::reorganize_vertices(
 			}
 		}
 
+		// TODO: make me vertex color
+		// Take the normal and see if we need to duplicate this polygon.
+		if (r_colors_raw.has(index)) {
+			const HashMap<PolygonId, Color> *color_arr = r_colors_raw.getptr(index);
+
+			if (color_arr->has(polygon_index)) {
+				this_vert_poly_color = color_arr->get(polygon_index);
+			} else if (color_arr->has(-1)) {
+				this_vert_poly_color = color_arr->get(-1);
+			} else {
+				print_error("invalid color detected: " + itos(index) + " polygon index: " + itos(polygon_index));
+				for (const PolygonId *pid = color_arr->next(nullptr); pid != nullptr; pid = color_arr->next(pid)) {
+					print_verbose("debug contents key: " + itos(*pid));
+
+					if (color_arr->has(*pid)) {
+						print_verbose("contents valid: " + color_arr->get(*pid));
+					}
+				}
+			}
+
+			// Now, check if we need to duplicate it.
+			for (const PolygonId *pid = color_arr->next(nullptr); pid != nullptr; pid = color_arr->next(pid)) {
+				if (*pid == polygon_index) {
+					continue;
+				}
+
+				const Color vert_poly_color = *color_arr->getptr(*pid);
+				if (!this_vert_poly_color.is_equal_approx(vert_poly_color)) {
+					// Yes this polygon need duplication.
+					need_duplication = true;
+					break;
+				}
+			}
+		}
+
 		// Take the UV1 and UV2 and see if we need to duplicate this polygon.
 		{
 			HashMap<int, HashMap<int, Vector2> > *uv_raw = &r_uv_1_raw;
@@ -599,6 +646,7 @@ void FBXMeshData::reorganize_vertices(
 					bool same_uv1 = false;
 					bool same_uv2 = false;
 					bool same_normal = false;
+					bool same_color = false;
 
 					if (r_uv_1.has(new_vertex)) {
 						if ((this_vert_poly_uv1 - (*r_uv_1.getptr(new_vertex))).length_squared() <= CMP_EPSILON) {
@@ -612,13 +660,19 @@ void FBXMeshData::reorganize_vertices(
 						}
 					}
 
+					if (r_color.has(new_vertex)) {
+						if (this_vert_poly_color.is_equal_approx((*r_color.getptr(new_vertex)))) {
+							same_color = true;
+						}
+					}
+
 					if (r_normals.has(new_vertex)) {
 						if ((this_vert_poly_normal - (*r_normals.getptr(new_vertex))).length_squared() <= CMP_EPSILON) {
 							same_uv2 = true;
 						}
 					}
 
-					if (same_uv1 && same_uv2 && same_normal) {
+					if (same_uv1 && same_uv2 && same_normal && same_color) {
 						similar_vertex = new_vertex;
 						break;
 					}
@@ -636,6 +690,8 @@ void FBXMeshData::reorganize_vertices(
 			}
 		}
 
+		need_duplication = false;
+
 		if (need_duplication) {
 			const Vertex old_index = index;
 			const Vertex new_index = r_vertices.size();
@@ -657,6 +713,13 @@ void FBXMeshData::reorganize_vertices(
 				r_normals_raw[new_index][polygon_index] = this_vert_poly_normal;
 			}
 
+			// Vertex Color
+			if (r_colors_raw.has(old_index)) {
+				r_color.set(new_index, this_vert_poly_color);
+				r_colors_raw.getptr(old_index)->erase(polygon_index);
+				r_colors_raw[new_index][polygon_index] = this_vert_poly_color;
+			}
+
 			// UV 0
 			if (r_uv_1_raw.has(old_index)) {
 				r_uv_1.set(new_index, this_vert_poly_uv1);
@@ -671,11 +734,6 @@ void FBXMeshData::reorganize_vertices(
 				r_uv_2_raw[new_index][polygon_index] = this_vert_poly_uv2;
 			}
 
-			// Vertex color.
-			if (r_color.has(old_index)) {
-				r_color[new_index] = r_color[old_index];
-			}
-
 			// Morphs
 			for (const String *mname = r_morphs.next(nullptr); mname != nullptr; mname = r_morphs.next(mname)) {
 				MorphVertexData *d = r_morphs.getptr(*mname);
@@ -700,6 +758,10 @@ void FBXMeshData::reorganize_vertices(
 				r_normals.set(index, this_vert_poly_normal);
 			}
 
+			if (r_colors_raw.has(index) && r_color.has(index) == false) {
+				r_color.set(index, this_vert_poly_color);
+			}
+
 			if (r_uv_1_raw.has(index) &&
 					r_uv_1.has(index) == false) {
 				r_uv_1.set(index, this_vert_poly_uv1);
@@ -1010,8 +1072,14 @@ HashMap<int, R> FBXMeshData::extract_per_vertex_data(
 	 * data size is 96 (contains uv coordinates)
 	 * this means index is simple data reduction basically
 	 */
+	////
+	if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0) {
+		print_verbose("debug count: index size: " + itos(p_mapping_data.index.size()) + ", data size: " + itos(p_mapping_data.data.size()));
+		print_verbose("vertex indices count: " + itos(p_mesh_indices.size()));
+		print_verbose("Edge map size: " + itos(p_edge_map.size()));
+	}
 
-	ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0, (HashMap<int, R>()), "FBX file is missing indexing array");
+	ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0, (HashMap<int, R>()), "FBX importer needs to map correctly to this field, please specify the override index name to fix this problem!");
 	ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index && p_mapping_data.index.size() == 0, (HashMap<int, R>()), "The FBX seems corrupted");
 
 	// Aggregate vertex data.

+ 1 - 0
modules/fbx/data/fbx_mesh_data.h

@@ -108,6 +108,7 @@ private:
 			HashMap<int, Color> &r_color,
 			HashMap<String, MorphVertexData> &r_morphs,
 			HashMap<int, HashMap<int, Vector3> > &r_normals_raw,
+			HashMap<int, HashMap<int, Color> > &r_colors_raw,
 			HashMap<int, HashMap<int, Vector2> > &r_uv_1_raw,
 			HashMap<int, HashMap<int, Vector2> > &r_uv_2_raw);
 

+ 39 - 3
modules/fbx/fbx_parser/FBXMeshGeometry.cpp

@@ -211,7 +211,33 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str
 				} else if (layer_type_name == "LayerElementNormal") {
 					m_normals = resolve_vertex_data_array<Vector3>(layer_scope, MappingInformationType, ReferenceInformationType, "Normals");
 				} else if (layer_type_name == "LayerElementColor") {
-					m_colors = resolve_vertex_data_array<Color>(layer_scope, MappingInformationType, ReferenceInformationType, "Colors");
+					m_colors = resolve_vertex_data_array<Color>(layer_scope, MappingInformationType, ReferenceInformationType, "Colors", "ColorIndex");
+					// NOTE: this is a useful sanity check to ensure you're getting any color data which is not default.
+					//					const Color first_color_check = m_colors.data[0];
+					//					bool colors_are_all_the_same = true;
+					//					size_t i = 1;
+					//					for(i = 1; i < m_colors.data.size(); i++)
+					//					{
+					//						const Color current_color = m_colors.data[i];
+					//						if(current_color.is_equal_approx(first_color_check))
+					//						{
+					//							continue;
+					//						}
+					//						else
+					//						{
+					//							colors_are_all_the_same = false;
+					//							break;
+					//						}
+					//					}
+					//
+					//					if(colors_are_all_the_same)
+					//					{
+					//						print_error("Color serialisation is not working for vertex colors some should be different in the test asset.");
+					//					}
+					//					else
+					//					{
+					//						print_verbose("Color array has unique colors at index: " + itos(i));
+					//					}
 				}
 			}
 		}
@@ -335,12 +361,22 @@ MeshGeometry::MappingData<T> MeshGeometry::resolve_vertex_data_array(
 		const ScopePtr source,
 		const std::string &MappingInformationType,
 		const std::string &ReferenceInformationType,
-		const std::string &dataElementName) {
+		const std::string &dataElementName,
+		const std::string &indexOverride) {
 
 	ERR_FAIL_COND_V_MSG(source == nullptr, MappingData<T>(), "Invalid scope operator preventing memory corruption");
 
 	// UVIndex, MaterialIndex, NormalIndex, etc..
-	std::string indexDataElementName = dataElementName + "Index";
+	std::string indexDataElementName;
+
+	if (indexOverride != "") {
+		// Colors should become ColorIndex
+		indexDataElementName = indexOverride;
+	} else {
+		// Some indexes will exist.
+		indexDataElementName = dataElementName + "Index";
+	}
+
 	// goal: expand everything to be per vertex
 
 	ReferenceType l_ref_type = ReferenceType::direct;

+ 2 - 1
modules/fbx/fbx_parser/FBXMeshGeometry.h

@@ -207,7 +207,8 @@ private:
 			const ScopePtr source,
 			const std::string &MappingInformationType,
 			const std::string &ReferenceInformationType,
-			const std::string &dataElementName);
+			const std::string &dataElementName,
+			const std::string &indexOverride = "");
 };
 
 /*