def _get_compositing_scene(cfg, op, show_label=False): cfg.aspect_ratio = (1, 1) cfg.duration = 6 # We can not use a circle geometry because the whole areas must be # rasterized for the compositing to work, so instead we build 2 overlapping # quad into which we draw colored circles, offsetted with an animation. # Alternatively, we could use a RTT. quad = ngl.Quad(corner=(-1, -1, 0), width=(2, 0, 0), height=(0, 2, 0)) prog = ngl.Program(vertex=_VERTEX, fragment=_FRAGMENT) prog.update_vert_out_vars(uv=ngl.IOVec2()) A_off_kf = ( ngl.AnimKeyFrameVec2(0, (-1 / 3, 0)), ngl.AnimKeyFrameVec2(cfg.duration / 2, (1 / 3, 0)), ngl.AnimKeyFrameVec2(cfg.duration, (-1 / 3, 0)), ) B_off_kf = ( ngl.AnimKeyFrameVec2(0, (1 / 3, 0)), ngl.AnimKeyFrameVec2(cfg.duration / 2, (-1 / 3, 0)), ngl.AnimKeyFrameVec2(cfg.duration, (1 / 3, 0)), ) A_off = ngl.AnimatedVec2(A_off_kf) B_off = ngl.AnimatedVec2(B_off_kf) A = ngl.Render(quad, prog, label="A") A.update_frag_resources(color=ngl.UniformVec3(value=COLORS.azure), off=A_off) B = ngl.Render(quad, prog, label="B", blending=op) B.update_frag_resources(color=ngl.UniformVec3(value=COLORS.orange), off=B_off) bg = ngl.RenderColor(blending="dst_over") # draw A in current FBO, then draw B with the current operator, and # then result goes over the white background ret = ngl.Group(children=(A, B, bg)) if show_label: label_h = 1 / 4 label_pad = 0.1 label = ngl.Text( op, fg_color=COLORS.black, bg_color=(0.8, 0.8, 0.8), bg_opacity=1, box_corner=(label_pad / 2 - 1, 1 - label_h - label_pad / 2, 0), box_width=(2 - label_pad, 0, 0), box_height=(0, label_h, 0), ) ret.add_children(label) return ret
def velocity_circle_distort_2d(cfg): cfg.duration = 4.0 cfg.aspect_ratio = (1, 1) coords = list(equilateral_triangle_coords()) coords.append(coords[0]) pos_kf = [ ngl.AnimKeyFrameVec2(cfg.duration * i / 3.0, pos[0:2], "exp_in_out") for i, pos in enumerate(coords) ] anim = ngl.AnimatedVec2(pos_kf) velocity = ngl.VelocityVec2(anim) vert = textwrap.dedent("""\ void main() { float distort_max = 0.1; float velocity_l = length(velocity); float direction_l = length(ngl_position); vec2 normed_velocity = velocity_l == 0.0 ? vec2(0.0) : -velocity / velocity_l; vec2 normed_direction = direction_l == 0.0 ? vec2(0.0) : ngl_position.xy / 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(translate, 0.0, 0.0) + vec4(-distort * velocity, 0.0, 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, translate=anim) return shape
def _get_live_shared_uniform_function(layout=None): data = [COLORS.red, COLORS.blue] color = ngl.UniformVec3(value=COLORS.black, label="color") def keyframes_callback(t_id): color.set_value(*data[t_id]) @test_cuepoints( points=_SHARED_UNIFORM_CUEPOINTS, nb_keyframes=len(data), keyframes_callback=keyframes_callback, tolerance=1, exercise_serialization=False, debug_positions=False, ) @scene(debug_positions=scene.Bool()) def scene_func(cfg, debug_positions=True): cfg.duration = 0 cfg.aspect_ratio = (1, 1) if layout: return _get_live_shared_uniform_with_block_scene( cfg, color, layout, debug_positions) else: return _get_live_shared_uniform_scene(cfg, color, debug_positions) return scene_func
def _compute_animation(cfg, animate_pre_render=True): cfg.duration = 5 cfg.aspect_ratio = (1, 1) local_size = 2 vertices_data = array.array( "f", [ # fmt: off -0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, 0.0, # fmt: on ], ) nb_vertices = 4 input_vertices = ngl.BufferVec3(data=vertices_data, label="vertices") output_vertices = ngl.BufferVec3(data=vertices_data, label="vertices") input_block = ngl.Block(fields=[input_vertices], layout="std140") output_block = ngl.Block(fields=[output_vertices], layout="std140") rotate_animkf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 360) ] rotate = ngl.Rotate(ngl.Identity(), axis=(0, 0, 1), angle=ngl.AnimatedFloat(rotate_animkf)) transform = ngl.UniformMat4(transform=rotate) program = ngl.ComputeProgram(_ANIMATION_COMPUTE, workgroup_size=(local_size, local_size, 1)) program.update_properties(dst=ngl.ResourceProps(writable=True)) compute = ngl.Compute(workgroup_count=(nb_vertices / (local_size**2), 1, 1), program=program) compute.update_resources(transform=transform, src=input_block, dst=output_block) quad_buffer = ngl.BufferVec3(block=output_block, block_field=0) geometry = ngl.Geometry(quad_buffer, topology="triangle_strip") program = ngl.Program(vertex=cfg.get_vert("color"), fragment=cfg.get_frag("color")) render = ngl.Render(geometry, program) render.update_frag_resources(color=ngl.UniformVec3(value=COLORS.sgreen), opacity=ngl.UniformFloat(1)) children = (compute, render) if animate_pre_render else (render, compute) return ngl.Group(children=children)
def compute_particles(cfg): cfg.duration = 10 workgroups = (2, 1, 4) local_size = (4, 4, 1) nb_particles = workgroups[0] * workgroups[1] * workgroups[2] * local_size[ 0] * local_size[1] * local_size[2] positions = array.array("f") velocities = array.array("f") for i in range(nb_particles): positions.extend([ cfg.rng.uniform(-2.0, 1.0), cfg.rng.uniform(-1.0, 1.0), 0.0, ]) velocities.extend([ cfg.rng.uniform(1.0, 2.0), cfg.rng.uniform(0.5, 1.5), ]) ipositions = ngl.Block( fields=[ ngl.BufferVec3(data=positions, label="positions"), ngl.BufferVec2(data=velocities, label="velocities"), ], layout="std430", ) opositions = ngl.Block( fields=[ngl.BufferVec3(count=nb_particles, label="positions")], layout="std140") animkf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 1.0), ] time = ngl.AnimatedFloat(animkf) duration = ngl.UniformFloat(cfg.duration) program = ngl.ComputeProgram(_PARTICULES_COMPUTE, workgroup_size=local_size) program.update_properties(odata=ngl.ResourceProps(writable=True)) compute = ngl.Compute(workgroups, program) compute.update_resources(time=time, duration=duration, idata=ipositions, odata=opositions) circle = ngl.Circle(radius=0.05) program = ngl.Program(vertex=_PARTICULES_VERT, fragment=cfg.get_frag("color")) render = ngl.Render(circle, program, nb_instances=nb_particles) render.update_frag_resources(color=ngl.UniformVec3(value=COLORS.sgreen), opacity=ngl.UniformFloat(1)) render.update_vert_resources(data=opositions) group = ngl.Group() group.add_children(compute, render) return group
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 _data_vertex_and_fragment_blocks(cfg, layout): """ This test ensures that the block bindings are properly set by pgcraft when UBOs or SSBOs are bound to different stages. """ cfg.aspect_ratio = (1, 1) src = ngl.Block( fields=[ ngl.UniformVec3(value=COLORS.red, label="color"), ngl.UniformFloat(value=0.5, label="opacity"), ], layout="std140", ) dst = ngl.Block( fields=[ ngl.UniformVec3(value=COLORS.white, label="color"), ], layout=layout, ) vert = textwrap.dedent("""\ void main() { ngl_out_pos = ngl_projection_matrix * ngl_modelview_matrix * vec4(ngl_position, 1.0); var_src = vec4(src.color, 1.0) * src.opacity; } """) frag = textwrap.dedent("""\ void main() { vec3 color = var_src.rgb + (1.0 - var_src.a) * dst.color; ngl_out_color = vec4(color, 1.0); } """) program = ngl.Program(vertex=vert, fragment=frag) program.update_vert_out_vars(var_src=ngl.IOVec4(), ) geometry = ngl.Quad(corner=(-1, -1, 0), width=(2, 0, 0), height=(0, 2, 0)) render = ngl.Render(geometry, program) render.update_vert_resources(src=src) render.update_frag_resources(dst=dst) return render
def color_negative_values_srgb(cfg): cfg.duration = 5 kfs = ( # The elastic_in easing has the special property to undershoot under 0 ngl.AnimKeyFrameVec3(-5, value=(0.0, 0.0, 0.0)), ngl.AnimKeyFrameVec3(5, value=(0.0, 0.0, 1.0), easing="elastic_in"), ) color0 = ngl.AnimatedVec3(keyframes=kfs) color1 = ngl.UniformVec3(value=(-1.0, -1.0, 1.0)) return ngl.RenderGradient(color0=color0, color1=color1, linear=True)
def shape_triangles_mat4_attribute(cfg): cfg.aspect_ratio = (1, 1) p0, p1, p2 = equilateral_triangle_coords(1) geometry = ngl.Triangle(p0, p1, p2) matrices = ngl.BufferMat4(data=array.array( "f", [ # fmt: off 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.5, 0.0, 0.0, 1.0, 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.5, 0.0, 0.0, 1.0, # fmt: on ], )) program = ngl.Program( vertex=TRIANGLES_MAT4_ATTRIBUTE_VERT, fragment=cfg.get_frag("color"), ) render = ngl.Render(geometry, program, nb_instances=2) render.update_instance_attributes(matrix=matrices) render.update_frag_resources(color=ngl.UniformVec3(value=COLORS.orange), opacity=ngl.UniformFloat(1)) return render
def get_random_block_info(spec, seed=0, layout=LAYOUTS[0], color_tint=True): # Seed only defines the random for the position of the fields random.seed(seed) fields_pos = random.sample(range(len(spec)), len(spec)) # Always the same colors whatever the user seed random.seed(0) fields_info = [] max_id_len = 0 for i, field_info in enumerate(spec): node = field_info['func'](field_info.get('data')) node.set_label(field_info['name']) field_info['node'] = node field_info['decl'] = _get_field_decl(layout, field_info) field_info['pos'] = fields_pos.index(i) max_id_len = max(len(field_info['decl']), max_id_len) if color_tint: hue = random.uniform(0, 1) field_info['color'] = colorsys.hls_to_rgb(hue, 0.6, 1.0) else: field_info['color'] = (1, 1, 1) fields_info.append(field_info) shuf_fields = [fields_info[pos] for pos in fields_pos] color_fields = [(f['name'], ngl.UniformVec3(f['color'], label=f['name'])) for f in fields_info] block_fields = [(f['name'], f['node']) for f in shuf_fields] if layout == 'uniform': color_fields = dict(color_fields) block_fields = dict(block_fields) else: color_fields = ngl.Block(fields=[f for n, f in color_fields], layout=layout, label='colors_block') block_fields = ngl.Block(fields=[f for n, f in block_fields], layout=layout, label='fields_block') pad = lambda s: (max_id_len - len(s)) * ' ' block_definition = '\n'.join('%s;%s // #%02d' % (f['decl'], pad(f['decl']), i) for i, f in enumerate(shuf_fields)) color_prefix = 'color_' if layout == 'uniform' else '' color_u = 'uniform ' if layout == 'uniform' else '' color_definition = '\n'.join( color_u + 'vec3 %s;' % (color_prefix + f['name']) for f in fields_info) return fields_info, block_fields, color_fields, block_definition, color_definition
def py_bindings_allow_node(): c = ngl.Camera(eye=(0, 1, 0)) assert c.set_eye(ngl.EvalVec3()) == 0 assert c.set_eye(1, 0, 0) == 0 c = ngl.Camera(eye=ngl.NoiseVec3()) assert c.set_eye(1, 0, 0) == 0 assert c.set_eye(ngl.UniformVec3()) == 0 r = ngl.Rotate(angle=30) assert r.set_angle(ngl.NoiseFloat()) == 0 assert r.set_angle(-45) == 0 r = ngl.Rotate(angle=ngl.EvalFloat()) assert r.set_angle(90) == 0 assert r.set_angle(ngl.UniformFloat()) == 0
def urchin(cfg, npoints=25): """Urchin with animated vertices""" cfg.duration = 5 cfg.aspect_ratio = (1, 1) def get_vertices(n, radius_func, offset=0.0): vertices = [] step = 2 * math.pi / n for i in range(n): angle = (i + offset) * step radius = radius_func() x, y = math.sin(angle) * radius, math.cos(angle) * radius vertices.append([x, y, 0]) return vertices k = 16 n, m = 0.1, 0.9 inner_rfunc = lambda: n inner_vertices = get_vertices(npoints, inner_rfunc) vdata = [] for i in range(k): outer_rfunc = lambda: cfg.rng.uniform(n, m) outer_vertices = get_vertices(npoints, outer_rfunc, offset=0.5) vertices_data = array.array("f") for inner_vertex, outer_vertex in zip(inner_vertices, outer_vertices): vertices_data.extend(inner_vertex + outer_vertex) vertices_data.extend(inner_vertices[0]) vdata.append(vertices_data) animkf = [] for i, v in enumerate(vdata + [vdata[0]]): animkf.append(ngl.AnimKeyFrameBuffer(i * cfg.duration / float(k), v)) vertices = ngl.AnimatedBufferVec3(animkf) geom = ngl.Geometry(vertices) geom.set_topology("line_strip") p = ngl.Program(vertex=cfg.get_vert("color"), fragment=cfg.get_frag("color")) render = ngl.Render(geom, p) render.update_frag_resources(color=ngl.UniformVec3(value=(0.9, 0.1, 0.3)), opacity=ngl.UniformFloat(1)) return render
def py_bindings_dict(): foo = ngl.UniformVec3(value=(1, 2, 3), label="foo-node") assert foo.set_value(3, 2, 1) == 0 render = ngl.Render(vert_resources=dict(foo=foo)) assert render.set_label("r") == 0 # Delete the previous entry and add another ret = render.update_vert_resources( foo=None, bar=ngl.UniformFloat(value=4, label="bar-node"), ) assert ret == 0 # Update by using a dict ret = render.update_vert_resources( dict( foo=ngl.UniformVec2(), bar=ngl.EvalFloat(), )) assert ret == 0
def data_noise_wiggle(cfg): cfg.aspect_ratio = (1, 1) cfg.duration = 3 vert = textwrap.dedent("""\ void main() { ngl_out_pos = ngl_projection_matrix * ngl_modelview_matrix * vec4(ngl_position, 1.0); ngl_out_pos += vec4(wiggle, 0.0, 0.0); } """) frag = textwrap.dedent("""\ void main() { ngl_out_color = vec4(color, 1.0); } """) geometry = ngl.Circle(radius=0.25, npoints=6) program = ngl.Program(vertex=vert, fragment=frag) render = ngl.Render(geometry, program) render.update_vert_resources(wiggle=ngl.NoiseVec2(octaves=8)) render.update_frag_resources(color=ngl.UniformVec3(value=COLORS.white)) return render
def shape_morphing(cfg, n=6): cfg.duration = 5.0 vertices_tl = _get_morphing_coordinates(cfg.rng, n, -1, 0) vertices_tr = _get_morphing_coordinates(cfg.rng, n, 0, 0) vertices_bl = _get_morphing_coordinates(cfg.rng, n, -1, -1) vertices_br = _get_morphing_coordinates(cfg.rng, n, 0, -1) vertices_animkf = [] for i, coords in enumerate( zip(vertices_tl, vertices_tr, vertices_bl, vertices_br)): flat_coords = list(itertools.chain(*coords)) coords_array = array.array("f", flat_coords) vertices_animkf.append( ngl.AnimKeyFrameBuffer(i * cfg.duration / (n - 1), coords_array)) vertices = ngl.AnimatedBufferVec3(vertices_animkf) geom = ngl.Geometry(vertices) geom.set_topology("triangle_strip") p = ngl.Program(vertex=cfg.get_vert("color"), fragment=cfg.get_frag("color")) render = ngl.Render(geom, p) render.update_frag_resources(color=ngl.UniformVec3(COLORS.cyan), opacity=ngl.UniformFloat(1)) return render
def particles(cfg, particles=32): """Particules demo using compute shaders and instancing""" compute_shader = cfg.get_comp("particles") vertex_shader = cfg.get_vert("particles") fragment_shader = cfg.get_frag("color") cfg.duration = 6 x = 64 p = x * particles positions = array.array("f") velocities = array.array("f") for i in range(p): positions.extend([ cfg.rng.uniform(-1.0, 1.0), cfg.rng.uniform(0.0, 1.0), 0.0, ]) velocities.extend([ cfg.rng.uniform(-0.01, 0.01), cfg.rng.uniform(-0.05, 0.05), ]) ipositions = ngl.Block( fields=[ngl.BufferVec3(data=positions, label="data")], layout="std430") ivelocities = ngl.Block( fields=[ngl.BufferVec2(data=velocities, label="data")], layout="std430") opositions = ngl.Block(fields=[ngl.BufferVec3(count=p, label="data")], layout="std430") animkf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 1) ] utime = ngl.AnimatedFloat(animkf) uduration = ngl.UniformFloat(cfg.duration) cp = ngl.ComputeProgram(compute_shader, workgroup_size=(1, 1, 1)) cp.update_properties(opositions=ngl.ResourceProps(writable=True)) c = ngl.Compute(workgroup_count=(x, particles, 1), program=cp) c.update_resources( time=utime, duration=uduration, ipositions=ipositions, ivelocities=ivelocities, opositions=opositions, ) quad_width = 0.01 quad = ngl.Quad(corner=(-quad_width / 2, -quad_width / 2, 0), width=(quad_width, 0, 0), height=(0, quad_width, 0)) p = ngl.Program( vertex=vertex_shader, fragment=fragment_shader, ) p.update_vert_out_vars(var_uvcoord=ngl.IOVec2(), var_tex0_coord=ngl.IOVec2()) r = ngl.Render(quad, p, nb_instances=particles, blending="src_over") r.update_frag_resources(color=ngl.UniformVec3(value=(0, 0.6, 0.8)), opacity=ngl.UniformFloat(0.9)) r.update_vert_resources(positions=opositions) g = ngl.Group() g.add_children(c, r) return ngl.Camera(g)
def _shape_geometry(cfg, set_normals=False, set_indices=False): # Fake cube (3 faces only) obtained from: # echo 'cube();'>x.scad; openscad x.scad -o x.stl vertices = array.array( "f", [ x - 0.5 for x in [ # fmt: off 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, # fmt: on ] ], ) normals = array.array( "f", [ # fmt: off 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, # fmt: on ], ) vertices_buffer = ngl.BufferVec3(data=vertices) normals_buffer = ngl.BufferVec3(data=normals) cfg.aspect_ratio = (1, 1) geometry = ngl.Geometry(vertices=vertices_buffer) if set_normals: geometry.set_normals(normals_buffer) prog = ngl.Program(vertex=cfg.get_vert("colored-normals"), fragment=cfg.get_frag("colored-normals")) prog.update_vert_out_vars(var_normal=ngl.IOVec3()) render = ngl.Render(geometry, prog) else: prog = ngl.Program(vertex=cfg.get_vert("color"), fragment=cfg.get_frag("color")) render = ngl.Render(geometry, prog) render.update_frag_resources( color=ngl.UniformVec3(value=COLORS.magenta), opacity=ngl.UniformFloat(1)) if set_indices: indices = array.array("H", list(range(3 * 6))) indices_buffer = ngl.BufferUShort(data=indices) geometry.set_indices(indices_buffer) return ngl.Rotate(render, 45, axis=(1, 1, 1))
def mountain(cfg, ndim=3, nb_layers=7, ref_color=(0.5, 0.75, 0.75), nb_mountains=6): """Mountain generated with a stack of noise shaders using Textures as random source""" random_dim = 1 << ndim cfg.aspect_ratio = (16, 9) cfg.duration = nb_mountains**2 def get_rand(): return array.array("f", [cfg.rng.uniform(0, 1) for x in range(random_dim)]) black, white = (0, 0, 0), (1, 1, 1) quad = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) prog = ngl.Program(vertex=cfg.get_vert("texture"), fragment=cfg.get_frag("mountain")) prog.update_vert_out_vars(var_uvcoord=ngl.IOVec2(), var_tex0_coord=ngl.IOVec2()) hscale = 1 / 2.0 mountains = [] for i in range(nb_mountains): yoffset = (nb_mountains - i - 1) / float(nb_mountains - 1) * (1.0 - hscale) if i < nb_mountains / 2: c0, c1 = ref_color, white x = (i + 1) / float(nb_mountains / 2 + 1) else: c0, c1 = black, ref_color x = (i - nb_mountains / 2) / float((nb_mountains - 1) / 2) mcolor = [x * a + (1.0 - x) * b for a, b in zip(c0, c1)] random_buf = ngl.BufferFloat(data=get_rand()) random_tex = ngl.Texture2D(data_src=random_buf, width=random_dim, height=1) utime_animkf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, i + 1) ] utime = ngl.AnimatedFloat(utime_animkf) uyoffset_animkf = [ ngl.AnimKeyFrameFloat(0, yoffset / 2.0), ngl.AnimKeyFrameFloat(cfg.duration / 2.0, yoffset), ngl.AnimKeyFrameFloat(cfg.duration, yoffset / 2.0), ] uyoffset = ngl.AnimatedFloat(uyoffset_animkf) render = ngl.Render(quad, prog, blending="src_over") render.update_frag_resources(tex0=random_tex) render.update_frag_resources(dim=ngl.UniformInt(random_dim)) render.update_frag_resources(nb_layers=ngl.UniformInt(nb_layers)) render.update_frag_resources(time=utime) render.update_frag_resources(lacunarity=ngl.UniformFloat(2.0)) render.update_frag_resources(gain=ngl.UniformFloat(0.5)) render.update_frag_resources(mcolor=ngl.UniformVec3(mcolor)) render.update_frag_resources(yoffset=uyoffset) render.update_frag_resources(hscale=ngl.UniformFloat(hscale)) mountains.append(render) sky = ngl.RenderColor(white[:3]) group = ngl.Group(children=[sky] + mountains) return group
def get_field_scene(cfg, spec, category, field_type, seed, debug_positions, layout, color_tint): """ Build a scene testing that a given data has been properly uploaded to the GPU memory. - `spec` contains all the fields that should also be declared (either in a block or as uniforms). All the fields are shuffled such that the field we are testing is always in a random position. This makes sure that we get the data alignment right. - `category` and `field_type` are filters in the spec to select the field(s) from which we want to read the data - `seed` is used to control the fields shuffling - `debug_positions` controls whether there are debug circles in the scene in order to make sure we are reading back the data colors at the appropriate position - `layout` controls the block layout or whether we are working with uniforms - `color_tint` is a debug helper to give a different color for each field (because if they have the same data, it is hard to indiscriminate them). """ cfg.aspect_ratio = (1, 1) # Seed only defines the random for the position of the fields fields_pos = random.Random(seed).sample(range(len(spec)), len(spec)) # Always the same colors whatever the user seed clr_rng = random.Random(0) fields_info = [] for i, field_info in enumerate(spec): create_func = field_info.get("func") if create_func is None: create_func = _FUNCS["{category}_{type}".format(**field_info)] node = create_func(field_info.get("data")) node.set_label(field_info["name"]) field_info["node"] = node if color_tint: hue = clr_rng.uniform(0, 1) field_info["color"] = colorsys.hls_to_rgb(hue, 0.6, 1.0) else: field_info["color"] = (1, 1, 1) fields_info.append(field_info) shuf_fields = [fields_info[pos] for pos in fields_pos] color_fields = [(f["name"], ngl.UniformVec3(f["color"], label=f["name"])) for f in fields_info] block_fields = [(f["name"], f["node"]) for f in shuf_fields] if layout == "uniform": color_fields = dict(color_fields) block_fields = dict(block_fields) else: color_fields = ngl.Block(fields=[f for n, f in color_fields], layout=layout, label="colors_block") block_fields = ngl.Block(fields=[f for n, f in block_fields], layout=layout, label="fields_block") fields = match_fields(fields_info, category, field_type) func_calls = [] func_definitions = [] for i, field in enumerate(fields): field_len = field.get("len") func_calls.append("get_color_{}(w, h, 0.0, {:f} * h)".format( field["name"], i)) func_definitions.append( _get_display_glsl_func(layout, field["name"], field["type"], field_len=field_len)) frag_data = dict( func_definitions="\n".join(func_definitions), func_calls=" + ".join(func_calls), ) fragment = _FIELDS_FRAG % frag_data vertex = _FIELDS_VERT program = ngl.Program(vertex=vertex, fragment=fragment) program.update_vert_out_vars(var_uvcoord=ngl.IOVec2()) quad = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) render = ngl.Render(quad, program) if isinstance(color_fields, dict): assert isinstance(block_fields, dict) field_names = {f["name"] for f in fields} d = {} d.update(("color_" + n, u) for (n, u) in color_fields.items() if n in field_names) d.update(("field_" + n, u) for (n, u) in block_fields.items() if n in field_names) render.update_frag_resources(**d) else: render.update_frag_resources(fields=block_fields, colors=color_fields) render.update_frag_resources(nb_fields=ngl.UniformInt(len(fields))) if debug_positions: debug_points = get_data_debug_positions(fields) dbg_circles = get_debug_points(cfg, debug_points, text_size=(0.2, 0.1)) g = ngl.Group(children=(render, dbg_circles)) return g return render
def _get_easing_node(cfg, easing, curve_zoom, color_program, nb_points=128): text_vratio = 1 / 8.0 graph_hpad_ratio = 1 / 16.0 area_size = 2.0 width, height = area_size, area_size text_height = text_vratio * height pad_height = graph_hpad_ratio * height # Colors hue = cfg.rng.uniform(0, 0.6) color = colorsys.hls_to_rgb(hue, 0.6, 1.0) ucolor = ngl.UniformVec3(value=color) line_ucolor = ngl.UniformVec3(value=(1, 1, 1)) # Text legend text = ngl.Text( text=easing, fg_color=color[:3], padding=3, bg_opacity=1, box_corner=(-width / 2.0, height / 2.0 - 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, (0.15, 0.15, 0.15), corner=(-graph_size / 2, -(graph_size + text_height) / 2, 0)) # Normed area of the graph normed_graph_size = graph_size * curve_zoom normed_graph_block = _block( normed_graph_size, normed_graph_size, (0, 0, 0), corner=(-normed_graph_size / 2, -(normed_graph_size + text_height) / 2, 0), ) # 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.0) y = curve_scale_factor * (v * height - height / 2.0) y -= text_height / 2.0 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_frag_resources(color=ucolor, opacity=ngl.UniformFloat(1)) # Value cursor y = 2 / 3.0 * pad_height x = y * math.sqrt(3) cursor_geometry = ngl.Triangle((-x, y, 0), (0, 0, 0), (-x, -y, 0)) cursor = ngl.RenderColor(color[:3], geometry=cursor_geometry, label="%s cursor" % easing) # 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, blending="src_over", label="%s value line" % easing) hline.update_frag_resources(color=line_ucolor, opacity=ngl.UniformFloat(0.4)) # Value animation (cursor + h-line) value_x = -graph_size / 2.0 value_y = (-text_height - normed_graph_size) / 2.0 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, vector=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, blending="src_over", label="%s time line" % easing) vline.update_frag_resources(color=line_ucolor, opacity=ngl.UniformFloat(0.4)) # Time animation (v-line only) time_x = -normed_graph_size / 2.0 time_y = (-text_height - graph_size) / 2.0 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, vector=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
array_vec4=lambda data: ngl.BufferVec4(data=data), single_bool=lambda data: ngl.UniformBool(data), single_float=lambda data: ngl.UniformFloat(data), single_int=lambda data: ngl.UniformInt(data), single_ivec2=lambda data: ngl.UniformIVec2(data), single_ivec3=lambda data: ngl.UniformIVec3(data), single_ivec4=lambda data: ngl.UniformIVec4(data), single_uint=lambda data: ngl.UniformUInt(data), single_uvec2=lambda data: ngl.UniformUIVec2(data), single_uvec3=lambda data: ngl.UniformUIVec3(data), single_uvec4=lambda data: ngl.UniformUIVec4(data), single_mat4=lambda data: ngl.UniformMat4(data), single_quat_mat4=lambda data: ngl.UniformQuat(data, as_mat4=True), single_quat_vec4=lambda data: ngl.UniformQuat(data, as_mat4=False), single_vec2=lambda data: ngl.UniformVec2(data), single_vec3=lambda data: ngl.UniformVec3(data), single_vec4=lambda data: ngl.UniformVec4(data), ) def _get_field_decl(layout, f): t = f['type'] t = t.split('_')[1] if t.startswith('quat') else t return '{}{:<5} {}{}{}'.format('uniform ' if layout == 'uniform' else '', t, 'field_' if layout == 'uniform' else '', f['name'], '[%d]' % f['len'] if 'len' in f else '') def get_random_block_info(spec, seed=0, layout=LAYOUTS[0], color_tint=True):
def blending_and_stencil(cfg): """Scene using blending and stencil graphic features""" cfg.duration = 5 vertex = cfg.get_vert("color") fragment = cfg.get_frag("color") program = ngl.Program(vertex=vertex, fragment=fragment) circle = ngl.Circle(npoints=256) cloud_color = ngl.UniformVec3(value=(1, 1, 1)) cloud_opacity = ngl.UniformFloat(0.4) main_group = ngl.Group() render = ngl.RenderColor(color=(0.2, 0.6, 1), label="sky") config = ngl.GraphicConfig( render, stencil_test=True, stencil_write_mask=0xFF, stencil_func="always", stencil_ref=1, stencil_read_mask=0xFF, stencil_fail="replace", stencil_depth_fail="replace", stencil_depth_pass="******", ) main_group.add_children(config) render = ngl.RenderColor(color=(1, 0.8, 0), geometry=circle, label="sun") scale = ngl.Scale(render, (0.15, 0.15, 0.0)) translate = ngl.Translate(scale, (0.4, 0.3, 0)) main_group.add_children(translate) cloud_group = ngl.Group(label="clouds") centers = [ (-1.0, 0.85, 0.4), (-0.5, 2.0, 1.0), (0, 0.85, 0.4), (1.0, 1.55, 0.8), (0.6, 0.65, 0.075), (0.5, 1.80, 1.25), ] for center in centers: render = ngl.Render(circle, program, blending="src_over") render.update_frag_resources(color=cloud_color, opacity=cloud_opacity) factor = cfg.rng.random() * 0.4 + center[2] keyframe = cfg.duration * (cfg.rng.random() * 0.4 + 0.2) animkf = ( ngl.AnimKeyFrameVec3(0, (factor, factor, 0)), ngl.AnimKeyFrameVec3(keyframe, (factor + 0.1, factor + 0.1, 0)), ngl.AnimKeyFrameVec3(cfg.duration, (factor, factor, 0)), ) scale = ngl.Scale(render, factors=ngl.AnimatedVec3(animkf)) translate = ngl.Translate(scale, vector=(center[0], center[1], 0)) cloud_group.add_children(translate) config = ngl.GraphicConfig( cloud_group, stencil_test=True, stencil_write_mask=0x0, stencil_func="equal", stencil_ref=1, stencil_read_mask=0xFF, stencil_fail="keep", stencil_depth_fail="keep", stencil_depth_pass="******", ) main_group.add_children(config) camera = ngl.Camera(main_group) camera.set_eye(0.0, 0.0, 2.0) camera.set_center(0.0, 0.0, 0.0) camera.set_up(0.0, 1.0, 0.0) camera.set_orthographic(-cfg.aspect_ratio_float, cfg.aspect_ratio_float, -1.0, 1.0) camera.set_clipping(1.0, 10.0) return camera
def _get_cube_side(texture, program, corner, width, height, color): render = ngl.Render(ngl.Quad(corner, width, height), program) render.update_textures(tex0=texture) render.update_uniforms(blend_color=ngl.UniformVec3(value=color)) render.update_uniforms(mix_factor=ngl.UniformFloat(value=0.2)) return render