Using Brayns python client

After launching the Brayns backend service, we will have a server to which we can connect and manipulate using the python client.

Initializing the client object

The first step will be always to create a connection to the backend. This will allow our client to download the latest API which we will be using, as well as sending the necessary commands to it.

We will need the address in which the backend service is running, as well as the port in which is listening. The following examples will assume:

  • Brayns backend is running on BB5, on the node r1i1n1

  • Brayns backend is listening on port 5000

from brayns import Client

braynsClient = Client("r1i1n1.bbp.epfl.ch:5000")

We will use the variable braynsClient to issue all our calls, or to construct any class specific implementation (such as those for the plugins), since all the network interface is implemented on the Client class.

Attention

If you are connecting to a backend running on BB5, it will be necessary to be working within the EPFL’s network, either by working on-site or using a vpn connection.

Loading a model into Brayns

Now, we can start performing requests to the backend. For example, we can load the mouse brain mesh model into it:

# Path to the mesh file to load
brainModelPath = "/gpfs/bbp.cscs.ch/project/proj3/resources/nadir/rat_brain.obj"

# Brayns backend loader we want to use
loaderName = "mesh"

# loader properties used when loading the geometry.
# In this case, "geometryQuality" = 2 means best quality
loaderProperties = { "geometryQuality": 2}

# Load the model
brainLoadResult = braynsClient.add_model(path=brainModelPath,
                                         loader_name=loaderName,
                                         loader_properties=loaderProperties)

# When loading a model, the return value will be the metadata.
# Among other information, we will get the model ID, which is
# used when requesting any operation on the given model
modelID = brainLoadResult["id"]

# We can also get the bounds of our model, as a min and max 3-components
# vector with the minimun and maximun bound
minBound = brainLoadResult["bounds"]["min"]
maxBound = brainLoadResult["bounds"]["max"]

Hint

When loading files from disk, by specifying a path, the backend will be able to load only the files which it can find on it’s filesystem. This means that, if we are running the backend on BB5, we cannot specify a path in our local machine.

Adjusting the camera

When the backend is launched, the camera is positioned at the origin of the virtual world generated by Brayns (0, 0, 0). When we load a model, by default is positioned at the origin as well, which means, probably we cannot fully see (or not see at all) the model we just loaded.

By using some trigonometry, we can calculate the camera parameters to position the camera to capture the whole model, and then request the change throught braynsClient

import math

# Computes the center point of a bounding box
def boundsCenter(minB, maxB):
    target = [0] * 3
    for i in range(3):
        target[i] = (minB[i] + maxB[i]) * 0.5
    return target

# Get the current camera and its parameters from the backend
cam = braynsClient.get_camera()
camParams = braynsClient.get_camera_params()

# Get the center of the model
target = boundsCenter(minBound, maxBound)

# Compute at which distance from the model we have to
# position the camera so that all of it fits in the screen
modelYlen = maxBound[1] - minBound[1]
fov = math.radians(camParams["fovy"] * 0.5)
hipoLen = (modelYlen * 0.5) / math.sin(fov)
dist = hipoLen * math.cos(fov)

# Compute the final camera position
pos = target.copy()

# The camera always faces on its local Z-axis, and we will
# set up the camera so its local Z-axis is aligned with the
# world's Z axis, so in this case, the distance must be
# added to the Z coordinate of the position
pos[2] = pos[2] + dist

braynsClient.set_camera(current = cam["current"],
                        orientation = [0,0,0,1],
                        target=target,
                        position=pos,
                        types=cam["types"])

Rendering a screenshot

After we have loaded the model and position the camera, we might want to generate an image of our piece of art. To do so, we simply request it to the backend, and it will return it to us as a base64 encoded string. We only need to store the result on disk.

import base64

# path were to store the image
path = "/home/nroman/Desktop/my_first_brayns_snapshot.png"

# We can specify the backend to render the image with any of the available renderers.
# However, in this case, we will use the default one
rend = braynsClient.get_renderer()

imgData = braynsClient.snapshot(format="PNG",
                                size=[3840,2160], # 4K
                                quality=0,        # Quality = 0 means maximum quality
                                samples_per_pixel=64,
                                renderer=rend)['data']

binaryImgData = base64.b64decode(imgData)
with open(path, "wb") as fh:
    fh.write(binaryImgData)

Further information

For further information about the API, refer to the different API pages. You can also find more complete and complex examples using the Brayns python client in the Examples