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):