Skip to content

Commit 9fbc516

Browse files
authored
Merge pull request #49 from ft-lab/dev/material_dae
COLLADA (dae): Materials support
1 parent db5c38f commit 9fbc516

File tree

12 files changed

+1193
-88
lines changed

12 files changed

+1193
-88
lines changed

tests/data/assets/box_materials.dae

Lines changed: 618 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3+
<asset>
4+
<unit name="meter" meter="1"/>
5+
<up_axis>Z_UP</up_axis>
6+
</asset>
7+
<library_effects>
8+
<effect id="transparent_mat-effect">
9+
<profile_COMMON>
10+
<technique sid="common">
11+
<lambert>
12+
<emission>
13+
<color sid="emission">0 0 0 1</color>
14+
</emission>
15+
<diffuse>
16+
<color sid="diffuse">0.1 0.8 0.1 1</color>
17+
</diffuse>
18+
<transparent opaque="RGB_ZERO">
19+
<color sid="alpha">0.2 0.3 0.1 1</color>
20+
</transparent>
21+
<index_of_refraction>
22+
<float sid="ior">1.45</float>
23+
</index_of_refraction>
24+
</lambert>
25+
</technique>
26+
</profile_COMMON>
27+
</effect>
28+
</library_effects>
29+
<library_images/>
30+
<library_materials>
31+
<material id="transparent_mat-material" name="transparent_mat">
32+
<instance_effect url="#transparent_mat-effect"/>
33+
</material>
34+
</library_materials>
35+
<library_geometries>
36+
<geometry id="Cube-mesh" name="Cube">
37+
<mesh>
38+
<source id="Cube-mesh-positions">
39+
<float_array id="Cube-mesh-positions-array" count="24">1 1 1 1 1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 -1 -1 1 -1 -1 -1</float_array>
40+
<technique_common>
41+
<accessor source="#Cube-mesh-positions-array" count="8" stride="3">
42+
<param name="X" type="float"/>
43+
<param name="Y" type="float"/>
44+
<param name="Z" type="float"/>
45+
</accessor>
46+
</technique_common>
47+
</source>
48+
<source id="Cube-mesh-normals">
49+
<float_array id="Cube-mesh-normals-array" count="36">0 0 1 0 -1 0 -1 0 0 0 0 -1 1 0 0 0 1 0 0 0 1 0 -1 0 -1 0 0 0 0 -1 1 0 0 0 1 0</float_array>
50+
<technique_common>
51+
<accessor source="#Cube-mesh-normals-array" count="12" stride="3">
52+
<param name="X" type="float"/>
53+
<param name="Y" type="float"/>
54+
<param name="Z" type="float"/>
55+
</accessor>
56+
</technique_common>
57+
</source>
58+
<source id="Cube-mesh-map-0">
59+
<float_array id="Cube-mesh-map-0-array" count="72">0.875 0.5 0.625 0.75 0.625 0.5 0.625 0.75 0.375 1 0.375 0.75 0.625 0 0.375 0.25 0.375 0 0.375 0.5 0.125 0.75 0.125 0.5 0.625 0.5 0.375 0.75 0.375 0.5 0.625 0.25 0.375 0.5 0.375 0.25 0.875 0.5 0.875 0.75 0.625 0.75 0.625 0.75 0.625 1 0.375 1 0.625 0 0.625 0.25 0.375 0.25 0.375 0.5 0.375 0.75 0.125 0.75 0.625 0.5 0.625 0.75 0.375 0.75 0.625 0.25 0.625 0.5 0.375 0.5</float_array>
60+
<technique_common>
61+
<accessor source="#Cube-mesh-map-0-array" count="36" stride="2">
62+
<param name="S" type="float"/>
63+
<param name="T" type="float"/>
64+
</accessor>
65+
</technique_common>
66+
</source>
67+
<vertices id="Cube-mesh-vertices">
68+
<input semantic="POSITION" source="#Cube-mesh-positions"/>
69+
</vertices>
70+
<triangles material="transparent_mat-material" count="12">
71+
<input semantic="VERTEX" source="#Cube-mesh-vertices" offset="0"/>
72+
<input semantic="NORMAL" source="#Cube-mesh-normals" offset="1"/>
73+
<input semantic="TEXCOORD" source="#Cube-mesh-map-0" offset="2" set="0"/>
74+
<p>4 0 0 2 0 1 0 0 2 2 1 3 7 1 4 3 1 5 6 2 6 5 2 7 7 2 8 1 3 9 7 3 10 5 3 11 0 4 12 3 4 13 1 4 14 4 5 15 1 5 16 5 5 17 4 6 18 6 6 19 2 6 20 2 7 21 6 7 22 7 7 23 6 8 24 4 8 25 5 8 26 1 9 27 3 9 28 7 9 29 0 10 30 2 10 31 3 10 32 4 11 33 0 11 34 1 11 35</p>
75+
</triangles>
76+
</mesh>
77+
</geometry>
78+
</library_geometries>
79+
<library_visual_scenes>
80+
<visual_scene id="Scene" name="Scene">
81+
<node id="Cube" name="Cube" type="NODE">
82+
<matrix sid="transform">0.5 0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 0 1</matrix>
83+
<instance_geometry url="#Cube-mesh" name="Cube">
84+
<bind_material>
85+
<technique_common>
86+
<instance_material symbol="transparent_mat-material" target="#transparent_mat-material">
87+
<bind_vertex_input semantic="UVMap" input_semantic="TEXCOORD" input_set="0"/>
88+
</instance_material>
89+
</technique_common>
90+
</bind_material>
91+
</instance_geometry>
92+
</node>
93+
</visual_scene>
94+
</library_visual_scenes>
95+
<scene>
96+
<instance_visual_scene url="#Scene"/>
97+
</scene>
98+
</COLLADA>

tests/data/assets/emissive.png

1.83 KB
Loading

tests/data/dae_materials.urdf

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?xml version="1.0"?>
2+
<robot name="dae_materials">
3+
<link name="link1">
4+
<visual>
5+
<geometry>
6+
<mesh filename="assets/box_materials.dae"/>
7+
</geometry>
8+
</visual>
9+
</link>
10+
<link name="link2">
11+
<visual>
12+
<geometry>
13+
<mesh filename="assets/box_two_materials.dae"/>
14+
</geometry>
15+
</visual>
16+
</link>
17+
<link name="link_transparent">
18+
<visual>
19+
<geometry>
20+
<mesh filename="assets/box_transparent_material.dae"/>
21+
</geometry>
22+
</visual>
23+
</link>
24+
25+
<joint name="joint_link" type="fixed">
26+
<origin rpy="0 0 0" xyz="2 0 0"/>
27+
<parent link="link1"/>
28+
<child link="link2"/>
29+
</joint>
30+
<joint name="joint_link_transparent" type="fixed">
31+
<origin rpy="0 0 0" xyz="2 0 0"/>
32+
<parent link="link2"/>
33+
<child link="link_transparent"/>
34+
</joint>
35+
</robot>

tests/testMaterial.py

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,3 +550,210 @@ def test_material_mesh_override(self):
550550

551551
# Check that the material bind is overwritten with blue_material.
552552
self.check_material_binding(two_boxes_prim, blue_material)
553+
554+
def test_dae_materials(self):
555+
input_path = "tests/data/dae_materials.urdf"
556+
output_dir = self.tmpDir()
557+
558+
converter = urdf_usd_converter.Converter()
559+
asset_path = converter.convert(input_path, output_dir)
560+
561+
self.assertIsNotNone(asset_path)
562+
self.assertTrue(pathlib.Path(asset_path.path).exists())
563+
564+
stage: Usd.Stage = Usd.Stage.Open(asset_path.path)
565+
self.assertIsValidUsd(stage)
566+
567+
default_prim = stage.GetDefaultPrim()
568+
569+
# Check the materials.
570+
material_scope_prim = default_prim.GetChild("Materials")
571+
self.assertTrue(material_scope_prim.IsValid())
572+
573+
material_prim = material_scope_prim.GetChild("texture_mat")
574+
self.assertTrue(material_prim.IsValid())
575+
self.assertTrue(material_prim.IsA(UsdShade.Material))
576+
texture_material = UsdShade.Material(material_prim)
577+
578+
diffuse_color_texture_path = self.get_material_texture_path(texture_material, "diffuseColor")
579+
self.assertEqual(diffuse_color_texture_path, pathlib.Path("./Textures/grid.png"))
580+
opacity = self.get_material_opacity(texture_material)
581+
self.assertAlmostEqual(opacity, 1.0, places=6)
582+
583+
material_prim = material_scope_prim.GetChild("emissive_mat")
584+
self.assertTrue(material_prim.IsValid())
585+
self.assertTrue(material_prim.IsA(UsdShade.Material))
586+
emissive_material = UsdShade.Material(material_prim)
587+
588+
diffuse_color = self.get_material_diffuse_color(emissive_material)
589+
diffuse_color = usdex.core.linearToSrgb(diffuse_color)
590+
self.assertTrue(Gf.IsClose(diffuse_color, Gf.Vec3f(0, 0, 0), 1e-6))
591+
emissive_color = self.get_material_emissive_color(emissive_material)
592+
emissive_color = usdex.core.linearToSrgb(emissive_color)
593+
self.assertTrue(Gf.IsClose(emissive_color, Gf.Vec3f(1, 1, 0), 1e-6))
594+
opacity = self.get_material_opacity(emissive_material)
595+
self.assertAlmostEqual(opacity, 1.0, places=6)
596+
597+
material_prim = material_scope_prim.GetChild("emissive_color_tex_mat")
598+
self.assertTrue(material_prim.IsValid())
599+
self.assertTrue(material_prim.IsA(UsdShade.Material))
600+
emissive_color_tex_material = UsdShade.Material(material_prim)
601+
602+
diffuse_color = self.get_material_diffuse_color(emissive_color_tex_material)
603+
self.assertTrue(Gf.IsClose(diffuse_color, Gf.Vec3f(0, 0, 0), 1e-6))
604+
emissive_color_texture_path = self.get_material_texture_path(emissive_color_tex_material, "emissiveColor")
605+
self.assertEqual(emissive_color_texture_path, pathlib.Path("./Textures/emissive.png"))
606+
607+
material_prim = material_scope_prim.GetChild("opacity_mat")
608+
self.assertTrue(material_prim.IsValid())
609+
self.assertTrue(material_prim.IsA(UsdShade.Material))
610+
opacity_material = UsdShade.Material(material_prim)
611+
612+
diffuse_texture_path = self.get_material_texture_path(opacity_material, "diffuseColor")
613+
self.assertEqual(diffuse_texture_path, pathlib.Path("./Textures/grid.png"))
614+
opacity = self.get_material_opacity(opacity_material)
615+
self.assertAlmostEqual(opacity, 0.4, places=6)
616+
617+
material_prim = material_scope_prim.GetChild("opacity_texture_mat")
618+
self.assertTrue(material_prim.IsValid())
619+
self.assertTrue(material_prim.IsA(UsdShade.Material))
620+
opacity_texture_material = UsdShade.Material(material_prim)
621+
622+
diffuse_texture_path = self.get_material_texture_path(opacity_texture_material, "diffuseColor")
623+
self.assertEqual(diffuse_texture_path, pathlib.Path("./Textures/grid.png"))
624+
opacity_texture_path = self.get_material_texture_path(opacity_texture_material, "opacity")
625+
self.assertEqual(opacity_texture_path, pathlib.Path("./Textures/opacity.png"))
626+
627+
material_prim = material_scope_prim.GetChild("specular_mat")
628+
self.assertTrue(material_prim.IsValid())
629+
self.assertTrue(material_prim.IsA(UsdShade.Material))
630+
specular_material = UsdShade.Material(material_prim)
631+
632+
diffuse_color = self.get_material_diffuse_color(specular_material)
633+
diffuse_color = usdex.core.linearToSrgb(diffuse_color)
634+
self.assertTrue(Gf.IsClose(diffuse_color, Gf.Vec3f(0.2, 0.2, 0.2), 1e-6))
635+
specular_color = self.get_material_specular_color(specular_material)
636+
specular_color = usdex.core.linearToSrgb(specular_color)
637+
self.assertTrue(Gf.IsClose(specular_color, Gf.Vec3f(0.8, 0.7, 0.1), 1e-6))
638+
opacity = self.get_material_opacity(specular_material)
639+
self.assertAlmostEqual(opacity, 1.0, places=6)
640+
specular_workflow = self.get_material_specular_workflow(specular_material)
641+
self.assertTrue(specular_workflow)
642+
643+
material_prim = material_scope_prim.GetChild("specular_texture_mat")
644+
self.assertTrue(material_prim.IsValid())
645+
self.assertTrue(material_prim.IsA(UsdShade.Material))
646+
specular_texture_material = UsdShade.Material(material_prim)
647+
648+
diffuse_color = self.get_material_diffuse_color(specular_texture_material)
649+
diffuse_color = usdex.core.linearToSrgb(diffuse_color)
650+
self.assertTrue(Gf.IsClose(diffuse_color, Gf.Vec3f(0.2, 0.2, 0.2), 1e-6))
651+
specular_texture_path = self.get_material_texture_path(specular_texture_material, "specularColor")
652+
self.assertEqual(specular_texture_path, pathlib.Path("./Textures/specular.png"))
653+
opacity = self.get_material_opacity(specular_texture_material)
654+
self.assertAlmostEqual(opacity, 1.0, places=6)
655+
specular_workflow = self.get_material_specular_workflow(specular_texture_material)
656+
self.assertTrue(specular_workflow)
657+
658+
material_prim = material_scope_prim.GetChild("Material_red")
659+
self.assertTrue(material_prim.IsValid())
660+
self.assertTrue(material_prim.IsA(UsdShade.Material))
661+
material_red = UsdShade.Material(material_prim)
662+
663+
diffuse_color = self.get_material_diffuse_color(material_red)
664+
diffuse_color = usdex.core.linearToSrgb(diffuse_color)
665+
self.assertTrue(Gf.IsClose(diffuse_color, Gf.Vec3f(1, 0, 0), 1e-6))
666+
opacity = self.get_material_opacity(material_red)
667+
self.assertAlmostEqual(opacity, 1.0, places=6)
668+
669+
material_prim = material_scope_prim.GetChild("Material_green")
670+
self.assertTrue(material_prim.IsValid())
671+
self.assertTrue(material_prim.IsA(UsdShade.Material))
672+
material_green = UsdShade.Material(material_prim)
673+
674+
diffuse_color = self.get_material_diffuse_color(material_green)
675+
diffuse_color = usdex.core.linearToSrgb(diffuse_color)
676+
self.assertTrue(Gf.IsClose(diffuse_color, Gf.Vec3f(0, 1, 0), 1e-6))
677+
opacity = self.get_material_opacity(material_green)
678+
self.assertAlmostEqual(opacity, 1.0, places=6)
679+
680+
material_prim = material_scope_prim.GetChild("transparent_mat")
681+
self.assertTrue(material_prim.IsValid())
682+
self.assertTrue(material_prim.IsA(UsdShade.Material))
683+
material_transparent = UsdShade.Material(material_prim)
684+
685+
diffuse_color = self.get_material_diffuse_color(material_transparent)
686+
diffuse_color = usdex.core.linearToSrgb(diffuse_color)
687+
self.assertTrue(Gf.IsClose(diffuse_color, Gf.Vec3f(0.1, 0.8, 0.1), 1e-6))
688+
opacity = self.get_material_opacity(material_transparent)
689+
self.assertAlmostEqual(opacity, 0.8, places=6)
690+
691+
# Check the bindings.
692+
default_prim = stage.GetDefaultPrim()
693+
geometry_scope_prim = default_prim.GetChild("Geometry")
694+
self.assertTrue(geometry_scope_prim.IsValid())
695+
self.assertTrue(geometry_scope_prim.IsA(UsdGeom.Scope))
696+
link1_prim = geometry_scope_prim.GetChild("link1")
697+
box_materials_prim = link1_prim.GetChild("box_materials")
698+
self.assertTrue(box_materials_prim.IsValid())
699+
self.assertTrue(box_materials_prim.IsA(UsdGeom.Xform))
700+
self.assertTrue(box_materials_prim.HasAuthoredReferences())
701+
702+
cube_prim = box_materials_prim.GetChild("Cube")
703+
self.assertTrue(cube_prim.IsValid())
704+
self.assertTrue(cube_prim.IsA(UsdGeom.Mesh))
705+
self.check_material_binding(cube_prim, texture_material)
706+
707+
cube_002_prim = box_materials_prim.GetChild("tn__Cube002_VB")
708+
self.assertTrue(cube_002_prim.IsValid())
709+
self.assertTrue(cube_002_prim.IsA(UsdGeom.Mesh))
710+
self.check_material_binding(cube_002_prim, emissive_material)
711+
712+
cube_003_prim = box_materials_prim.GetChild("tn__Cube003_VB")
713+
self.assertTrue(cube_003_prim.IsValid())
714+
self.assertTrue(cube_003_prim.IsA(UsdGeom.Mesh))
715+
self.check_material_binding(cube_003_prim, emissive_color_tex_material)
716+
717+
cube_004_prim = box_materials_prim.GetChild("tn__Cube004_VB")
718+
self.assertTrue(cube_004_prim.IsValid())
719+
self.assertTrue(cube_004_prim.IsA(UsdGeom.Mesh))
720+
self.check_material_binding(cube_004_prim, opacity_material)
721+
722+
cube_005_prim = box_materials_prim.GetChild("tn__Cube005_VB")
723+
self.assertTrue(cube_005_prim.IsValid())
724+
self.assertTrue(cube_005_prim.IsA(UsdGeom.Mesh))
725+
self.check_material_binding(cube_005_prim, opacity_texture_material)
726+
727+
cube_001_prim = box_materials_prim.GetChild("tn__Cube001_VB")
728+
self.assertTrue(cube_001_prim.IsValid())
729+
self.assertTrue(cube_001_prim.IsA(UsdGeom.Mesh))
730+
self.check_material_binding(cube_001_prim, specular_material)
731+
732+
cube_006_prim = box_materials_prim.GetChild("tn__Cube006_VB")
733+
self.assertTrue(cube_006_prim.IsValid())
734+
self.assertTrue(cube_006_prim.IsA(UsdGeom.Mesh))
735+
self.check_material_binding(cube_006_prim, specular_texture_material)
736+
737+
# Check material binding to GeomSubset.
738+
link2_prim = link1_prim.GetChild("link2")
739+
box_materials_prim = link2_prim.GetChild("box_two_materials")
740+
self.assertTrue(box_materials_prim.IsValid())
741+
self.assertTrue(box_materials_prim.IsA(UsdGeom.Mesh))
742+
self.assertTrue(box_materials_prim.HasAuthoredReferences())
743+
744+
subset_001_prim = box_materials_prim.GetChild("GeomSubset_001")
745+
self.assertTrue(subset_001_prim.IsValid())
746+
self.assertTrue(subset_001_prim.IsA(UsdGeom.Subset))
747+
self.check_material_binding(subset_001_prim, material_red)
748+
749+
subset_002_prim = box_materials_prim.GetChild("GeomSubset_002")
750+
self.assertTrue(subset_002_prim.IsValid())
751+
self.assertTrue(subset_002_prim.IsA(UsdGeom.Subset))
752+
self.check_material_binding(subset_002_prim, material_green)
753+
754+
link_transparent_prim = link2_prim.GetChild("link_transparent")
755+
box_transparent_prim = link_transparent_prim.GetChild("box_transparent_material")
756+
self.assertTrue(box_transparent_prim.IsValid())
757+
self.assertTrue(box_transparent_prim.IsA(UsdGeom.Mesh))
758+
self.assertTrue(box_transparent_prim.HasAuthoredReferences())
759+
self.check_material_binding(box_transparent_prim, material_transparent)

tests/util/ConverterTestCase.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ def _get_material_input_value(self, material: UsdShade.Material, input_name: str
4141
def get_material_diffuse_color(self, material: UsdShade.Material) -> Gf.Vec3f | None:
4242
return self._get_material_input_value(material, "diffuseColor")
4343

44+
def get_material_emissive_color(self, material: UsdShade.Material) -> Gf.Vec3f | None:
45+
return self._get_material_input_value(material, "emissiveColor")
46+
4447
def get_material_specular_color(self, material: UsdShade.Material) -> Gf.Vec3f | None:
4548
return self._get_material_input_value(material, "specularColor")
4649

0 commit comments

Comments
 (0)