rendering - 3D interface

This module provides a render pipeline system centered around class ‘Scene’ and a Qt widget ‘View’ for window integration and user interaction. ‘Scene’ is only to manage the objects to render (almost every madcad object). Most of the time you won’t need to deal with it directly. The widget is what actually displays it on the screen. The objects displayed can be of any type but must implement the display protocol

display protocol

a displayable is an object that implements the signatue of Display:

class display:
        box (Box)                      # delimiting the display, can be an empty or invalid box
        world (fmat4)                   # local transformation

        stack(scene)                   # rendering routines (can be methods, or any callable)
        duplicate(src,dst)             # copy the display object for an other scene if possible
        upgrade(scene,displayable)     # upgrade the current display to represent the given displayable
        control(...)                   # handle events

        __getitem__                    # access to subdisplays if there is

For more details, see class Display below

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

Note

There is some restrictions using the widget. This is due to some Qt limitations (and design choices), that 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)
    

Rendering system

show(objs, options=None, interest=None)

shortcut to create a QApplication showing only one view with the given objects inside. the functions returns when the window has been closed and all GUI destroyed

overrides

dictionnary of callables used by Scene.display to override the classes .display(scene) method

global_context

shared open gl context, None if not yet initialized

opengl_version

minimum opengl required version

class Display

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 part for the scene

    display(scene) self

    displays are obviously displayable as themselves

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

    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 ressources

    duplicate(src, dst) display/None

    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.

    __getitem__(key) display

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

    update(scene, displayable) bool

    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 part for Qt interaction

    selected (bool)

    flag set to True by left-clicking on the object

    control(view, key, sub, evt: PyQt5.QtCore.QEvent)

    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)

class Scene(objs=(), options=None, ctx=None, setup=None)

rendeing pipeline for madcad displayable objects

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

Attributes defined here:

  • scene stuff

    ctx

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

    ressources

    dictionnary of scene ressources (like textures, shaders, etc) index by name

    options

    dictionnary of options for rendering, innitialized with a copy of settings.scene

  • rendering pipeline stuff

    displays

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

    stacks

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

    setup

    callable for setup of each rendering target

    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)

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.

add(displayable, key=None) key

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 the renderpipeline yet, but queued for next rendering.

box()

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

dequeue()

load all pending objects to insert into the scene

display(obj)

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)

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

The parents must all make their children accessible via __getitem__

render(view)

render to the view targets.

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

ressource(name, func=None)

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

sync(objs: dict)

update the scene from a dictionnary of displayables, the former values that cannot be updated are discarded

touch()

shorthand for self.touched = True

update(objs: dict)

rebuild the scene from a dictionnary of displayables update former displays if possible instead of replacing it

class View(scene, projection=None, navigation=None, parent=None)

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

Attributes definied here:

scene

the Scene object displayed

projection

Perspective or Orthographic

navigation

Orbit or Turntable

tool

list of callables in priority order to receive events

  • render stuff

    targets

    render targets matching those in scene.stacks

    uniforms

    parameters for rendering, used in shaders

  • Methods to get items on the screen

    somenear(point: PyQt5.QtCore.QPoint, radius=None) PyQt5.QtCore.QPoint

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

    ptat(point: PyQt5.QtCore.QPoint) glm.vec3

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

    ptfrom(point: PyQt5.QtCore.QPoint, center: glm.vec3) glm.vec3

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

    itemat(point: PyQt5.QtCore.QPoint) 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[glm.vec3] = None)

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

    adjust(box: Optional[madcad.mathutils.Box] = None)

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

    center(center: Optional[glm.vec3] = None)

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

  • Event system

    event(evt)

    Qt event handler In addition to the usual subhandlers, inputEvent is called first to handle every InputEvent.

    The usual subhandlers are used to implement the navigation through the scene (that is considered to be intrinsic to the scene widget).

    inputEvent(evt)

    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)

    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

view settings/interaction methods

class Turntable(center: glm.vec3 = 0, distance: float = 1, yaw: float = 0, pitch: float = 0)

navigation rotating on yaw and pitch around a center

object used as View.navigation

class Orbit(center: glm.vec3 = 0, distance: float = 1, orient: glm.vec3 = vec3(1, 0, 0))

navigation rotating on the 3 axis around a center.

object used as View.navigation

class Perspective(fov=None)

object used as View.projection

Fov

field of view (rad)

class Orthographic

object used as View.projection

helpers to trick into the pipeline

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

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)

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)

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 ressources

update(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

class Step(*args)

simple display holding a rendering stack step

Step(target, priority, callable)

stack(scene)

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 ressources

class Displayable(build, *args, **kwargs)

simple displayable initializeing the given Display class with arguments

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

displayable(obj)

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