def gradient_eval(cfg, mode="ramp", c0=(1, 0.5, 0.5), c1=(0.5, 1, 0.5)): """Animate a gradient and objects using CPU evaluation""" pos_res = dict(t=ngl.Time()) pos0_x = ngl.EvalFloat("sin( 0.307*t - 0.190)", resources=pos_res) pos0_y = ngl.EvalFloat("sin( 0.703*t - 0.957)", resources=pos_res) pos1_x = ngl.EvalFloat("sin(-0.236*t + 0.218)", resources=pos_res) pos1_y = ngl.EvalFloat("sin(-0.851*t - 0.904)", resources=pos_res) trf0 = ngl.EvalVec3("x", "y", "0", resources=dict(x=pos0_x, y=pos0_y)) trf1 = ngl.EvalVec3("x", "y", "0", resources=dict(x=pos1_x, y=pos1_y)) geom = ngl.Circle(radius=0.02, npoints=64) p0 = ngl.RenderColor(color=(1 - c0[0], 1 - c0[1], 1 - c0[2]), geometry=geom) p1 = ngl.RenderColor(color=(1 - c1[0], 1 - c1[1], 1 - c1[2]), geometry=geom) p0 = ngl.Scale(p0, factors=(1 / cfg.aspect_ratio_float, 1, 1)) p1 = ngl.Scale(p1, factors=(1 / cfg.aspect_ratio_float, 1, 1)) p0 = ngl.Translate(p0, vector=trf0) p1 = ngl.Translate(p1, vector=trf1) pos0 = ngl.EvalVec2("x/2+.5", ".5-y/2", resources=dict(x=pos0_x, y=pos0_y)) pos1 = ngl.EvalVec2("x/2+.5", ".5-y/2", resources=dict(x=pos1_x, y=pos1_y)) grad = ngl.RenderGradient(pos0=pos0, pos1=pos1, mode=mode, color0=c0, color1=c1) return ngl.Group(children=(grad, p0, p1))
def get_debug_points(cfg, points, radius=0.025, color=COLORS['green'], text_size=(0.1, 0.1)): prog = ngl.Program(vertex=cfg.get_vert('color'), fragment=cfg.get_frag('color')) g = ngl.Group() circle = ngl.Circle(radius=radius) circle_render = ngl.Render(circle, prog) circle_render.update_uniforms(color=ngl.UniformVec4(value=color)) box_w = (text_size[0], 0, 0) box_h = (0, text_size[1], 0) for pos_name, position in points.items(): text = ngl.Text(pos_name, box_width=box_w, box_height=box_h, bg_color=(0, 0, 0, 0), valign='top') text = ngl.Translate(text, (1 + radius, 1 - radius - text_size[1], 0)) point = ngl.Group(children=(circle_render, text)) point = ngl.Translate(point, list(position) + [0]) g.add_children(point) return ngl.GraphicConfig(g, blend=True, blend_src_factor='src_alpha', blend_dst_factor='one_minus_src_alpha', blend_src_factor_a='zero', blend_dst_factor_a='one', label='Debug circles')
def animated_camera(cfg, rotate=True): '''Animated camera around a scene''' g = ngl.Group() q = ngl.Quad((-0.5, -0.5, 0), (1, 0, 0), (0, 1, 0)) m = ngl.Media(cfg.medias[0].filename) t = ngl.Texture2D(data_src=m) program = ngl.Program(vertex=cfg.get_vert('texture'), fragment=cfg.get_frag('texture')) program.update_vert_out_vars(var_uvcoord=ngl.IOVec2(), var_tex0_coord=ngl.IOVec2()) node = ngl.Render(q, program) node.update_frag_resources(tex0=t) g.add_children(node) translate = ngl.Translate(node, vector=(-0.6, 0.8, -1)) g.add_children(translate) translate = ngl.Translate(node, vector=(0.6, 0.8, -1)) g.add_children(translate) translate = ngl.Translate(node, vector=(-0.6, -0.5, -1)) g.add_children(translate) translate = ngl.Translate(node, vector=(0.6, -0.5, -1)) g.add_children(translate) g = ngl.GraphicConfig(g, depth_test=True) camera = ngl.Camera(g) camera.set_eye(0, 0, 2) camera.set_center(0.0, 0.0, 0.0) camera.set_up(0.0, 1.0, 0.0) camera.set_perspective(45.0, cfg.aspect_ratio_float) camera.set_clipping(0.1, 10.0) tr_animkf = [ ngl.AnimKeyFrameVec3(0, (0.0, 0.0, 0.0)), ngl.AnimKeyFrameVec3(10, (0.0, 0.0, 3.0), 'exp_out') ] node = ngl.Translate(ngl.Identity(), anim=ngl.AnimatedVec3(tr_animkf)) if rotate: rot_animkf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 360, 'exp_out') ] node = ngl.Rotate(node, axis=(0, 1, 0), anim=ngl.AnimatedFloat(rot_animkf)) camera.set_eye_transform(node) fov_animkf = [ ngl.AnimKeyFrameFloat(0.5, 60.0), ngl.AnimKeyFrameFloat(cfg.duration, 45.0, 'exp_out') ] camera.set_fov_anim(ngl.AnimatedFloat(fov_animkf)) return camera
def transform_animated_camera(cfg): cfg.duration = 5. g = ngl.Group() elems = ( ('red', None), ('yellow', (-0.6, 0.8, -1)), ('green', (0.6, 0.8, -1)), ('cyan', (-0.6, -0.5, -1)), ('magenta', (0.6, -0.5, -1)), ) quad = ngl.Quad((-0.5, -0.5, 0), (1, 0, 0), (0, 1, 0)) prog = ngl.Program(vertex=cfg.get_vert('color'), fragment=cfg.get_frag('color')) for color, vector in elems: node = ngl.Render(quad, prog) node.update_uniforms(color=ngl.UniformVec4(value=COLORS[color])) if vector: node = ngl.Translate(node, vector=vector) g.add_children(node) g = ngl.GraphicConfig(g, depth_test=True) camera = ngl.Camera(g) camera.set_eye(0, 0, 2) camera.set_center(0.0, 0.0, 0.0) camera.set_up(0.0, 1.0, 0.0) camera.set_perspective(45.0, cfg.aspect_ratio_float) camera.set_clipping(0.1, 10.0) tr_animkf = [ ngl.AnimKeyFrameVec3(0, (0.0, 0.0, 0.0)), ngl.AnimKeyFrameVec3(cfg.duration, (0.0, 0.0, 3.0)) ] eye_transform = ngl.Translate(ngl.Identity(), anim=ngl.AnimatedVec3(tr_animkf)) rot_animkf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 360) ] eye_transform = ngl.Rotate(eye_transform, axis=(0, 1, 0), anim=ngl.AnimatedFloat(rot_animkf)) camera.set_eye_transform(eye_transform) fov_animkf = [ ngl.AnimKeyFrameFloat(0.5, 60.0), ngl.AnimKeyFrameFloat(cfg.duration, 45.0) ] camera.set_fov_anim(ngl.AnimatedFloat(fov_animkf)) return camera
def animated_camera(cfg, rotate=True): """Animated camera around a scene""" g = ngl.Group() q = ngl.Quad((-0.5, -0.5, 0), (1, 0, 0), (0, 1, 0)) m = ngl.Media(cfg.medias[0].filename) t = ngl.Texture2D(data_src=m) node = ngl.RenderTexture(t, geometry=q) g.add_children(node) translate = ngl.Translate(node, vector=(-0.6, 0.8, -1)) g.add_children(translate) translate = ngl.Translate(node, vector=(0.6, 0.8, -1)) g.add_children(translate) translate = ngl.Translate(node, vector=(-0.6, -0.5, -1)) g.add_children(translate) translate = ngl.Translate(node, vector=(0.6, -0.5, -1)) g.add_children(translate) g = ngl.GraphicConfig(g, depth_test=True) camera = ngl.Camera(g) camera.set_eye(0, 0, 2) camera.set_center(0.0, 0.0, 0.0) camera.set_up(0.0, 1.0, 0.0) camera.set_clipping(0.1, 10.0) tr_animkf = [ ngl.AnimKeyFrameVec3(0, (0.0, 0.0, 0.0)), ngl.AnimKeyFrameVec3(10, (0.0, 0.0, 3.0), "exp_out") ] node = ngl.Translate(ngl.Identity(), vector=ngl.AnimatedVec3(tr_animkf)) if rotate: rot_animkf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 360, "exp_out") ] node = ngl.Rotate(node, axis=(0, 1, 0), angle=ngl.AnimatedFloat(rot_animkf)) camera.set_eye_transform(node) perspective_animkf = [ ngl.AnimKeyFrameVec2(0.5, (60.0, cfg.aspect_ratio_float)), ngl.AnimKeyFrameVec2(cfg.duration, (45.0, cfg.aspect_ratio_float), "exp_out"), ] camera.set_perspective(ngl.AnimatedVec2(perspective_animkf)) return camera
def transform_animated_camera(cfg): cfg.duration = 5.0 g = ngl.Group() elems = ( # fmt: off (COLORS.red, None), (COLORS.yellow, (-0.6, 0.8, -1)), (COLORS.green, (0.6, 0.8, -1)), (COLORS.cyan, (-0.6, -0.5, -1)), (COLORS.magenta, (0.6, -0.5, -1)), # fmt: on ) quad = ngl.Quad((-0.5, -0.5, 0), (1, 0, 0), (0, 1, 0)) for color, vector in elems: node = ngl.RenderColor(color, geometry=quad) if vector: node = ngl.Translate(node, vector=vector) g.add_children(node) g = ngl.GraphicConfig(g, depth_test=True) camera = ngl.Camera(g) camera.set_eye(0, 0, 2) camera.set_center(0.0, 0.0, 0.0) camera.set_up(0.0, 1.0, 0.0) camera.set_clipping(0.1, 10.0) tr_animkf = [ ngl.AnimKeyFrameVec3(0, (0.0, 0.0, 0.0)), ngl.AnimKeyFrameVec3(cfg.duration, (0.0, 0.0, 3.0)) ] eye_transform = ngl.Translate(ngl.Identity(), vector=ngl.AnimatedVec3(tr_animkf)) rot_animkf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 360) ] eye_transform = ngl.Rotate(eye_transform, axis=(0, 1, 0), angle=ngl.AnimatedFloat(rot_animkf)) camera.set_eye_transform(eye_transform) perspective_animkf = [ ngl.AnimKeyFrameVec2(0.5, (60.0, cfg.aspect_ratio_float)), ngl.AnimKeyFrameVec2(cfg.duration, (45.0, cfg.aspect_ratio_float)), ] camera.set_perspective(ngl.AnimatedVec2(perspective_animkf)) return camera
def animated_square(cfg, color=(1, 0.66, 0), rotate=True, scale=True, translate=True): """Animated Translate/Scale/Rotate on a square""" cfg.duration = 5.0 cfg.aspect_ratio = (1, 1) sz = 1 / 3.0 q = ngl.Quad((-sz / 2, -sz / 2, 0), (sz, 0, 0), (0, sz, 0)) node = ngl.RenderColor(color, geometry=q) coords = [(-1, 1), (1, 1), (1, -1), (-1, -1), (-1, 1)] if rotate: animkf = (ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 360)) node = ngl.Rotate(node, angle=ngl.AnimatedFloat(animkf)) if scale: animkf = ( ngl.AnimKeyFrameVec3(0, (1, 1, 1)), ngl.AnimKeyFrameVec3(cfg.duration / 2, (2, 2, 2)), ngl.AnimKeyFrameVec3(cfg.duration, (1, 1, 1)), ) node = ngl.Scale(node, factors=ngl.AnimatedVec3(animkf)) if translate: animkf = [] tscale = 1.0 / float(len(coords) - 1) * cfg.duration for i, xy in enumerate(coords): pos = (xy[0] * 0.5, xy[1] * 0.5, 0) t = i * tscale animkf.append(ngl.AnimKeyFrameVec3(t, pos)) node = ngl.Translate(node, vector=ngl.AnimatedVec3(animkf)) return node
def velocity_circle_distort_3d(cfg): cfg.duration = 4.0 cfg.aspect_ratio = (1, 1) coords = list(equilateral_triangle_coords()) coords.append(coords[0]) pos_kf = [ ngl.AnimKeyFrameVec3(cfg.duration * i / 3.0, pos, "exp_in_out") for i, pos in enumerate(coords) ] anim = ngl.AnimatedVec3(pos_kf) velocity = ngl.VelocityVec3(anim) vert = textwrap.dedent("""\ void main() { float distort_max = 0.1; float velocity_l = length(velocity); float direction_l = length(ngl_position); vec3 normed_velocity = velocity_l == 0.0 ? vec3(0.0) : -velocity / velocity_l; vec3 normed_direction = direction_l == 0.0 ? vec3(0.0) : ngl_position / direction_l; float distort = clamp(dot(normed_velocity, normed_direction) / 2.0 * distort_max, 0.0, 1.0); vec4 pos = vec4(ngl_position, 1.0) + vec4(-distort * velocity, 0.0); ngl_out_pos = ngl_projection_matrix * ngl_modelview_matrix * pos; } """) geom = ngl.Circle(radius=0.2, npoints=128) prog = ngl.Program(vertex=vert, fragment=cfg.get_frag("color")) shape = ngl.Render(geom, prog) shape.update_frag_resources(color=ngl.UniformVec3(COLORS.white), opacity=ngl.UniformFloat(1)) shape.update_vert_resources(velocity=velocity) return ngl.Translate(shape, vector=anim)
def _path_scene(cfg, path, points=None, controls=None, easing="linear"): cfg.aspect_ratio = (1, 1) anim_kf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 1, easing), ] geom = ngl.Circle(radius=0.03, npoints=32) shape = ngl.RenderColor(COLORS.orange, geometry=geom) moving_shape = ngl.Translate(shape, vector=ngl.AnimatedPath(anim_kf, path)) objects = [] if points: debug_points = {f"P{i}": p[:2] for i, p in enumerate(points)} objects.append(get_debug_points(cfg, debug_points)) if controls: debug_controls = {f"C{i}": p[:2] for i, p in enumerate(controls)} objects.append(get_debug_points(cfg, debug_controls, color=COLORS.cyan)) objects.append(moving_shape) return ngl.Group(children=objects)
def _get_background_circles(circle, positions, bcolor): blend_bg = ngl.Group() render = ngl.RenderColor(bcolor, geometry=circle) for position in positions: trender = ngl.Translate(render, position + (0.0, )) blend_bg.add_children(trender) return blend_bg
def transform_path(cfg): cfg.aspect_ratio = (1, 1) cfg.duration = 7 shape = _transform_shape(cfg, w=0.2, h=0.5) # fmt: off points = ( (0.7, 0.0, -0.3), (-0.8, -0.1, 0.1), ) controls = ( (0.2, 0.3, -0.2), (-0.2, -0.8, -0.4), ) # fmt: on keyframes = ( ngl.PathKeyMove(to=points[0]), ngl.PathKeyLine(to=points[1]), ngl.PathKeyBezier2(control=controls[0], to=points[0]), ngl.PathKeyBezier3(control1=controls[0], control2=controls[1], to=points[1]), ) path = ngl.Path(keyframes) # We use back_in_out easing to force an overflow on both sides anim_kf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration - 1, 1, "back_in_out"), ] return ngl.Translate(shape, vector=ngl.AnimatedPath(anim_kf, path))
def transform_smoothpath(cfg): cfg.aspect_ratio = (1, 1) cfg.duration = 3 shape = _transform_shape(cfg, w=0.3, h=0.3) # fmt: off points = ( (-0.62, -0.30, 0.0), (-0.36, 0.40, 0.0), (0.04, -0.27, 0.0), (0.36, 0.28, 0.0), (0.65, -0.04, 0.0), ) controls = ( (-0.84, 0.07, 0.0), (0.84, 0.04, 0.0), ) # fmt: on flat_points = (elt for point in points for elt in point) points_array = array.array("f", flat_points) path = ngl.SmoothPath( ngl.BufferVec3(data=points_array), control1=controls[0], control2=controls[1], tension=0.4, ) anim_kf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 1, "exp_in_out"), ] return ngl.Translate(shape, vector=ngl.AnimatedPath(anim_kf, path))
def _get_background_circles(circle, prog, positions, bcolor): blend_bg = ngl.Group() render = ngl.Render(circle, prog) render.update_frag_resources(color=ngl.UniformVec4(value=bcolor)) for position in positions: trender = ngl.Translate(render, position) blend_bg.add_children(trender) return blend_bg
def _get_userlive_select_func(): # We point on the same underlying render to test the different render paths render = ngl.RenderColor(COLORS.white, opacity=0.5, geometry=ngl.Quad()) below = ngl.Translate(render, vector=(0.5 - 2 / 3, 0.5 - 1 / 3, 0)) above = ngl.Translate(render, vector=(0.5 - 1 / 3, 0.5 - 2 / 3, 0)) # Additive blending (for premultiplied values): lighten gc0 = ngl.GraphicConfig( above, blend=True, blend_src_factor="one", blend_dst_factor="one", blend_src_factor_a="one", blend_dst_factor_a="one", ) # Multiply blending (for premultiplied values): darken gc1 = ngl.GraphicConfig( above, blend=True, blend_src_factor="zero", blend_dst_factor="src_color", blend_src_factor_a="zero", blend_dst_factor_a="src_alpha", ) # Select has 3 branches: simple over blending, additive blending, multiply # blending select = ngl.UserSelect(branches=(above, gc0, gc1)) def keyframes_callback(t_id): # 4 states: the for the 3 blending branches and one extra for nothing # (branch ID overflow). We remain on the each state for 2 frames. select.set_branch((t_id // 2) % 4) @test_fingerprint(nb_keyframes=8, keyframes_callback=keyframes_callback, tolerance=1, exercise_serialization=False) @scene(branch=scene.Range([0, 3])) def scene_func(cfg, branch=0): cfg.aspect_ratio = (1, 1) select.set_branch(branch) return ngl.Group(children=(below, select)) return scene_func
def _get_blending_base_objects(): circle = ngl.Circle(radius=_CIRCLE_RADIUS, npoints=100) positions = _equilateral_triangle_coords(_CIRCLE_RADIUS * 2.0 / 3.0) colored_circles = ngl.Group(label="colored circles") for position, color in zip(positions, _CIRCLES_COLORS): render = ngl.RenderColor(color, geometry=circle) render = ngl.Translate(render, position + (0.0, )) colored_circles.add_children(render) return colored_circles, circle, positions
def _get_blending_base_objects(cfg): circle = ngl.Circle(radius=_CIRCLE_RADIUS, npoints=100) prog = ngl.Program(vertex=cfg.get_vert('color'), fragment=cfg.get_frag('color')) positions = _equilateral_triangle_coords(_CIRCLE_RADIUS * 2.0 / 3.0) colored_circles = ngl.Group(label='colored circles') for position, color in zip(positions, _CIRCLES_COLORS): render = ngl.Render(circle, prog) render.update_frag_resources(color=ngl.UniformVec4(value=color)) render = ngl.Translate(render, position) colored_circles.add_children(render) return colored_circles, circle, prog, positions
def transform_translate_animated(cfg): cfg.aspect_ratio = (1, 1) cfg.duration = 3.0 p0, p1, p2 = equilateral_triangle_coords() anim = [ ngl.AnimKeyFrameVec3(0, p0), ngl.AnimKeyFrameVec3(1 * cfg.duration / 3.0, p1), ngl.AnimKeyFrameVec3(2 * cfg.duration / 3.0, p2), ngl.AnimKeyFrameVec3(cfg.duration, p0), ] shape = _transform_shape(cfg) return ngl.Translate(shape, vector=ngl.AnimatedVec3(anim))
def get_debug_points(cfg, points, radius=0.025, color=COLORS.green, text_size=(0.1, 0.1)): g = ngl.Group(label="Debug circles") circle = ngl.Circle(radius=radius) circle_render = ngl.RenderColor(color, geometry=circle) box_w = (text_size[0], 0, 0) box_h = (0, text_size[1], 0) for pos_name, position in points.items(): text = ngl.Text(pos_name, box_width=box_w, box_height=box_h, bg_opacity=0, valign="top") text = ngl.Translate(text, (1 + radius, 1 - radius - text_size[1], 0)) point = ngl.Group(children=(circle_render, text)) point = ngl.Translate(point, list(position) + [0]) g.add_children(point) return g
def _debug_overlay(cfg, scene, grid_names, show_dbg_points=False, show_labels=False): if not show_dbg_points and not show_labels: return scene assert grid_names is not None text_height = 0.25 overlay = ngl.Group() if show_labels: text_group = ngl.Group() ag = AutoGrid(grid_names) for grid_name, _, col, row in ag: text = ngl.Text( grid_name, fg_color=COLORS.white, bg_opacity=1, valign="top", box_width=(2.0, 0, 0), box_height=(0, text_height, 0), box_corner=(-1, 1.0 - text_height, 0), ) text = ag.place_node(text, (col, row)) text_group.add_children(text) scene = ngl.Translate(scene, (0, -text_height / 2.0 * ag.scale, 0), label="text offsetting") overlay.add_children(scene, text_group) else: overlay.add_children(scene) if show_dbg_points: nb = len(grid_names) dbg_positions = _get_dbg_positions(nb) if show_labels: dbg_positions = { name: (p[0], p[1] - text_height / 2.0 * ag.scale) for name, p in dbg_positions.items() } dbg_points = get_debug_points(cfg, dbg_positions, radius=0.01, text_size=(0.08, 0.08)) overlay.add_children(dbg_points) return overlay
def _get_easing_nodes(cfg, color_program): ag = AutoGrid(_easing_list) cfg.aspect_ratio = (ag.nb_cols, ag.nb_rows) easing_h = 1. / ag.nb_rows easing_w = 1. / ag.nb_cols for easing, easing_id, col, row in ag: easing_name, zoom = easing easing_node = _get_easing_node(cfg, easing_name, zoom, color_program) easing_node = ngl.Scale(easing_node, factors=[easing_w, easing_h, 0]) x = easing_w * (-ag.nb_cols + 1 + 2 * col) y = easing_h * (ag.nb_rows - 1 - 2 * row) easing_node = ngl.Translate(easing_node, vector=(x, y, 0)) yield easing_node
def api_denied_node_live_change(width=320, height=240): ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=width, height=height, backend=_backend) assert ret == 0 scene = ngl.Translate(ngl.Group()) # Check that we can live change but not into a node assert ctx.set_scene(scene) == 0 assert scene.set_vector(1, 2, 3) == 0 assert scene.set_vector(ngl.UniformVec3(value=(3, 2, 1))) != 0 # Check that we can do the change after a reset of the context assert ctx.set_scene(None) == 0 assert scene.set_vector(ngl.UniformVec3(value=(4, 5, 6))) == 0 # Check that we can not live unplug a node from a live changeable parameter assert ctx.set_scene(scene) == 0 assert scene.set_vector(ngl.UniformVec3(value=(7, 8, 9))) != 0
def animated_circles(cfg): '''Simple cyclic circles animation''' group = ngl.Group() cfg.duration = 5. cfg.aspect_ratio = (1, 1) radius = 0.2 n = 10 step = 360. / n shape = ngl.Circle(radius=radius, npoints=128) prog = ngl.Program(vertex=cfg.get_vert('color'), fragment=cfg.get_frag('color')) render = ngl.Render(shape, prog) render.update_uniforms(color=ngl.UniformVec4([1.0] * 4)) 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.0, 1.0, 1.0), '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 = render tnode = ngl.Scale(tnode, anim=ngl.AnimatedVec3(scale_animkf)) tnode = ngl.Translate(tnode, vector=(1 - radius, 0, 0)) tnode = ngl.Rotate(tnode, anim=ngl.AnimatedFloat(rotate_animkf)) group.add_children(tnode) return group
def _get_random_transform(cfg, rng, t0, t1, child): translate = lambda rng, child: ngl.Translate( child, vector=_get_random_animated_vec3(rng, t0, t1, _get_random_position), ) scale = lambda rng, child: ngl.Scale( child, factors=_get_random_animated_vec3(rng, t0, t1, _get_random_factors), anchor=_get_random_anchor(rng), ) rotate = lambda rng, child: ngl.Rotate( child, angle=_get_random_animated_float(rng, t0, t1, _get_random_angle), anchor=_get_random_anchor(rng), ) for i in range(rng.randint(1, 2)): trf_func = rng.choice((translate, scale, rotate)) child = trf_func(rng, child) return child
def animated_square(cfg, color=(1, 0.66, 0, 1), rotate=True, scale=True, translate=True): '''Animated Translate/Scale/Rotate on a square''' cfg.duration = 5.0 cfg.aspect_ratio = (1, 1) sz = 1 / 3. q = ngl.Quad((-sz / 2, -sz / 2, 0), (sz, 0, 0), (0, sz, 0)) p = ngl.Program(vertex=cfg.get_vert('color'), fragment=cfg.get_frag('color')) node = ngl.Render(q, p) ucolor = ngl.UniformVec4(value=color) node.update_uniforms(color=ucolor) coords = [(-1, 1), (1, 1), (1, -1), (-1, -1), (-1, 1)] if rotate: animkf = (ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 360)) node = ngl.Rotate(node, anim=ngl.AnimatedFloat(animkf)) if scale: animkf = (ngl.AnimKeyFrameVec3(0, (1, 1, 1)), ngl.AnimKeyFrameVec3(cfg.duration / 2, (2, 2, 2)), ngl.AnimKeyFrameVec3(cfg.duration, (1, 1, 1))) node = ngl.Scale(node, anim=ngl.AnimatedVec3(animkf)) if translate: animkf = [] tscale = 1. / float(len(coords) - 1) * cfg.duration for i, xy in enumerate(coords): pos = (xy[0] * .5, xy[1] * .5, 0) t = i * tscale animkf.append(ngl.AnimKeyFrameVec3(t, pos)) node = ngl.Translate(node, anim=ngl.AnimatedVec3(animkf)) return node
def animated_circles(cfg): """Simple cyclic circles animation""" group = ngl.Group() cfg.duration = 5.0 cfg.aspect_ratio = (1, 1) radius = 0.2 n = 10 step = 360.0 / n shape = ngl.Circle(radius=radius, npoints=128) render = ngl.RenderColor(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.0, 1.0, 1.0), "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 = render 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
def _get_easing_nodes(cfg, color_program): easings = _easing_list nb_easings = len(easings) nb_rows = int(math.sqrt(nb_easings)) nb_cols = int(math.ceil(nb_easings / float(nb_rows))) cfg.aspect_ratio = (nb_cols, nb_rows) easing_h = 1. / nb_rows easing_w = 1. / nb_cols for row in range(nb_rows): for col in range(nb_cols): easing_id = row * nb_cols + col if easing_id >= nb_easings: return easing, zoom = easings[easing_id] easing_node = _get_easing_node(cfg, easing, zoom, color_program) easing_node = ngl.Scale(easing_node, factors=[easing_w, easing_h, 0]) x = easing_w * (-nb_cols + 1 + 2 * col) y = easing_h * (nb_rows - 1 - 2 * row) easing_node = ngl.Translate(easing_node, vector=(x, y, 0)) yield easing_node
def _get_live_trf_spec(layout): t0 = ngl.Identity() t1 = ngl.Transform(t0) t2 = ngl.Translate(t1) t3 = ngl.Rotate(t2) t4 = ngl.Scale(t3) t5 = ngl.RotateQuat(t4) return [ dict( name='m4', type='mat4', category='single', func=lambda data: ngl.UniformMat4(data, transform=t5), livechange=( lambda: t1.set_matrix( # trf_step=1 0.1, 0.2, 0.0, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.0, 0.5, 0.0, 0.8, 0.7, 0.0, 0.6, ), lambda: t2.set_vector(0.2, 0.7, -0.4), # trf_step=2 lambda: t3.set_angle(123.4), # trf_step=3 lambda: t4.set_factors(0.7, 1.4, 0.2), # trf_step=4 lambda: t5.set_quat(0, 0, -0.474, 0.880), # trf_step=5 lambda: t5.set_quat(0, 0, 0, 1), lambda: t4.set_factors(1, 1, 1), lambda: t3.set_angle(0), lambda: t2.set_vector(0, 0, 0), lambda: t1.set_matrix( 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, )), ), ]
def _get_easing_node(cfg, easing, curve_zoom, color_program, nb_points=128): text_vratio = 1 / 8. graph_hpad_ratio = 1 / 16. area_size = 2.0 width, height = area_size, area_size text_height = text_vratio * height pad_height = graph_hpad_ratio * height # Colors hue = random.uniform(0, 0.6) color = list(colorsys.hls_to_rgb(hue, 0.6, 1.0)) + [1] ucolor = ngl.UniformVec4(value=color) graph_bg_ucolor = ngl.UniformVec4(value=(.15, .15, .15, 1)) normed_graph_bg_ucolor = ngl.UniformVec4(value=(0, 0, 0, 1)) line_ucolor = ngl.UniformVec4(value=(1, 1, 1, .4)) # Text legend text = ngl.Text(text=easing, fg_color=color, padding=3, bg_color=(0, 0, 0, 1), box_corner=(-width / 2., height / 2. - text_height, 0), box_width=(width, 0, 0), box_height=(0, text_height, 0), label='%s legend' % easing) # Graph drawing area (where the curve may overflow) graph_size = area_size - text_height - pad_height * 2 graph_block = _block(graph_size, graph_size, color_program, corner=(-graph_size / 2, -(graph_size + text_height) / 2, 0), color=graph_bg_ucolor) # Normed area of the graph normed_graph_size = graph_size * curve_zoom normed_graph_block = _block(normed_graph_size, normed_graph_size, color_program, corner=(-normed_graph_size / 2, -(normed_graph_size + text_height) / 2, 0), color=normed_graph_bg_ucolor) # Curve easing_name, easing_args = _easing_split(easing) curve_scale_factor = graph_size / area_size * curve_zoom vertices_data = array.array('f') for i in range(nb_points + 1): t = i / float(nb_points) v = ngl.easing_evaluate(easing_name, t, easing_args) x = curve_scale_factor * (t * width - width / 2.) y = curve_scale_factor * (v * height - height / 2.) y -= text_height / 2. vertices_data.extend([x, y, 0]) vertices = ngl.BufferVec3(data=vertices_data) geometry = ngl.Geometry(vertices, topology='line_strip') curve = ngl.Render(geometry, color_program, label='%s curve' % easing) curve.update_uniforms(color=ucolor) # Value cursor y = 2 / 3. * pad_height x = y * math.sqrt(3) cursor_geometry = ngl.Triangle((-x, y, 0), (0, 0, 0), (-x, -y, 0)) cursor = ngl.Render(cursor_geometry, color_program, label='%s cursor' % easing) cursor.update_uniforms(color=ucolor) # Horizontal value line hline_data = array.array('f', (0, 0, 0, graph_size, 0, 0)) hline_vertices = ngl.BufferVec3(data=hline_data) hline_geometry = ngl.Geometry(hline_vertices, topology='line_strip') hline = ngl.Render(hline_geometry, color_program, label='%s value line' % easing) hline.update_uniforms(color=line_ucolor) # Value animation (cursor + h-line) value_x = -graph_size / 2. value_y = (-text_height - normed_graph_size) / 2. value_animkf = ( ngl.AnimKeyFrameVec3(0, (value_x, value_y, 0)), ngl.AnimKeyFrameVec3(cfg.duration, (value_x, value_y + normed_graph_size, 0), easing_name, easing_args), ) value_anim = ngl.Group(children=(hline, cursor)) value_anim = ngl.Translate(value_anim, anim=ngl.AnimatedVec3(value_animkf), label='%s value anim' % easing) # Vertical time line vline_data = array.array('f', (0, 0, 0, 0, graph_size, 0)) vline_vertices = ngl.BufferVec3(data=vline_data) vline_geometry = ngl.Geometry(vline_vertices, topology='line_strip') vline = ngl.Render(vline_geometry, color_program, label='%s time line' % easing) vline.update_uniforms(color=line_ucolor) # Time animation (v-line only) time_x = -normed_graph_size / 2. time_y = (-text_height - graph_size) / 2. time_animkf = (ngl.AnimKeyFrameVec3(0, (time_x, time_y, 0)), ngl.AnimKeyFrameVec3( cfg.duration, (time_x + normed_graph_size, time_y, 0))) time_anim = ngl.Translate(vline, anim=ngl.AnimatedVec3(time_animkf), label='%s time anim' % easing) group = ngl.Group(label='%s block' % easing) group.add_children(text, graph_block, normed_graph_block, curve, value_anim, time_anim) return group
def _get_live_trf_spec(): t0 = ngl.Identity() t1 = ngl.Transform(t0) t2 = ngl.Translate(t1) t3 = ngl.Rotate(t2) t4 = ngl.Scale(t3) t5 = ngl.RotateQuat(t4) t6 = ngl.Skew(t5) return [ dict( name="m4", type="mat4", category="single", func=lambda data: ngl.UniformMat4(data, transform=t6), livechange=( # fmt: off lambda: t1.set_matrix( # trf_step=1 0.1, 0.2, 0.0, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.0, 0.5, 0.0, 0.8, 0.7, 0.0, 0.6, ), lambda: t2.set_vector(0.2, 0.7, -0.4), # trf_step=2 lambda: t3.set_angle(123.4), # trf_step=3 lambda: t4.set_factors(0.7, 1.4, 0.2), # trf_step=4 lambda: t5.set_quat(0, 0, -0.474, 0.880), # trf_step=5 lambda: t6.set_angles(0, 50, -145), # trf_step=6 lambda: t6.set_angles(0, 0, 0), lambda: t5.set_quat(0, 0, 0, 1), lambda: t4.set_factors(1, 1, 1), lambda: t3.set_angle(0), lambda: t2.set_vector(0, 0, 0), lambda: t1.set_matrix( 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, ) # fmt: on ), ), ]
def transform_translate(cfg, vector=(0.2, 0.7, -0.4)): cfg.aspect_ratio = (1, 1) shape = _transform_shape(cfg) return ngl.Translate(shape, vector)