⚠️ Beta State

PyBevy is in an early and experimental stage. The API is incomplete, subject to breaking changes without notice, and you should expect bugs. Many features are still under development.

NumPy Point Cloud

Create a custom mesh from a NumPy array to render a point cloud.

Introduction

This advanced recipe shows how to integrate pybevy with numpy, a popular Python library for numerical computing. We will generate a large number of points using numpy and then render them efficiently as a "point cloud" using a custom mesh.

# You will need to install numpy: pip install numpy
import numpy as np
from pybevy.prelude import *

Generating Points with NumPy

We'll create a function to generate points on the surface of a sphere. This is a classic algorithm that uses numpy for fast, vectorized operations. The function will return a numpy array of shape (N, 3).

def generate_sphere_points(num_points: int) -> np.ndarray:
    indices = np.arange(0, num_points, dtype=float) + 0.5
    phi = np.arccos(1 - 2 * indices / num_points)
    theta = np.pi * (1 + 5**0.5) * indices
    x, y, z = np.cos(theta) * np.sin(phi), np.sin(theta) * np.sin(phi), np.cos(phi)
    return np.stack([x, y, z], axis=-1) * 5.0 # Scale the sphere

The Setup System

This is where the magic happens.

  1. We call our numpy function to get the point data.
  2. We create a new Mesh asset.
  3. We set the mesh's vertex positions using the numpy array.
  4. Crucially, we set the primitive_topology to PointList. This tells the GPU to render each vertex as a single point, rather than trying to connect them into triangles.
def setup(
    commands: Commands,
    meshes: ResMut[Assets[Mesh]],
    materials: ResMut[Assets[StandardMaterial]],
):
    # Generate 50,000 points using NumPy
    points = generate_sphere_points(50000)
 
    # Create a new Bevy mesh
    point_cloud_mesh = Mesh()
    # Set the vertex positions from the NumPy array
    point_cloud_mesh.set_attribute(Mesh.ATTRIBUTE_POSITION, points)
    # Set the topology to PointList
    point_cloud_mesh.primitive_topology = PrimitiveTopology.PointList
 
    # Spawn the point cloud entity
    commands.spawn(
        Mesh3d(meshes.add(point_cloud_mesh)),
        MeshMaterial3d(materials.add(StandardMaterial(
            base_color=Color.srgb(0.9, 0.2, 0.3),
            unlit=True, # Unlit makes points visible without a light source
        ))),
    )
 
    # Spawn a camera
    commands.spawn(
        Camera3d(),
        Transform.from_xyz(0.0, 0.0, 15.0).looking_at(Vec3.ZERO, Vec3.Y),
    )

Running the App

This will render a sphere made of thousands of individual points. This technique is very efficient for visualizing large datasets, simulations, or creating particle effects.

@entrypoint
def main(app: App) -> App:
    return app.add_plugins(DefaultPlugins).add_systems(Startup, setup)
 
if __name__ == "__main__":
    main().run()