diff --git a/nicegui/elements/scene.js b/nicegui/elements/scene.js index 0959639c5..5926613ee 100644 --- a/nicegui/elements/scene.js +++ b/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: `
@@ -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(); diff --git a/nicegui/elements/scene_object3d.py b/nicegui/elements/scene_object3d.py index 3be5261c7..5cf508bc7 100644 --- a/nicegui/elements/scene_object3d.py +++ b/nicegui/elements/scene_object3d.py @@ -22,7 +22,7 @@ def __init__(self, type_: str, *args: Any) -> None: 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 @@ def _draggable(self) -> None: 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') diff --git a/nicegui/elements/scene_objects.py b/nicegui/elements/scene_objects.py index 7938e2e74..203e3a615 100644 --- a/nicegui/elements/scene_objects.py +++ b/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 @@ def __init__(self, This element is based on Three.js' `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):