def test_mesh_roundtrip(self): """Check that we can save then read a textured mesh.""" mesh = TexturedMesh.example() expected_color = mesh.base_color()[0, 0, :] expected_mr = mesh.metallic_roughness()[0, 0, :] model = GltfModel.from_textured_mesh(mesh) model.save_as_gltf(self.temp_directory, "dummy") # now load... input_path = os.path.join(self.temp_directory, "dummy.gltf") model2 = GltfModel.load_from_gltf(input_path) self.assertEqual(model2.num_images(), 2) self.assertEqual(model.image_size(0), 288) self.assertEqual(model.image_size(1), 72) self.assertEqual(model.image_uri(0), "0.png") self.assertEqual(model.image_uri(1), "1.png") # ...and check mesh. mesh2 = model2.extract_textured_primitive_mesh() self.assertEqual(mesh2.num_vertices(), 24) self.assertTrue(mesh.has_dual_texture_material()) np.testing.assert_array_equal(mesh2.base_color()[0, 0, :], expected_color) np.testing.assert_array_equal(mesh2.metallic_roughness()[0, 0, :], expected_mr)
def test_glb_roundtrip(self): """Check that we can load, save, and re-load the glb.""" # 1. Read input_path = os.path.join(TEST_PATH, "blind.glb") model = GltfModel.load_from_glb(input_path) self.assertEqual(model.num_primitive_meshes(), 6) indices = model.primitive_meshes()[0].indices() self.assertEqual(model.num_images(), 4) self.assertLessEqual(np.max(indices), model.primitive_meshes()[0].num_vertices() - 1) image_props = [(model.image_size(i), model.image_uri(i)) for i in range(4)] # 2. Save output_path = os.path.join(self.temp_directory, "test.glb") model.save_as_glb(output_path) self.assert_temp_file("test.glb") # 3. Read again model2 = GltfModel.load_from_glb(output_path) self.assertEqual(model2.num_primitive_meshes(), 6) indices2 = model2.primitive_meshes()[0].indices() np.testing.assert_array_equal(indices, indices2) self.assertEqual(model2.num_images(), 4) for i, props in enumerate(image_props): size, uri = props self.assertEqual(model2.image_size(i), size) self.assertEqual(model2.image_uri(i), uri)
def example(cls): """Create a simple ProjectObjectDict.""" pose1 = Pose3() pose2 = Pose3(t=Vector3(2, 2, 0)) pose3 = Pose3(t=Vector3(4, 2, 0)) # Be explicit about unicode literal in case this code is called from python 2 data_path = parutil.get_dir_path( u"sumo/threedee/test_data") model1 = GltfModel.load_from_glb(os.path.join(data_path, "bed.glb")) model2 = GltfModel.load_from_glb(os.path.join(data_path, "bed.glb")) model3 = GltfModel.load_from_glb(os.path.join(data_path, "bed.glb")) obj1 = ProjectObject.gen_meshes_object( meshes=model1, id="1", pose=pose1, category="bed" ) obj2 = ProjectObject.gen_meshes_object( meshes=model2, id="2", pose=pose2, category="chair" ) obj3 = ProjectObject.gen_meshes_object( meshes=model3, id="3", pose=pose3, category="bed" ) project_object_dict = ProjectObjectDict() project_object_dict[obj1.id] = obj1 project_object_dict[obj2.id] = obj2 project_object_dict[obj3.id] = obj3 return project_object_dict
def test_deep_copy(self): """Check that we can copy gltf models""" input_path = os.path.join(TEST_PATH, "bed.glb") model = GltfModel.load_from_glb(input_path) model2 = model.deepcopy() self.assertEqual(model.num_primitive_meshes(), model2.num_primitive_meshes()) model = GltfModel.example() self.assertNotEqual(model.num_primitive_meshes(), model2.num_primitive_meshes())
def test_save_as_gltf2(self): """Test for material properties round trip.""" input_path = os.path.join(TEST_PATH, "bed.glb") model = GltfModel.load_from_glb(input_path) mesh = model.extract_textured_primitive_mesh() model2 = GltfModel.from_textured_mesh(mesh) model2.save_as_gltf(self.temp_directory, "test") gltf_path = os.path.join(self.temp_directory, "test.gltf") self.assertTrue(os.path.isfile(gltf_path)) model3 = GltfModel.load_from_gltf(gltf_path) mesh3 = model3.extract_textured_primitive_mesh() self.assertTrue(mesh3.has_same_material(mesh))
def test_from_gltf_model(self): """Verify bounding box computed from a GltfModel.""" object = GltfModel.example() box = ComputeBbox().from_gltf_object(object) np.testing.assert_array_equal(box.min_corner, Vector3(-1, -1, -1)) np.testing.assert_array_equal(box.max_corner, Vector3(1, 1, 1))
def test_save_as_glb(self): """Check that we can save a GltfModel instance to glb.""" model = GltfModel.example() path = os.path.join(self.temp_directory, "example.glb") model.save_as_glb(path) # Check the existence of glb self.assert_temp_file("example.glb")
def test_load_textured_mesh(self): """Check that we can load a textured mesh from a gltf file.""" input_path = os.path.join(TEST_PATH, "Cube.gltf") model = GltfModel.load_from_gltf(input_path) mesh = model.extract_textured_primitive_mesh() self.assertIsInstance(mesh, TexturedMesh) self.assertEqual(mesh.num_vertices(), 36) self.assertTrue(mesh.has_dual_texture_material())
def test_save_textured_mesh_as_glb(self): """Check that we can save a textured mesh directly to glb.""" mesh = TexturedMesh.example() model = GltfModel.from_textured_mesh(mesh) path = os.path.join(self.temp_directory, "dummy.glb") model.save_as_glb(path) # Check the existence of glb self.assertTrue(os.path.isfile(path))
def load(cls, project_type, base_elem, path=None): """ Factory method to create a ProjectObject by reading it from disk and xml. Note: If <project_type> is bounding_box, no file is read and <path> is not relevant. Inputs: project_type (string) - Specifies the project type to construct (valid values are "bounding_box", "voxels", or "meshes") base_elem (ET.Element) - An Element with tag "element" and appropriate sub-elements. path (string) - path to project directory (only required if project_type is voxels or mesh). Return: New ProjectObject Exceptions: ValueError - If base_elem is not <element> or if none of its children is <id>. ValueError - If project_type is not valid. IOError - if file cannot be read. """ (id, pose, category, bounds, symmetry, score, evaluated) = \ cls._parse_xml(base_elem) # load file-based attributes and return the constructed object if project_type == "bounding_box": return ProjectObject.gen_bounding_box_object(id=id, bounds=bounds, pose=pose, category=category, symmetry=symmetry, score=score, evaluated=evaluated) elif project_type == "voxels": voxels = VoxelGrid.from_file(os.path.join(path, id + ".h5")) return ProjectObject.gen_voxels_object(id=id, bounds=bounds, voxels=voxels, pose=pose, category=category, symmetry=symmetry, score=score, evaluated=evaluated) elif project_type == "meshes": meshes = GltfModel.load_from_glb(os.path.join(path, id + ".glb")) return ProjectObject.gen_meshes_object(id=id, bounds=bounds, meshes=meshes, pose=pose, category=category, symmetry=symmetry, score=score, evaluated=evaluated) else: raise ValueError("Invalid project_type: " + project_type)
def test_save(self): """Check that we can save a GltfModel instance to gltf + files.""" model = GltfModel.example() model.save_as_gltf(self.temp_directory, "example") # Check the existence of gltf self.assert_temp_file("example.gltf") self.assert_temp_file("example.bin") self.assert_temp_file("0.png") self.assert_temp_file("1.png")
def test_update_textured_material(self): mesh = TexturedMesh.example() model = GltfModel.from_textured_mesh(mesh) self.assertEqual(model.num_images(), 2) uri = "Cube_BaseColor.png" base_dir = TEST_PATH material = {"color": Vector3(0, 0, 0), "uri": uri} model.update_materials(base_dir, [material]) self.assertEqual(model.num_images(), 3)
def test_meshes(self): """Check that we can retrieve all meshes in an object.""" input_path = os.path.join(TEST_PATH, "Cube.gltf") model = GltfModel.load_from_gltf(input_path) self.assertEqual(model.num_primitive_meshes(), 1) meshes = model.primitive_meshes() self.assertEqual(len(meshes), 1) self.assertIsInstance(meshes[0], TexturedMesh) self.assertEqual(meshes[0].num_vertices(), 36)
def test_add_mesh(self): """Test python wrapper to go from TexturedMesh to GltfModel.""" model = GltfModel() mesh = TexturedMesh.example() model.add_textured_primitive_mesh(mesh) self.assertEqual(model.num_primitive_meshes(), 1) self.assertEqual(model.num_nodes(), 1) self.assertEqual(model.num_buffers(), 1)
def test_add_colored_material(self): mesh = TexturedMesh.example() model = GltfModel.from_textured_mesh(mesh) index = model.add_colored_material("my_material", Vector3f(0.5, 0.5, 0.5), 0.0, 0.95) self.assertEqual(index, 1) index = model.add_colored_material("another_material", Vector3f(0.75, 0.75, 0.75), 0.1, 0.7) self.assertEqual(index, 2)
def test_minimal(self): """ Check that we can create and save a minimal object. Loading, however, does not work as no scene is defined by default constructor. """ obj = GltfModel() filename = os.path.join(self.temp_directory, "Minimal.gltf") self.tiny.write_gltf_scene_to_file(obj, filename) with self.assertRaises(IOError): self.tiny.load_ascii_from_file(filename)
def test_load_gltf(self): """Check that loading from gltf loads images.""" input_path = os.path.join(TEST_PATH, "Cube.gltf") model = GltfModel.load_from_gltf(input_path) self.assertEqual(model.num_primitive_meshes(), 1) self.assertEqual(model.num_images(), 2) expected_size = 512 * 512 self.assertEqual(model.image_size(0), expected_size * 4) self.assertEqual(model.image_size(1), expected_size * 3) self.assertEqual(model.image_uri(0), "Cube_BaseColor.png") self.assertEqual(model.image_uri(1), "Cube_MetallicRoughness.png")
def test_meshes_no_base_color(self): """Check we can load a glb which has meshes without base color""" input_path = os.path.join(TEST_PATH, "blind.glb") model = GltfModel.load_from_glb(input_path) self.assertEqual(model.num_primitive_meshes(), 6) meshes = model.primitive_meshes() self.assertEqual(len(meshes), 6) for i in [0, 1, 3, 4]: self.assertIsInstance(meshes[i], TexturedMesh) for i in [2, 5]: self.assertIsInstance(meshes[i], Mesh)
def example(cls, id="1"): """Create a simple ProjectObject of project_type = meshes.""" meshes = GltfModel.example() pose = Pose3(t=Vector3(1, 2, 3)) symmetry = ObjectSymmetry.example() return cls.gen_meshes_object(id=id, pose=pose, category="chair", meshes=meshes, symmetry=symmetry, score=0.57)
def test_min_samples(self): """ Test to ensure that with low sampling density, the algorithm still produces at least one sample per face. """ input_path = os.path.join(TEST_PATH, "bed.glb") model = GltfModel.load_from_glb(input_path) sampler = ModelSampler(sampling_density=1) samples = sampler.run(model) self.assertEqual(samples.shape[1], 6) self.assertTrue(samples.shape[0] > 0)
def test_model_sampler(self): """ Test to make sure that the algorithm runs and produces some output. It is difficult to check the validity of the output, so we have some code that will allow to manually visual """ input_path = os.path.join(TEST_PATH, "bed.glb") model = GltfModel.load_from_glb(input_path) sampler = ModelSampler() samples = sampler.run(model) self.assertEqual(samples.shape[1], 6) self.assertTrue(samples.shape[0] > 0)
def test_meshes_multiple_primitives(self): """Check we can load glb which has multiple primitives.""" input_path = os.path.join(TEST_PATH, "bed.glb") model = GltfModel.load_from_glb(input_path) self.assertEqual(model.num_primitive_meshes(), 3) meshes = model.primitive_meshes() self.assertEqual(len(meshes), 3) indices = [3672, 324, 1032] for i in range(3): self.assertEqual(meshes[0].num_vertices(), 1189) self.assertIsInstance(meshes[i], Mesh) self.assertTrue(meshes[i].is_textured()) self.assertIsInstance(meshes[i], TexturedMesh) self.assertEqual(meshes[i].num_indices(), indices[i])
def test_voxelizer(self): """ Test to make sure that the algorithm runs and produces some output. It is difficult to check the validity of the output, so we have some code that will allow to manually visual """ input_path = os.path.join(TEST_PATH, "bed.glb") model = GltfModel.load_from_glb(input_path) voxelizer = Voxelizer() voxels = voxelizer.run(model) centers = voxels.voxel_centers() self.assertEqual(centers.shape[1], 3) self.assertTrue(centers.shape[0] > 0)
def test_meshes2(self): """Check that we can retrieve all meshes in an object, multiple meshes.""" input_path = os.path.join(TEST_PATH, "bed.glb") model = GltfModel.load_from_glb(input_path) self.assertEqual(model.num_primitive_meshes(), 3) meshes = model.primitive_meshes() self.assertEqual(len(meshes), 3) self.assertEqual(meshes[0].num_vertices(), 1189) self.assertLessEqual(np.max(meshes[0].indices()), meshes[0].num_vertices() - 1) for i in range(3): self.assertIsInstance(meshes[i], Mesh) for i in range(3): self.assertTrue(meshes[i].is_textured()) self.assertIsInstance(meshes[i], TexturedMesh)
def test_all_mesh_materials(self): """Round trip with model having multiple textured, non-textured meshes""" input_path = os.path.join(TEST_PATH, "blind.glb") model = GltfModel.load_from_glb(input_path) meshes = model.primitive_meshes() model2 = GltfModel() for mesh in meshes: model2.add_mesh(mesh) meshes2 = model2.primitive_meshes() self.assertEqual(len(meshes2), 6) model2.save_as_gltf(self.temp_directory, "test") gltf_path = os.path.join(self.temp_directory, "test.gltf") self.assertTrue(os.path.isfile(gltf_path)) model3 = GltfModel.load_from_gltf(gltf_path) meshes3 = model3.primitive_meshes() self.assertTrue(len(meshes) == len(meshes3)) for i in range(len(meshes)): self.assertTrue(meshes3[i].has_same_material(meshes[i]))
def test_load_glb(self): """ Test glb loading. Just ensures loading returns success and that some fields are correct. """ input_path = os.path.join(TEST_PATH, "bed.glb") model = GltfModel.load_from_glb(input_path) # note: these values were manually checked against the text part of # the glb file. The sizes are regression tests. self.assertEqual(model.num_primitive_meshes(), 3) self.assertEqual(model.num_images(), 3) self.assertEqual(model.image_size(0), 196608) self.assertEqual(model.image_size(1), 196608) # Note: The fact that these URIs are empty after reading from a glb # means that we have to make up URI's when creating a glb. self.assertEqual(model.image_uri(0), "0.png") self.assertEqual(model.image_uri(1), "1.png")
def setUp(self): # create sample bounding box, meshes, and voxel grid objects self.bounds = Box3d([-1.5, -2.2, 3], [4, 4.1, 6.5]) textured_mesh = self.bounds.to_textured_mesh() self.meshes = GltfModel.from_textured_mesh(textured_mesh) points = np.array([[0.1, 0.1, 0.1], [1.1, 1.1, 1.1], [1.3, 1.2, 1.4]]) self.voxels = VoxelGrid(0.5, min_corner=Vector3f(0, 0, 0), points=points) # and pose rot = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]], dtype=float) trans = Vector3f(1, 1, 1) self.pose = Pose3(rot, trans) # Create temporary outout directory. self.temp_directory = tempfile.mkdtemp()
def test_example(self): """Test example class method.""" model = GltfModel.example() self.assertEqual(model.num_primitive_meshes(), 1) self.assertEqual(model.num_nodes(), 1) self.assertEqual(model.num_buffers(), 1)
def test_update_material(self): mesh = TexturedMesh.example() model = GltfModel.from_textured_mesh(mesh) material = {"color": Vector3(0.5, 0.5, 0.5), "uri": ""} model.update_materials("", [material])