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
-
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¶

-
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¶

-
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¶

-
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¶

-
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¶

-
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¶

-
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¶

-
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¶

-
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¶
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: -
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¶
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: -
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.
Contribution¶
Feel free to add features to pysg or fix bugs. Do the following:
- Fork pysg
- Make changes
- Send a Pull request
Thanks for everybody who is interested in the project.