rendering - 3D user interface

This module provides a render pipeline system featuring:

  • Class Scene to gather the data to render
  • Widget View that actually renders the scene
  • The display protocol, that allows any object to define its Display subclass to be rendered in a scene.

The view is for window integration and user interaction. Scene is only to manage the objects to render . Almost all madcad data types can be rendered to scenes being converted into an appropriate subclass of Display. Since the conversion from madcad data types into display instance is automatically handled via the display protocol, you usually don’t need to deal with displays directly.

show(scene: dict, interest: Optional[Box] = None, size=uvec2(400, 400), projection=None, navigation=None, **options)[source]

Easy and convenient way to create a window containing a View on a created Scene

If a Qt app is not already running, the functions returns when the window has been closed and all GUI destroyed

Parameters:
  • scene – a mapping (dict or list) giving the objects to render in the scene
  • interest – the region of interest to zoom on at the window initialization
  • size – the window size (pixel)
  • options – options to set in Scene.options

Tip

For integration in a Qt window or to manipulate the view, you should directly use View

opengl_version

Minimum opengl version required by the rendering pipeline

Display protocol

A displayable is an object that implements the signature of Display.

displayable(obj)[source]

Return True if the given object has the matching signature to be added to a Scene

class Display[source]

Blanket implementation for displays. This class signature is exactly the display protocol specification

world

matrix from local space to parent space

Type:fmat4
box

boudingbox of the display in local space

Type:Box

These attributes are variable members by default but can be overriden as properties if needed.

  • Mendatory interface for the scene

    display(scene) self[source]

    Displays are obviously displayable as themselves

    stack(scene) [key, target, priority, callable][source]

    Rendering functions to insert in the renderpipeline.

    The expected result can be any iterable providing tuples (key, target, priority, callable) such as:

    Key:a tuple with the successive keys in the displays tree, most of the time implementers set it to () because it doesn’t belong to a subpart of the Display.
    Target:the name of the render target in the view that will be rendered (see View)
    Priority:a float that is used to insert the callable at the proper place in the rendering stack
    Callable:a function that renders, signature is func(view)

    The view contains the uniforms, rendering targets and the scene for common resources

    __getitem__(key) display[source]

    Get a subdisplay by its index/key in this display (like in a scene)

    duplicate(src, dst) display/None[source]

    Duplicate the display for an other scene (other context) but keeping the same memory buffers when possible.

    Return None if not possible or not implemented.

    update(scene, displayable) bool[source]

    Update the current displays internal datas with the given displayable .

    If the display cannot be upgraded, it must return False to be replaced by a fresh new display created from the displayable

  • Optional interface, only for Qt interaction

    selected

    flag set to True by left-clicking on the object

    control(view, key, sub, evt: QEvent)[source]

    Handle input events occuring on the area of this display (or of one of its subdisplay). For subdisplay events, the parents control functions are called first, and the sub display controls are called only if the event is not accepted by parents

    Parameters:
    • key – the key path for the current display
    • sub – the key path for the subdisplay
    • evt – the Qt event (see Qt doc)

Rendering system

Note

As the GPU native precision is f4 (float 32 bits), all the vector stuff regarding rendering is made using simple precision types: fvec3, fvec4, fmat3, fmat4, ... instead of the usual double precision vec3

overrides

Dictionary of callables used by Scene.display to override the display protocol method object.display(scene)

global_context

Shared open gl context, None if not yet initialized

class Scene(objs=(), options=None, ctx=None, setup=None)[source]

Rendering pipeline for madcad displayable objects

This class is gui-agnostic, it only relies on OpenGL, and the context has to be created by the user.

When an object is added to the scene, a Display is not immediately created for it, the object is put into the queue and the Display is created at the next render. If the object is removed from the scene before the next render, it is dequeued.

ctx

moderngl Context (must be the same for all views using this scene)

resources

dictionary of scene resources (like textures, shaders, etc) index by name

Type:dict
options

dictionary of options for rendering, initialized with a copy of settings.scene

Type:dict
displays

dictionary of items in the scheme {'name': Display}

Type:dict
stacks

lists of callables to render each target {'target': [(key, priority, callable(view))]}

Type:list
setup

setup of each rendering target {'target': callable}

Type:dict
touched

flag set to True if the stack must be recomputed at the next render time (there is a change in a Display or in one of its children)

Type:bool
__getitem__(key) display[source]

Get the displayable for the given key, raise when there is no object or when the object is still in queue.

__setitem__(key, value)[source]

Equivalent with self.add with a key

add(displayable, key=None) key[source]

Add a displayable object to the scene, if key is not specified, an unused integer key is used The object is not added to the render pipeline yet, but queued for next rendering.

box()[source]

Computes the boundingbox of the scene, with the current object poses

dequeue()[source]

Load all pending objects to insert into the scene. This is called automatically by the next render() if touch() has been called

display(obj, former=None)[source]

Create a display for the given object for the current scene.

This is the actual function converting objects into displays. You don’t need to call this method if you just want to add an object to the scene, use add() instead

item(key)[source]

Get the Display associated with the given key, descending the parenting tree

The parents must all make their children accessible via __getitem__

render(view)[source]

Render to the view targets.

This must be called by the view widget, once the OpenGL context is set.

resource(name, func=None)[source]

Get a resource loaded or load it using the function func. If func is not provided, an error is raised

restack()[source]

Update the rendering calls stack from the current scene’s displays. This is called automatically on dequeue()

sync(objs: dict)[source]

Update the scene from a dictionary of displayables, the former values that cannot be updated are discarded

touch()[source]

Shorthand for self.touched = True

update(objs: dict)[source]

Rebuild the scene from a dictionary of displayables Update former displays if possible instead of replacing it

Views classes

class View(scene, projection=None, navigation=None, parent=None)[source]

Qt widget to render and interact with displayable objects. It holds a scene as renderpipeline.

scene

the Scene object displayed

projection

Perspective or Orthographic

navigation

Orbit or Turntable

tool

list of callables in priority order to receive events

targets

render targets matching those requested in scene.stacks

uniforms

parameters for rendering, used in shaders

Note

There is some restrictions using the widget. Due to some Qt limitations (and design choices), Qt is using separated opengl contexts for each independent widgets or window.

  • a View should not be reparented once displayed

  • a View can’t share a scene with Views from an other window

  • to share a Scene between Views, you must activate

    QCoreApplication.setAttribute(Qt.AA_ShareOpenGLContexts, True)
    
  • Methods to get items on the screen

    somenear(point: QPoint, radius=None) QPoint[source]

    Return the closest coordinate to coords, (within the given radius) for which there is an object at So if objnear is returning something, objat and ptat will return something at the returned point

    ptat(point: QPoint) vec3[source]

    Return the point of the rendered surfaces that match the given window coordinates

    ptfrom(point: QPoint, center: vec3) vec3[source]

    3D point below the cursor in the plane orthogonal to the sight, with center as origin

    itemat(point: QPoint) key[source]

    Return the key path of the object at the given screen position (widget relative). If no object is at this exact location, None is returned

  • Methods to move camera

    look(position: Optional[vec3] = None)[source]

    Make the scene navigation look at the position. This is changing the camera direction, center and distance.

    adjust(box: Optional[Box] = None)[source]

    Make the navigation camera large enough to get the given box in . This is changing the zoom level

    center(center: Optional[vec3] = None)[source]

    Relocate the navigation to the given position . This is translating the camera.

  • Event system

    event(self, e: Optional[QEvent]) bool
    inputEvent(evt)[source]

    Default handler for every input event (mouse move, press, release, keyboard, …) When the event is not accepted, the usual matching Qt handlers are used (mousePressEvent, KeyPressEvent, etc).

    This function can be overwritten to change the view widget behavior.

    control(key, evt)[source]

    Transmit a control event successively to all the displays matching the key path stages. At each level, if the event is not accepted, it transmits to sub items

    This function can be overwritten to change the interaction with the scene objects.

  • Rendering system

    refreshmaps()

    Load the rendered frames from the GPU to the CPU

    • When a picture is used to GPU rendering it’s called ‘frame’
    • When it is dumped to the RAM we call it ‘map’ in this library
    identstep(nidents)

    Updates the amount of rendered idents and return the start ident for the calling rendering pass? Method to call during a renderstep

class Offscreen(scene, size=uvec2(400, 400), projection=None, navigation=None)[source]

Object allowing to perform offscreen rendering, navigate and get information from screen as for a normal window

  • Methods to get items on the screen

    somenear(point: ivec2, radius=None) ivec2

    Return the closest coordinate to coords, (within the given radius) for which there is an object at So if objnear is returning something, objat and ptat will return something at the returned point

    ptat(point: ivec2) vec3

    Return the point of the rendered surfaces that match the given window coordinates

    ptfrom(point: ivec2, center: vec3) vec3

    3D point below the cursor in the plane orthogonal to the sight, with center as origin

    itemat(point: ivec2) key

    Return the key path of the object at the given screen position (widget relative). If no object is at this exact location, None is returned

  • Methods to move camera

    look(position: Optional[vec3] = None)

    Make the scene navigation look at the position. This is changing the camera direction, center and distance.

    adjust(box: Optional[Box] = None)

    Make the navigation camera large enough to get the given box in . This is changing the zoom level

    center(center: Optional[vec3] = None)

    Relocate the navigation to the given position . This is translating the camera.

  • Rendering system

    refreshmaps()

    Load the rendered frames from the GPU to the CPU

    • When a picture is used to GPU rendering it’s called ‘frame’
    • When it is dumped to the RAM we call it ‘map’ in this library
    identstep(nidents)

    Updates the amount of rendered idents and return the start ident for the calling rendering pass? Method to call during a renderstep

View projections and navigation

class Turntable(center: vec3 = 0, distance: float = 1, yaw: float = 0, pitch: float = 0)[source]

Navigation rotating on yaw and pitch around a center

Object used as View.navigation

class Orbit(center: vec3 = 0, distance: float = 1, orient: vec3 = vec3(1, 0, 0))[source]

Navigation rotating on the 3 axis around a center.

Object used as View.navigation

class Perspective(fov=None)[source]

Object used as View.projection

fov

field of view (rad), defaulting to settings.display['field_of_view']

Type:float
class Orthographic(size=None)[source]

Object used as View.projection

size

factor between the distance from camera to navigation center and the zone size to display defaulting to tan(settings.display['field_of_view']/2)

Type:float

Helpers to trick into the pipeline

class Group(scene, objs: dict / list = None, pose=1)[source]

A group is like a subscene

property pose

Pose of the group relatively to its parents

property world

Update children’s world matrix applying the current pose in addition to world

property box

Computes the boundingbox of the scene, with the current object poses

__getitem__(key)[source]

Get a subdisplay by its index/key in this display (like in a scene)

dequeue(scene, objs)

Update the current displays internal datas with the given displayable .

If the display cannot be upgraded, it must return False to be replaced by a fresh new display created from the displayable

stack(scene)[source]

Rendering functions to insert in the renderpipeline.

The expected result can be any iterable providing tuples (key, target, priority, callable) such as:

Key:a tuple with the successive keys in the displays tree, most of the time implementers set it to () because it doesn’t belong to a subpart of the Display.
Target:the name of the render target in the view that will be rendered (see View)
Priority:a float that is used to insert the callable at the proper place in the rendering stack
Callable:a function that renders, signature is func(view)

The view contains the uniforms, rendering targets and the scene for common resources

update(scene, objs)[source]

Update the current displays internal datas with the given displayable .

If the display cannot be upgraded, it must return False to be replaced by a fresh new display created from the displayable

class Step(target, priority, callable)[source]

Simple display holding a rendering stack step

Step(target, priority, callable)

class Displayable(build, *args, **kwargs)[source]

Simple displayable initializing the given Display class with arguments

At the display creation time, it will simply execute build(*args, **kwargs)