def histogram(cfg): """Histogram using compute shaders""" m0 = cfg.medias[0] cfg.duration = m0.duration cfg.aspect_ratio = (m0.width, m0.height) g = ngl.Group() m = ngl.Media(cfg.medias[0].filename) t = ngl.Texture2D(data_src=m) h = ngl.Block(label="histogram_block", layout="std430") h.add_fields( ngl.BufferUInt(256, label="r"), ngl.BufferUInt(256, label="g"), ngl.BufferUInt(256, label="b"), ngl.UniformUInt(label="maximum"), ) r = ngl.RenderTexture(t) proxy_size = 128 proxy = ngl.Texture2D(width=proxy_size, height=proxy_size) rtt = ngl.RenderToTexture(r) rtt.add_color_textures(proxy) g.add_children(rtt) compute_program = ngl.ComputeProgram(cfg.get_comp("histogram-clear"), workgroup_size=(1, 1, 1)) compute_program.update_properties(hist=ngl.ResourceProps(writable=True)) compute = ngl.Compute(workgroup_count=(256, 1, 1), program=compute_program, label="histogram-clear") compute.update_resources(hist=h) g.add_children(compute) local_size = 8 group_size = proxy_size / local_size compute_program = ngl.ComputeProgram(cfg.get_comp("histogram-exec"), workgroup_size=(local_size, local_size, 1)) compute = ngl.Compute(workgroup_count=(group_size, group_size, 1), program=compute_program, label="histogram-exec") compute.update_resources(hist=h, source=proxy) compute_program.update_properties(hist=ngl.ResourceProps(writable=True)) compute_program.update_properties(source=ngl.ResourceProps(as_image=True)) g.add_children(compute) q = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) p = ngl.Program(vertex=cfg.get_vert("histogram-display"), fragment=cfg.get_frag("histogram-display")) p.update_vert_out_vars(var_uvcoord=ngl.IOVec2(), var_tex0_coord=ngl.IOVec2()) render = ngl.Render(q, p) render.update_frag_resources(tex0=t, hist=h) g.add_children(render) return g
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 compute_image_load_store(cfg, show_dbg_points=False): size = _N texture_data = ngl.BufferFloat( data=array.array("f", [x / (size**2) for x in range(size**2)])) texture_r = ngl.Texture2D(format="r32_sfloat", width=size, height=size, data_src=texture_data) texture_g = ngl.Texture2D(format="r32_sfloat", width=size, height=size, data_src=texture_data) texture_b = ngl.Texture2D(format="r32_sfloat", width=size, height=size, data_src=texture_data) scale = ngl.Block( fields=[ngl.UniformVec2(value=(-1.0, 1.0), label="factors")], layout="std140", ) texture_rgba = ngl.Texture2D(width=size, height=size) program = ngl.ComputeProgram(_IMAGE_LOAD_STORE_COMPUTE, workgroup_size=(size, size, 1)) program.update_properties( texture_r=ngl.ResourceProps(as_image=True), texture_g=ngl.ResourceProps(as_image=True), texture_b=ngl.ResourceProps(as_image=True), texture_rgba=ngl.ResourceProps(as_image=True, writable=True), ) compute = ngl.Compute(workgroup_count=(1, 1, 1), program=program) compute.update_resources(texture_r=texture_r, texture_g=texture_g, texture_b=texture_b, scale=scale, texture_rgba=texture_rgba) render = ngl.RenderTexture(texture_rgba) group = ngl.Group(children=(compute, render)) if show_dbg_points: cuepoints = _get_compute_histogram_cuepoints() group.add_children(get_debug_points(cfg, cuepoints)) return group
def compute_animation(cfg): cfg.duration = 5 cfg.aspect_ratio = (1, 1) local_size = 2 vertices_data = array.array('f', [ -0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, 0.0, ]) 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), anim=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.UniformVec4(value=COLORS['sgreen'])) return ngl.Group(children=(compute, render))
def _get_random_compute(cfg, rng, t0, t1): count = 10 fragment_shader = cfg.get_frag("texture") vertex_shader = textwrap.dedent( """ void main() { vec4 position = vec4(ngl_position, 1.0) + vec4(pos.data[ngl_instance_index], 0.0, 0.0); ngl_out_pos = ngl_projection_matrix * ngl_modelview_matrix * position; var_tex0_coord = (tex0_coord_matrix * vec4(ngl_uvcoord, 0.0, 1.0)).xy; } """ ) funcs = ("snake", "circle", "spread") compute_shader = textwrap.dedent( """ #define TAU (2.0 * 3.14159265358979323846) vec2 snake(float i) { return vec2(i * 2.0 - 1.0, sin((time + i) * TAU)); } vec2 circle(float i) { float angle = (time + i) * TAU; return vec2(sin(angle), cos(angle)); } vec2 spread(float i) { float angle = i * TAU; return vec2(sin(angle), cos(angle)) * (time + i); } void main() { uint wg = gl_WorkGroupID.x; float i = float(wg) / float(gl_NumWorkGroups.x - 1U); pos.data[wg] = FUNC(i); } """.replace( "FUNC", rng.choice(funcs) ) ) pos = ngl.Block(fields=[ngl.BufferVec2(count=count, label="data")]) time_animkf = [ngl.AnimKeyFrameFloat(t0, 0), ngl.AnimKeyFrameFloat(t1, 1)] compute_prog = ngl.ComputeProgram(compute_shader, workgroup_size=(1, 1, 1)) compute_prog.update_properties(pos=ngl.ResourceProps(writable=True)) compute = ngl.Compute(workgroup_count=(count, 1, 1), program=compute_prog) compute.update_resources(time=ngl.AnimatedFloat(time_animkf), pos=pos) geometry = _get_random_geometry(rng) program = ngl.Program(vertex=vertex_shader, fragment=cfg.get_frag("texture")) program.update_vert_out_vars(var_tex0_coord=ngl.IOVec2()) render = ngl.Render(geometry, program, nb_instances=count, blending="src_over") render.update_frag_resources(tex0=_get_random_texture(cfg, rng)) render.update_vert_resources(pos=pos) render = ngl.Scale(render, factors=(0.5, 0.5, 0)) return ngl.Group(children=(compute, render))
def compute_histogram(cfg, show_dbg_points=False): cfg.duration = 10 cfg.aspect_ratio = (1, 1) hsize, size, local_size = _N * _N, _N, _N // 2 data = array.array("f") for i in range(size * size): data.extend(( cfg.rng.uniform(0.0, 0.5), cfg.rng.uniform(0.25, 0.75), cfg.rng.uniform(0.5, 1.0), 1.0, )) texture_buffer = ngl.BufferVec4(data=data) texture = ngl.Texture2D(width=size, height=size, data_src=texture_buffer) texture.set_format("r32g32b32a32_sfloat") histogram_block = ngl.Block(layout="std140", label="histogram") histogram_block.add_fields( ngl.BufferUInt(hsize, label="r"), ngl.BufferUInt(hsize, label="g"), ngl.BufferUInt(hsize, label="b"), ngl.UniformUIVec3(label="max"), ) shader_params = dict(hsize=hsize, size=size, local_size=local_size) group_size = hsize // local_size clear_histogram_shader = _COMPUTE_HISTOGRAM_CLEAR % shader_params clear_histogram_program = ngl.ComputeProgram(clear_histogram_shader, workgroup_size=(local_size, 1, 1)) clear_histogram_program.update_properties(hist=ngl.ResourceProps( writable=True)) clear_histogram = ngl.Compute( workgroup_count=(group_size, 1, 1), program=clear_histogram_program, label="clear_histogram", ) clear_histogram.update_resources(hist=histogram_block) group_size = size // local_size exec_histogram_shader = _COMPUTE_HISTOGRAM_EXEC % shader_params exec_histogram_program = ngl.ComputeProgram(exec_histogram_shader, workgroup_size=(local_size, local_size, 1)) exec_histogram_program.update_properties(hist=ngl.ResourceProps( writable=True)) exec_histogram = ngl.Compute(workgroup_count=(group_size, group_size, 1), program=exec_histogram_program, label="compute_histogram") exec_histogram.update_resources(hist=histogram_block, source=texture) exec_histogram_program.update_properties(source=ngl.ResourceProps( as_image=True)) quad = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) program = ngl.Program( vertex=_RENDER_HISTOGRAM_VERT, fragment=_RENDER_HISTOGRAM_FRAG % shader_params, ) program.update_vert_out_vars(var_uvcoord=ngl.IOVec2()) render = ngl.Render(quad, program, label="render_histogram") render.update_frag_resources(hist=histogram_block) group = ngl.Group(children=(clear_histogram, exec_histogram, render)) if show_dbg_points: cuepoints = _get_compute_histogram_cuepoints() group.add_children(get_debug_points(cfg, cuepoints)) return group
def histogram(cfg): '''Histogram using compute shaders''' m0 = cfg.medias[0] cfg.duration = m0.duration cfg.aspect_ratio = (m0.width, m0.height) g = ngl.Group() m = ngl.Media(cfg.medias[0].filename) t = ngl.Texture2D(data_src=m) h = ngl.Block(label='histogram_block', layout='std430') h.add_fields( ngl.BufferUInt(256, label='r'), ngl.BufferUInt(256, label='g'), ngl.BufferUInt(256, label='b'), ngl.UniformUInt(label='maximum'), ) q = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) p = ngl.Program(vertex=cfg.get_vert('texture'), fragment=cfg.get_frag('texture')) p.update_vert_out_vars(var_uvcoord=ngl.IOVec2(), var_tex0_coord=ngl.IOVec2()) r = ngl.Render(q, p) r.update_frag_resources(tex0=t) proxy_size = 128 proxy = ngl.Texture2D(width=proxy_size, height=proxy_size) rtt = ngl.RenderToTexture(r) rtt.add_color_textures(proxy) g.add_children(rtt) compute_program = ngl.ComputeProgram(cfg.get_comp('histogram-clear')) compute = ngl.Compute(256, 1, 1, compute_program, label='histogram-clear') compute.update_resources(hist=h) g.add_children(compute) local_size = 8 group_size = proxy_size / local_size compute_shader = cfg.get_comp('histogram-exec') % { 'local_size': local_size } compute_program = ngl.ComputeProgram(compute_shader) compute = ngl.Compute(group_size, group_size, 1, compute_program, label='histogram-exec') compute.update_resources(hist=h, source=proxy) compute_program.update_properties(source=ngl.ResourceProps(as_image=True)) g.add_children(compute) q = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) p = ngl.Program(vertex=cfg.get_vert('histogram-display'), fragment=cfg.get_frag('histogram-display')) p.update_vert_out_vars(var_uvcoord=ngl.IOVec2(), var_tex0_coord=ngl.IOVec2()) render = ngl.Render(q, p) render.update_frag_resources(tex0=t, hist=h) g.add_children(render) return g
def particles(cfg, particles=32): '''Particules demo using compute shaders and instancing''' random.seed(0) 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([ random.uniform(-1.0, 1.0), random.uniform(0.0, 1.0), 0.0, ]) velocities.extend([ random.uniform(-0.01, 0.01), random.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) r.update_frag_resources(color=ngl.UniformVec4(value=(0, .6, .8, .9))) r.update_vert_resources(positions=opositions) r = ngl.GraphicConfig(r, blend=True, blend_src_factor='src_alpha', blend_dst_factor='one_minus_src_alpha', blend_src_factor_a='zero', blend_dst_factor_a='one') g = ngl.Group() g.add_children(c, r) return ngl.Camera(g)
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)