Spaces:
mashroo
/
Running on Zero

YoussefAnso commited on
Commit
3a77493
·
1 Parent(s): 4bc1108

Refactor GLTF export in Mesh class to streamline buffer views and accessors. Enhance texture handling and ensure proper integration of vertex attributes, improving overall GLB file generation.

Browse files
Files changed (1) hide show
  1. mesh.py +59 -124
mesh.py CHANGED
@@ -595,13 +595,12 @@ class Mesh:
595
  Args:
596
  path (str): path to write.
597
  """
 
598
 
599
  # assert self.v.shape[0] == self.vn.shape[0] and self.v.shape[0] == self.vt.shape[0]
600
  if self.vt is not None and self.v.shape[0] != self.vt.shape[0]:
601
  self.align_v_to_vt()
602
 
603
- import pygltflib
604
-
605
  f_np = self.f.detach().cpu().numpy().astype(np.uint32)
606
  f_np_blob = f_np.flatten().tobytes()
607
 
@@ -615,13 +614,53 @@ class Mesh:
615
  attributes = pygltflib.Attributes(POSITION=1)
616
  accessor_count = 2 # Start after position (0) and indices (1)
617
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
618
  # Add vertex colors if they exist
619
  if self.vc is not None:
620
  vc_np = self.vc.detach().cpu().numpy().astype(np.float32)
621
  vc_np_blob = vc_np.tobytes()
622
 
623
  # Add vertex color buffer view
624
- gltf.bufferViews.append(
625
  pygltflib.BufferView(
626
  buffer=0,
627
  byteOffset=byteOffset,
@@ -632,7 +671,7 @@ class Mesh:
632
  )
633
 
634
  # Add vertex color accessor
635
- gltf.accessors.append(
636
  pygltflib.Accessor(
637
  bufferView=accessor_count,
638
  componentType=pygltflib.FLOAT,
@@ -650,7 +689,7 @@ class Mesh:
650
  blob += vc_np_blob
651
  byteOffset += len(vc_np_blob)
652
 
653
- # base mesh
654
  gltf = pygltflib.GLTF2(
655
  scene=0,
656
  scenes=[pygltflib.Scene(nodes=[0])],
@@ -659,46 +698,9 @@ class Mesh:
659
  attributes=attributes,
660
  indices=0,
661
  )])],
662
- buffers=[
663
- pygltflib.Buffer(byteLength=byteOffset)
664
- ],
665
- # buffer view (based on dtype)
666
- bufferViews=[
667
- # triangles; as flatten (element) array
668
- pygltflib.BufferView(
669
- buffer=0,
670
- byteLength=len(f_np_blob),
671
- target=pygltflib.ELEMENT_ARRAY_BUFFER,
672
- ),
673
- # positions; as vec3 array
674
- pygltflib.BufferView(
675
- buffer=0,
676
- byteOffset=len(f_np_blob),
677
- byteLength=len(v_np_blob),
678
- byteStride=12, # vec3
679
- target=pygltflib.ARRAY_BUFFER,
680
- ),
681
- ],
682
- accessors=[
683
- # 0 = triangles
684
- pygltflib.Accessor(
685
- bufferView=0,
686
- componentType=pygltflib.UNSIGNED_INT,
687
- count=f_np.size,
688
- type=pygltflib.SCALAR,
689
- max=[int(f_np.max())],
690
- min=[int(f_np.min())],
691
- ),
692
- # 1 = positions
693
- pygltflib.Accessor(
694
- bufferView=1,
695
- componentType=pygltflib.FLOAT,
696
- count=len(v_np),
697
- type=pygltflib.VEC3,
698
- max=v_np.max(axis=0).tolist(),
699
- min=v_np.min(axis=0).tolist(),
700
- ),
701
- ],
702
  )
703
 
704
  # Add material for vertex colors
@@ -715,53 +717,26 @@ class Mesh:
715
  ))
716
  gltf.meshes[0].primitives[0].material = 0
717
 
718
- # append texture info
719
  if self.vt is not None:
720
-
721
  vt_np = self.vt.detach().cpu().numpy().astype(np.float32)
722
  vt_np_blob = vt_np.tobytes()
723
 
724
- albedo = self.albedo.detach().cpu().numpy()
725
- albedo = (albedo * 255).astype(np.uint8)
726
- albedo = cv2.cvtColor(albedo, cv2.COLOR_RGB2BGR)
727
- albedo_blob = cv2.imencode('.png', albedo)[1].tobytes()
728
-
729
- # update primitive
730
- gltf.meshes[0].primitives[0].attributes.TEXCOORD_0 = 2
731
- gltf.meshes[0].primitives[0].material = 0
732
-
733
- # update materials
734
- gltf.materials.append(pygltflib.Material(
735
- pbrMetallicRoughness=pygltflib.PbrMetallicRoughness(
736
- baseColorTexture=pygltflib.TextureInfo(index=0, texCoord=0),
737
- metallicFactor=0.0,
738
- roughnessFactor=1.0,
739
- ),
740
- alphaMode=pygltflib.OPAQUE,
741
- alphaCutoff=None,
742
- doubleSided=True,
743
- ))
744
-
745
- gltf.textures.append(pygltflib.Texture(sampler=0, source=0))
746
- gltf.samplers.append(pygltflib.Sampler(magFilter=pygltflib.LINEAR, minFilter=pygltflib.LINEAR_MIPMAP_LINEAR, wrapS=pygltflib.REPEAT, wrapT=pygltflib.REPEAT))
747
- gltf.images.append(pygltflib.Image(bufferView=3, mimeType="image/png"))
748
-
749
- # update buffers
750
  gltf.bufferViews.append(
751
- # index = 2, texcoords; as vec2 array
752
  pygltflib.BufferView(
753
  buffer=0,
754
  byteOffset=byteOffset,
755
  byteLength=len(vt_np_blob),
756
- byteStride=8, # vec2
757
  target=pygltflib.ARRAY_BUFFER,
758
  )
759
  )
760
 
 
761
  gltf.accessors.append(
762
- # 2 = texcoords
763
  pygltflib.Accessor(
764
- bufferView=2,
765
  componentType=pygltflib.FLOAT,
766
  count=len(vt_np),
767
  type=pygltflib.VEC2,
@@ -770,59 +745,19 @@ class Mesh:
770
  )
771
  )
772
 
773
- blob += vt_np_blob
774
- byteOffset += len(vt_np_blob)
775
-
776
- gltf.bufferViews.append(
777
- # index = 3, albedo texture; as none target
778
- pygltflib.BufferView(
779
- buffer=0,
780
- byteOffset=byteOffset,
781
- byteLength=len(albedo_blob),
782
- )
783
- )
784
 
785
- blob += albedo_blob
786
- byteOffset += len(albedo_blob)
787
 
 
788
  gltf.buffers[0].byteLength = byteOffset
789
 
790
- # append metllic roughness
791
- if self.metallicRoughness is not None:
792
- metallicRoughness = self.metallicRoughness.detach().cpu().numpy()
793
- metallicRoughness = (metallicRoughness * 255).astype(np.uint8)
794
- metallicRoughness = cv2.cvtColor(metallicRoughness, cv2.COLOR_RGB2BGR)
795
- metallicRoughness_blob = cv2.imencode('.png', metallicRoughness)[1].tobytes()
796
-
797
- # update texture definition
798
- gltf.materials[0].pbrMetallicRoughness.metallicFactor = 1.0
799
- gltf.materials[0].pbrMetallicRoughness.roughnessFactor = 1.0
800
- gltf.materials[0].pbrMetallicRoughness.metallicRoughnessTexture = pygltflib.TextureInfo(index=1, texCoord=0)
801
-
802
- gltf.textures.append(pygltflib.Texture(sampler=1, source=1))
803
- gltf.samplers.append(pygltflib.Sampler(magFilter=pygltflib.LINEAR, minFilter=pygltflib.LINEAR_MIPMAP_LINEAR, wrapS=pygltflib.REPEAT, wrapT=pygltflib.REPEAT))
804
- gltf.images.append(pygltflib.Image(bufferView=4, mimeType="image/png"))
805
-
806
- # update buffers
807
- gltf.bufferViews.append(
808
- # index = 4, metallicRoughness texture; as none target
809
- pygltflib.BufferView(
810
- buffer=0,
811
- byteOffset=byteOffset,
812
- byteLength=len(metallicRoughness_blob),
813
- )
814
- )
815
-
816
- blob += metallicRoughness_blob
817
- byteOffset += len(metallicRoughness_blob)
818
-
819
- gltf.buffers[0].byteLength = byteOffset
820
-
821
-
822
- # set actual data
823
  gltf.set_binary_blob(blob)
824
 
825
- # glb = b"".join(gltf.save_to_bytes())
826
  gltf.save(path)
827
 
828
 
 
595
  Args:
596
  path (str): path to write.
597
  """
598
+ import pygltflib
599
 
600
  # assert self.v.shape[0] == self.vn.shape[0] and self.v.shape[0] == self.vt.shape[0]
601
  if self.vt is not None and self.v.shape[0] != self.vt.shape[0]:
602
  self.align_v_to_vt()
603
 
 
 
604
  f_np = self.f.detach().cpu().numpy().astype(np.uint32)
605
  f_np_blob = f_np.flatten().tobytes()
606
 
 
614
  attributes = pygltflib.Attributes(POSITION=1)
615
  accessor_count = 2 # Start after position (0) and indices (1)
616
 
617
+ # Initialize buffer views list
618
+ buffer_views = [
619
+ # triangles; as flatten (element) array
620
+ pygltflib.BufferView(
621
+ buffer=0,
622
+ byteLength=len(f_np_blob),
623
+ target=pygltflib.ELEMENT_ARRAY_BUFFER,
624
+ ),
625
+ # positions; as vec3 array
626
+ pygltflib.BufferView(
627
+ buffer=0,
628
+ byteOffset=len(f_np_blob),
629
+ byteLength=len(v_np_blob),
630
+ byteStride=12, # vec3
631
+ target=pygltflib.ARRAY_BUFFER,
632
+ ),
633
+ ]
634
+
635
+ # Initialize accessors list
636
+ accessors = [
637
+ # 0 = triangles
638
+ pygltflib.Accessor(
639
+ bufferView=0,
640
+ componentType=pygltflib.UNSIGNED_INT,
641
+ count=f_np.size,
642
+ type=pygltflib.SCALAR,
643
+ max=[int(f_np.max())],
644
+ min=[int(f_np.min())],
645
+ ),
646
+ # 1 = positions
647
+ pygltflib.Accessor(
648
+ bufferView=1,
649
+ componentType=pygltflib.FLOAT,
650
+ count=len(v_np),
651
+ type=pygltflib.VEC3,
652
+ max=v_np.max(axis=0).tolist(),
653
+ min=v_np.min(axis=0).tolist(),
654
+ ),
655
+ ]
656
+
657
  # Add vertex colors if they exist
658
  if self.vc is not None:
659
  vc_np = self.vc.detach().cpu().numpy().astype(np.float32)
660
  vc_np_blob = vc_np.tobytes()
661
 
662
  # Add vertex color buffer view
663
+ buffer_views.append(
664
  pygltflib.BufferView(
665
  buffer=0,
666
  byteOffset=byteOffset,
 
671
  )
672
 
673
  # Add vertex color accessor
674
+ accessors.append(
675
  pygltflib.Accessor(
676
  bufferView=accessor_count,
677
  componentType=pygltflib.FLOAT,
 
689
  blob += vc_np_blob
690
  byteOffset += len(vc_np_blob)
691
 
692
+ # Create the GLTF object with all components
693
  gltf = pygltflib.GLTF2(
694
  scene=0,
695
  scenes=[pygltflib.Scene(nodes=[0])],
 
698
  attributes=attributes,
699
  indices=0,
700
  )])],
701
+ buffers=[pygltflib.Buffer(byteLength=byteOffset)],
702
+ bufferViews=buffer_views,
703
+ accessors=accessors,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
704
  )
705
 
706
  # Add material for vertex colors
 
717
  ))
718
  gltf.meshes[0].primitives[0].material = 0
719
 
720
+ # Handle textures if they exist
721
  if self.vt is not None:
 
722
  vt_np = self.vt.detach().cpu().numpy().astype(np.float32)
723
  vt_np_blob = vt_np.tobytes()
724
 
725
+ # Add texture coordinates buffer view
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
726
  gltf.bufferViews.append(
 
727
  pygltflib.BufferView(
728
  buffer=0,
729
  byteOffset=byteOffset,
730
  byteLength=len(vt_np_blob),
731
+ byteStride=8, # vec2
732
  target=pygltflib.ARRAY_BUFFER,
733
  )
734
  )
735
 
736
+ # Add texture coordinates accessor
737
  gltf.accessors.append(
 
738
  pygltflib.Accessor(
739
+ bufferView=len(gltf.bufferViews) - 1,
740
  componentType=pygltflib.FLOAT,
741
  count=len(vt_np),
742
  type=pygltflib.VEC2,
 
745
  )
746
  )
747
 
748
+ # Add texture coordinates to attributes
749
+ gltf.meshes[0].primitives[0].attributes.TEXCOORD_0 = len(gltf.accessors) - 1
 
 
 
 
 
 
 
 
 
750
 
751
+ blob += vt_np_blob
752
+ byteOffset += len(vt_np_blob)
753
 
754
+ # Update buffer size
755
  gltf.buffers[0].byteLength = byteOffset
756
 
757
+ # Set the binary blob
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
758
  gltf.set_binary_blob(blob)
759
 
760
+ # Save the GLB file
761
  gltf.save(path)
762
 
763