Explorar o código

Faster creation of monochrome point clouds (#3545)

* Faster creation of monochrome point clouds

* Make per-point colors optional

Monochrome point-clouds can be styled using the .materials method just as any other mesh

* Fix changing color on reload + switch between single and per-point color

* make material color optional to support transparency for point clouds

* Use color == None for vertex colors

* remove unused argument

---------

Co-authored-by: Andreas Voigt <andreas.voigt@optonic.com>
Co-authored-by: Falko Schindler <falko@zauberzeug.com>
Voigta hai 7 meses
pai
achega
68b56d1164

+ 17 - 6
nicegui/elements/scene.js

@@ -50,6 +50,15 @@ function texture_material(texture) {
   });
 }
 
+function set_point_cloud_data(position, color, geometry) {
+  geometry.setAttribute("position", new THREE.Float32BufferAttribute(position.flat(), 3));
+  if (color === null) {
+    geometry.deleteAttribute("color");
+  } else {
+    geometry.setAttribute("color", new THREE.Float32BufferAttribute(color.flat(), 3));
+  }
+}
+
 export default {
   template: `
     <div style="position:relative" data-initializing>
@@ -266,9 +275,8 @@ export default {
         mesh.add(light.target);
       } else if (type == "point_cloud") {
         const geometry = new THREE.BufferGeometry();
-        geometry.setAttribute("position", new THREE.Float32BufferAttribute(args[0].flat(), 3));
-        geometry.setAttribute("color", new THREE.Float32BufferAttribute(args[1].flat(), 3));
-        const material = new THREE.PointsMaterial({ size: args[2], vertexColors: true });
+        const material = new THREE.PointsMaterial({ size: args[2], transparent: true });
+        set_point_cloud_data(args[0], args[1], geometry);
         mesh = new THREE.Points(geometry, material);
       } else if (type == "gltf") {
         const url = args[0];
@@ -337,7 +345,10 @@ export default {
       if (!this.objects.has(object_id)) return;
       const material = this.objects.get(object_id).material;
       if (!material) return;
-      material.color.set(color);
+      const vertexColors = color === null;
+      material.color.set(vertexColors ? "#ffffff" : color);
+      material.needsUpdate = material.vertexColors != vertexColors;
+      material.vertexColors = vertexColors;
       material.opacity = opacity;
       if (side == "front") material.side = THREE.FrontSide;
       else if (side == "back") material.side = THREE.BackSide;
@@ -398,9 +409,9 @@ export default {
       this.objects.get(object_id).geometry = texture_geometry(coords);
     },
     set_points(object_id, position, color) {
+      if (!this.objects.has(object_id)) return;
       const geometry = this.objects.get(object_id).geometry;
-      geometry.setAttribute("position", new THREE.Float32BufferAttribute(position.flat(), 3));
-      geometry.setAttribute("color", new THREE.Float32BufferAttribute(color.flat(), 3));
+      set_point_cloud_data(position, color, geometry);
     },
     move_camera(x, y, z, look_at_x, look_at_y, look_at_z, up_x, up_y, up_z, duration) {
       if (this.camera_tween) this.camera_tween.stop();

+ 6 - 2
nicegui/elements/scene_object3d.py

@@ -22,7 +22,7 @@ class Object3D:
         self.scene.objects[self.id] = self
         self.parent: Union[Object3D, SceneObject] = self.scene.stack[-1]
         self.args: List = list(args)
-        self.color: str = '#ffffff'
+        self.color: Optional[str] = '#ffffff'
         self.opacity: float = 1.0
         self.side_: str = 'front'
         self.visible_: bool = True
@@ -90,7 +90,11 @@ class Object3D:
     def _delete(self) -> None:
         self.scene.run_method('delete', self.id)
 
-    def material(self, color: str = '#ffffff', opacity: float = 1.0, side: Literal['front', 'back', 'both'] = 'front') -> Self:
+    def material(self,
+                 color: Optional[str] = '#ffffff',
+                 opacity: float = 1.0,
+                 side: Literal['front', 'back', 'both'] = 'front',
+                 ) -> Self:
         """Set the color and opacity of the object.
 
         :param color: CSS color string (default: '#ffffff')

+ 7 - 3
nicegui/elements/scene_objects.py

@@ -317,7 +317,7 @@ class PointCloud(Object3D):
 
     def __init__(self,
                  points: List[List[float]],
-                 colors: List[List[float]],
+                 colors: Optional[List[List[float]]] = None,
                  point_size: float = 1.0,
                  ) -> None:
         """Point Cloud
@@ -325,16 +325,20 @@ class PointCloud(Object3D):
         This element is based on Three.js' `Points <https://threejs.org/docs/index.html#api/en/objects/Points>`_ object.
 
         :param points: list of points
-        :param colors: list of colors (one per point)
+        :param colors: optional list of colors (one per point)
         :param point_size: size of the points (default: 1.0)
         """
         super().__init__('point_cloud', points, colors, point_size)
+        if colors is not None:
+            self.material(color=None)
 
-    def set_points(self, points: List[List[float]], colors: List[List[float]]) -> None:
+    def set_points(self, points: List[List[float]], colors: Optional[List[List[float]]] = None) -> None:
         """Change the points and colors of the point cloud."""
         self.args[0] = points
         self.args[1] = colors
         self.scene.run_method('set_points', self.id, points, colors)
+        if colors is not None:
+            self.material(color=None)
 
 
 class AxesHelper(Object3D):