animated_quat_mat4=lambda data: ngl.AnimatedQuat( keyframes=_get_anim_kf(ngl.AnimKeyFrameQuat, data), as_mat4=True), animated_quat_vec4=lambda data: ngl.AnimatedQuat( keyframes=_get_anim_kf(ngl.AnimKeyFrameQuat, data), as_mat4=False), array_float=lambda data: ngl.BufferFloat(data=data), array_int=lambda data: ngl.BufferInt(data=data), array_ivec2=lambda data: ngl.BufferIVec2(data=data), array_ivec3=lambda data: ngl.BufferIVec3(data=data), array_ivec4=lambda data: ngl.BufferIVec4(data=data), array_mat4=lambda data: ngl.BufferMat4(data=data), array_vec2=lambda data: ngl.BufferVec2(data=data), array_vec3=lambda data: ngl.BufferVec3(data=data), 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_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) 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) 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) 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: color_fields = ngl.Block(fields=[f for _, f in color_fields], layout=layout, label="colors_block") block_fields = ngl.Block(fields=[f for _, f in block_fields], layout=layout, label="fields_block") 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 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 _ 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 = tuple(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 mountain(cfg, ndim=3, nb_layers=7, ref_color=(0.5, .75, .75, 1.0), nb_mountains=6): '''Mountain generated with a stack of noise shaders using Textures as random source''' random.seed(0) random_dim = 1 << ndim cfg.aspect_ratio = (16, 9) cfg.duration = nb_mountains ** 2 def get_rand(): return array.array('f', [random.uniform(0, 1) for x in range(random_dim)]) black, white = (0, 0, 0, 1), (1, 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. 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.), ngl.AnimKeyFrameFloat(cfg.duration/2.0, yoffset), ngl.AnimKeyFrameFloat(cfg.duration, yoffset/2.)] uyoffset = ngl.AnimatedFloat(uyoffset_animkf) render = ngl.Render(quad, prog) 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.UniformVec4(mcolor)) render.update_frag_resources(yoffset=uyoffset) render.update_frag_resources(hscale=ngl.UniformFloat(hscale)) mountains.append(render) prog = ngl.Program(vertex=cfg.get_vert('color'), fragment=cfg.get_frag('color')) sky = ngl.Render(quad, prog) sky.update_frag_resources(color=ngl.UniformVec4(white)) group = ngl.Group(children=[sky] + mountains) blend = ngl.GraphicConfig(group, blend=True, blend_src_factor='src_alpha', blend_dst_factor='one_minus_src_alpha', blend_src_factor_a='zero', blend_dst_factor_a='one') return blend