Creating transformsΒΆ

There are 4 basic transform nodes: Translate, Scale, Rotate and Skew. It is also possible to create custom transform with the Transform node (by passing down a 4x4 matrix). They can be used to transform the vertices of the shapes below in the graph.

Rotate a quad by 45Β°
Code
Graph
import pynopegl as ngl


@ngl.scene()
def rotate(cfg: ngl.SceneCfg):
    cfg.aspect_ratio = (1, 1)

    scene = ngl.DrawColor(geometry=ngl.Quad())
    return ngl.Rotate(scene, angle=45)
graph
Rotate a quad by 360Β° over the course of 3 seconds
Code
Graph
import pynopegl as ngl


@ngl.scene()
def animated_rotate(cfg: ngl.SceneCfg):
    cfg.aspect_ratio = (1, 1)
    cfg.duration = 3

    animkf = [
        ngl.AnimKeyFrameFloat(0, 0),
        ngl.AnimKeyFrameFloat(cfg.duration, 360),
    ]

    scene = ngl.DrawColor(geometry=ngl.Quad())
    return ngl.Rotate(scene, angle=ngl.AnimatedFloat(animkf))
graph
Translate a circle from one side to another, and back
Code
Graph
import pynopegl as ngl


@ngl.scene()
def animated_translate(cfg: ngl.SceneCfg):
    cfg.aspect_ratio = (1, 1)
    cfg.duration = 3

    animkf = [
        ngl.AnimKeyFrameVec3(0, (-1 / 3, 0, 0)),
        ngl.AnimKeyFrameVec3(cfg.duration / 2, (1 / 3, 0, 0)),
        ngl.AnimKeyFrameVec3(cfg.duration, (-1 / 3, 0, 0)),
    ]

    scene = ngl.DrawColor(geometry=ngl.Circle(0.5))
    return ngl.Translate(scene, vector=ngl.AnimatedVec3(animkf))
graph
Scale up and down a circle
Code
Graph
import pynopegl as ngl


@ngl.scene()
def animated_scale(cfg: ngl.SceneCfg):
    cfg.aspect_ratio = (1, 1)
    cfg.duration = 3

    animkf = [
        ngl.AnimKeyFrameVec3(0, (1 / 3, 1 / 3, 1 / 3)),
        ngl.AnimKeyFrameVec3(cfg.duration / 2, (3 / 4, 3 / 4, 3 / 4)),
        ngl.AnimKeyFrameVec3(cfg.duration, (1 / 3, 1 / 3, 1 / 3)),
    ]

    scene = ngl.DrawColor(geometry=ngl.Circle(0.5))
    return ngl.Scale(scene, factors=ngl.AnimatedVec3(animkf))
graph

To combine transforms, they have to be chained. The following example combines 3 of them: Scale(Translate(Rotate(...))):

A chain of animated transforms
Code
Graph
import pynopegl as ngl


@ngl.scene()
def chained_transforms(cfg: ngl.SceneCfg):
    cfg.duration = 5
    cfg.aspect_ratio = (1, 1)

    group = ngl.Group()
    radius = 0.2
    n = 10
    step = 360 / n

    shape = ngl.Circle(radius=radius, npoints=128)
    draw = ngl.DrawColor(geometry=shape)

    for i in range(n):
        mid_time = cfg.duration / 2.0
        start_time = mid_time / (i + 2)
        end_time = cfg.duration - start_time

        scale_animkf = [
            ngl.AnimKeyFrameVec3(start_time, (0, 0, 0)),
            ngl.AnimKeyFrameVec3(mid_time, (1, 1, 1), "exp_out"),
            ngl.AnimKeyFrameVec3(end_time, (0, 0, 0), "exp_in"),
        ]

        angle = i * step
        rotate_animkf = [
            ngl.AnimKeyFrameFloat(start_time, 0),
            ngl.AnimKeyFrameFloat(mid_time, angle, "exp_out"),
            ngl.AnimKeyFrameFloat(end_time, 0, "exp_in"),
        ]

        tnode = draw
        tnode = ngl.Scale(tnode, factors=ngl.AnimatedVec3(scale_animkf))
        tnode = ngl.Translate(tnode, vector=(1 - radius, 0, 0))
        tnode = ngl.Rotate(tnode, angle=ngl.AnimatedFloat(rotate_animkf))

        group.add_children(tnode)

    return group
graph