Welcome to pysg’s documentation!

The python scene graph library pysg is a simple and easy to use 3D render scene graph for python using the ModernGL library. It gives you the power of a scene graph which allows easy 3D object manipulation and hierarchy without all the matrix transform headache. For most geometry functions the python library pyrr is used. The render pipeline is written in ModernGL which makes it easy to use different window management libraries, but also allows headless rendering and save the 3D scene images to a hard disk.

Overview

Installation

Install the latest stable version of pysg with pip:

$ pip install pysg

Check pysg version:

import pysg
pysg.__version__

Guide

Usage

With pysg it is possible to create simple scenes with basic 3D geometries and render them to screen or save them as images on the hard drive.

The example described in this section only render a single image and display it on the screen using pillow.

See also

More examples in the example folder: https://gitlab.com/becheran/pysg/tree/master/examples

References

Load all required references. The pillow (PIL) library is required to display the result image of the standalone renderer. The pyrr vector is needed to define a new position for the 3D elements in the scene.

from PIL import Image
from pyrr import Vector3
import pysg
Init

Initialize all camera, scene, and renderer. All three things are required to display a 3D scene. The camera defines the viewing volume within an scene. The scene is the root element of all 3D objects which are used for rendering. A scene also defines the ambient brightness and background color. The renderer is used to actually synthesise the described pysg scene. It can either be a standalone renderer, rendering to a texture which can later be saved as an image. With the GLRenderer the scene can be displayed within a OpenGL windows.

# Constants. Width and height of image.
WIDTH = 800
HEIGHT = 600
# Camera, scene and renderer is always needed to render a 3D scene.
camera = pysg.PerspectiveCamera(fov=45, aspect=800 / 600, near=0.01, far=1000)
scene = pysg.Scene(background_color=(1, 1, 1), ambient_light=(0.2, 0.2, 0.2))
renderer = pysg.HeadlessGLRenderer(scene, camera, width=WIDTH, height=HEIGHT)
Scene

The scene in pysg contains all objects with their 3D transform which describe a renderable 3D scenario. Lighting is also handles within a scene.

# Change position of camera to view whole scene (camera is looking towards -z).
camera.local_position += Vector3([0, 0, 10])
# Add point-light to scene and define color as white. With ambient color sum of brightness is 1.
light = pysg.PointLight(color=(0.8, 0.8, 0.8))
# Change position of light in scene.
light.world_position = Vector3([1, 1, 1])
# Add cube object with 1x1x1 size and blueish color.
cube = pysg.CubeObject3D(1, 1, 1, color=(0.4, 0.5, 0.9))
# Rotate cube so that not the only the a corner is now in front of camera.
cube.local_euler_angles = Vector3([0, 45, 0])
# Add 3D elements to scene.
scene.add(cube)
scene.add(light)
Render

Rendering is the last step of the pysg pipeline. If object transforms or properties are updated, the render function can be called within a loop in order to simulate dynamic scene changes.

# Actually render the 3D scene.
renderer.render()
# Get current rendering from texture as byte array.
current_image_data = renderer.current_image()
# Convert byte array to pillow image and use show function to display it.
img = Image.frombytes('RGB', (WIDTH, HEIGHT), current_image_data, 'raw', 'RGB', 0, -1)
img.show()

Rotations & Coordinate System

For pysg a right handed coordinate system is used. The x-axis is facing right, the y-axis up, and the z-axis to the front. The pysg library uses ModernGL to render all 3D objects in the scene. The camera inside a scene is facing towards the -z direction.

For the pysg scene graph all rotations are internally represented as quaternions. If the rotation of an object is set via Euler angles they are converted to quaternions. For the Euler angles the rotation order is YZX.

See also

The website EuclideanSpace contains more information about rotations and how they are implemented in pysg.

References

All coding references generated with Sphinx.

Node3D

The base of all objects which can be aggregated to describe a 3D scene. Every Node3D element contains the local and world transformations in 3D space. Every node has one parent node and a list of child nodes. Every transformation such as, position, rotation, or scale, also affects the child objects of a node.

The following code example shows how nodes can be created and combined to describe a simple scene with the following node hierarchy:

Create Hierarchy
#     root
#     /  \
#   c_1, c_2
#       /   \
#    c_2_1  c_2_2

root = Node3D("root")
c_1 = Node3D("child_1")
c_2 = Node3D("child_2")
c_2_1 = Node3D("child_2_1")
c_2_2 = Node3D("child_2_2")
root.add(c_1)
root.add(c_2)
c_2.add(c_2_1)
c_2.add(c_2_2)

All Node3D objects can now be individually transformed in 3D space.

Change position of root node
root.local_position = Vector([2,1,1])

After executing the code above, all child nodes and the root node itself are moved to the position of the root node.

Change child node local position
c_2.local_position += Vector([1,0,0])

The root node and node c_1 are still at position [2,1,1] since they are not affected by the transforms of the c_2 child node. Both child nodes c_2_1 and c_2_2 and node c_2 itself are shifted 1 unit towards the local x-axis away from the root node. This means that these nodes are now at world coordinates [3,1,1].

class pysg.node_3d.Node3D(name: str = 'New Node')

Node element of scene graph (tree structure).

Parameters:name – Name for string representation.
add(node_3d: pysg.node_3d.Node3D) → None

Adds another node as child of this node. It is important to note, that the world position and rotation will remain the same of the added child, but all its local transforms will be updated relative to the new parent.

Parameters:node_3d (Node3D) – The child node which shall be added to the scene graph.
get_leaf_nodes() → list

Recursively iterate over all children and return list with all leaf Node3Ds (no more children).

Returns:List of all children with no more child nodes. Type of list elements is Node3D.
Return type:list
local_euler_angles

Local rotation in euler angle representation as Vector of length 3. Internally quaternions are used. The used rotation order is YZX.

See also

Please have a look at the rotations section for more details.

local_matrix

Local translation matrix (read only).

Returns:4x4 local translation matrix of the current node.
Return type:Matrix44
local_position

The local position is relative to the transform of the parent node.

Note

The return value is a copy of the original vector and can not be edited directly. This means that code like node.local_position.x += 2 will not work as you might expect it to!

Returns:Position of node relative to parent node.
Return type:Vector3
local_quaternion

The local rotation as quaternion.

Note

The return value is a copy of the original quaternion and can not be edited directly. Use the quaternion setter instead.

Returns:Quaternion rotation relative to parent node.
Return type:Quaternion
parent

The parent of the current node element.

Returns:Parent node.
Return type:Node3D
remove(node_3d: pysg.node_3d.Node3D) → None

Remove a child from the scene graph.

Parameters:node_3d (Node3D) – The child node which shall be removed from the scene graph.
rotate_x(angle: float, local_space: bool = True) → None

Rotate object around its x-axis.

Parameters:
  • angle – The rotation angle in degrees.
  • local_space – If True rotate in local coordinate system. Otherwise in world space.
rotate_y(angle: float, local_space: bool = True) → None

Rotate object around its y-axis.

Parameters:
  • angle – The rotation angle in degrees.
  • local_space – If True rotate in local coordinate system. Otherwise in world space.
rotate_z(angle: float, local_space: bool = True) → None

Rotate object around its z-axis.

Parameters:
  • angle – The rotation angle in degrees.
  • local_space – If True rotate in local coordinate system. Otherwise in world space.
scale

Local scale of current node.

Returns:X, Y and Z scale as Vector3.
Return type:Vector3
update_world_matrix() → None

Updates the world matrix for a given node in the render scene graph.

world_euler_angles()

World rotation in euler angle representation as Vector of length 3. Internally quaternions are used. The used rotation order is YZX.

See also

Please have a look at the rotations section for more details.

world_matrix

World translation matrix (read only).

Returns:4x4 translation matrix of the current node in world space.
Return type:Matrix44
world_position

The world position of a node.

Note

The return value is a copy of the original vector and can not be edited directly. This means that code like node.world_position.x += 2 will not work as you might expect it to!

Returns:Position of node in world space.
Return type:Vector3
world_quaternion

The world rotation as quaternion.

Note

The return value is a copy of the original quaternion and can not be edited directly. Use the quaternion setter instead.

Returns:Rotation in world space as quaternion.
Return type:Quaternion

Object3D

This module contains all geometric 3D objects which can be added to a scene. All 3D objects inherit from the Object3D base class. 3D objects are defined via a color, the object size, and a name.

Circle
_images/Circle.jpg
class pysg.object_3d.CircleObject3D(radius: float, color=(1, 1, 1), name: str = 'CircleObject')

Creates a simple circle geometry.

Note

Per default, only the front face of a plane gets rendered. If you want to also show the backface, you have to configure the moderngl render context. See Renderer section for more information.

Parameters:
  • radius (float) – Radius of circle.
  • color (tuple) – Color of 3D object.
  • name (str) – Name of object.
Plane
_images/Plane.jpg
class pysg.object_3d.PlaneObject3D(width: float, height: float, color=(1, 1, 1), name: str = 'PlaneObject')

Creates a simple plane geometry.

Note

Per default, only the front face of a plane gets rendered. If you want to also show the backface, you have to configure the moderngl render context. See Renderer section for more information.

Parameters:
  • width (float) – Width of plane.
  • height (float) – Height of plane.
  • color (tuple) – Color of 3D object.
  • name (str) – Name of object.
Triangle
_images/Triangle.jpg
class pysg.object_3d.TriangleObject3D(width: float, height: float, color=(1, 1, 1), name: str = 'TriangleObject')

Creates a icosahedron geometry.

Parameters:
  • width (float) – Width of triangle.
  • height (float) – Height of triangle.
  • color (tuple) – Color of 3D object.
  • name (str) – Name of object.
Cube
_images/Cube.jpg
class pysg.object_3d.CubeObject3D(width: float, height: float, depth: float, color=(1, 1, 1), name: str = 'CubeObject')

Creates a simple cube geometry

Parameters:
  • width (float) – Width of cube.
  • height (float) – Height of cube.
  • depth (float) – Depth of cube.
  • color (tuple) – Color of 3D object.
  • name (str) – Name of object.
Icosahedron
_images/Icosahedron.jpg
class pysg.object_3d.IcosahedronObject3D(radius: float, color=(1, 1, 1), name: str = 'IcosahedronObject')

Creates a icosahedron geometry.

Parameters:
  • radius (float) – Radius of icosahedron.
  • color (tuple) – Color of 3D object.
  • name (str) – Name of object.
Cylinder
_images/Cylinder.jpg
class pysg.object_3d.CylinderObject3D(height: float, radius: float, color=(1, 1, 1), name: str = 'CylinderObject')

Creates a icosahedron geometry.

Parameters:
  • width (float) – Width of triangle.
  • height (float) – Height of triangle.
  • color (tuple) – Color of 3D object.
  • name (str) – Name of object.
Tetrahedral
_images/Tetrahedral.jpg
class pysg.object_3d.TetrahedralObject3D(radius: float, color=(1, 1, 1), name: str = 'BoxObject')

Creates a tetrahedral geometry.

Parameters:
  • radius (float) – radius of edge points lying on unit sphere.
  • color (tuple) – Color of 3D object.
  • name (str) – Name of object.
Pyramid
_images/Pyramid.jpg
class pysg.object_3d.PyramidObject3D(base_size: float, height: float, color=(1, 1, 1), name: str = 'PyramidObject')

Creates a square base pyramide geometry.

Parameters:
  • base_size (float) – Size of the pyramid square base.
  • height (float) – Pyramid height.
  • color (tuple) – Color of 3D object.
  • name (str) – Name of object.

Camera

The camera is used to calculate the viewing frustum in 3D space. All cameras inherit from the Camera class which itself is of the type Node3D and can be added to the scene graph.

Camera
class pysg.camera.Camera

Base class of all camera types used in pysg.

projection_matrix

The current projection matrix of the camera.

Returns:Projection matrix of camera in OpenGL format:

m00 m04 m08 m12

m01 m05 m09 m13

m02 m06 m10 m14

m03 m07 m11 m15

Return type:Matrix44
Perspective Camera
class pysg.camera.PerspectiveCamera(*, fov: float, aspect: float, near: float, far: float)

Camera which uses frustum for the projection matrix.

Parameters:
  • fov (float) – Vertical field of view for the perspective camera in degrees.
  • aspect (float) – Aspect ratio of camera sensor (with/height).
  • near (float) – Camera frustum near plane. Everything closer will be culled.
  • far (float) – Camera frustum far plane. Everything farther away will be culled.
Orthographic Camera
class pysg.camera.OrthographicCamera(*, left: float, right: float, top: float, bottom: float, near: float, far: float)

Camera using a box geometry for the projection matrix.

Parameters:
  • left (float) – Camera volume left (usually -screen_width/2).
  • right (float) – Camera volume right (usually screen_width/2).
  • top (float) – Camera volume top (usually screen_height/2).
  • bottom (float) – Camera volume bottom (usually -screen_height/2)..
  • near (float) – Camera frustum near plane. Everything closer will be culled.
  • far (float) – Camera frustum far plane. Everything farther away will be culled.

Light

Lights can be added to the scene to illuminate the objects.

class pysg.light.Light(color: tuple, name: str = 'Light')

Base class of all lights which can be added to the scene.

class pysg.light.PointLight(color: tuple, name: str = 'PointLight')

Point light emits light in all directions from a single point.

Parameters:color – The light intensity of light source.

Scene

The root of the scene graph

All children added to this node can be rendered via a renderer.

class pysg.scene.RenderLists

Data object containing lights and geometry list for rendering.

class pysg.scene.Scene(background_color: tuple = (0, 0, 0), ambient_light: tuple = (0.0, 0.0, 0.0), auto_update: bool = True)

The scene object. Must always bee the root node of the scene graph.

Parameters:
  • background_color – The clear color of the scene.
  • ambient_light – Light value which will be applied to all objects in scene.
  • auto_update – If true the object transform will be updated automatically.
  • you have to do it manually. (Otherwise) –
add(node_3d: pysg.node_3d.Node3D) → None

Overrides base class of Node3D to add an objects to render or light list.

Parameters:node_3d (Node3D) – The child node which shall be added to the scene graph.
clear() → None

Clears render lists and scene graph.

remove(node_3d: pysg.node_3d.Node3D) → None

Overrides base class of Node3D to removes an object from render or light list.

Parameters:node_3d (Node3D) – The child node which shall be removed.
render_list

The current render list containing all the 3D objects and lights for rendering.

Returns:A RenderLists object containing all elements for rendering.
Return type:RenderLists

Renderer

All rendering related functions and classes. The ModernGL python library is used for all rendering functions in pysg.

Base Class
class pysg.renderer.Renderer(scene: pysg.scene.Scene, camera: pysg.camera.Camera)

Base class. All renderer implementations need to inherit form this class.

Parameters:
  • scene (Scene) – Scene which shall be rendered.
  • camera (Camera) – Camera which is used to view scene.
ctx = None

The ModernGL context object which can be used to set some OpenGL related settings. For example the context can be used to deactivate backface culling:

camera.ctx.disable(moderngl.CULL_FACE)

See https://moderngl.readthedocs.io/en/stable/reference/context.html for more information.

Type:Context
render() → None

Base render function which needs to be implemented by sub-classes.

GLRenderer
class pysg.renderer.GLRenderer(scene: pysg.scene.Scene, camera: pysg.camera.Camera)

Render the scene to a given viewport.

Parameters:
  • scene (Scene) – Scene which shall be rendered.
  • camera (Camera) – Camera which is used to view scene.
render() → None

Set viewport and call _render() function of base class.

viewport = None

Viewport is a tuple of size four (x, y, width, height).

Type:tuple
HeadlessGLRenderer
class pysg.renderer.HeadlessGLRenderer(scene: pysg.scene.Scene, camera: pysg.camera.Camera, *, width: int, height: int)

Render the scene to a framebuffer which can be read to CPU memory to be used as an image.

Parameters:
  • scene (Scene) – Scene which shall be rendered.
  • camera (Camera) – Camera which is used to view scene.
  • width (float) – Width of output image in pixel
  • height (float) – Height of output image in pixel
current_image() → bytes

Render the current scene and camera into a buffer. The buffer can later be returned with the ‘current_image’ method.

Returns:The rendered byte array. Copy from vRAM to RAM.
Return type:bytes
render() → None

Render the current scene and camera into a buffer. The buffer can later be returned with the current_image method.

Util

Utility functions for pysg.

pysg.util.parameters_as_angles_deg_to_rad(*args_to_convert)

Converts specific angle arguments to angles in radians.

Used as a decorator to reduce duplicate code.

Arguments are specified by their argument name. For example

@parameters_as_angles_deg_to_rad('a', 'b', 'optional')
def myfunc(a, b, *args, **kwargs):
    pass

myfunc(20, [15,15], optional=[80,80,80])
pysg.util.pyrr_type_checker(var: object, var_type: type) → object

Makes sure that pyrr types are used as input. Tries to cast and raises PyrrTypeError if not possible.

Parameters:
  • var – Input variable.
  • var_type – Type of input variable.
Returns:

Variable in correct type. Otherwise raise PyrrTypeError exception.

Coding Standards & Contribution

The pysg project is OpenSource and can be extended to your specific needs. In general the main project is not intended to be a full-fledged game engine, but an easy to use and simple tool to create simple 3D scenarios and have all objects in a scene graph structure.

Coding Standards

All code should be formatted in PEP-8 style.

Contribution

Feel free to add features to pysg or fix bugs. Do the following:

  1. Fork pysg
  2. Make changes
  3. Send a Pull request

Thanks for everybody who is interested in the project.

Indices and tables