.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "_gallery/other/post_processing1.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr__gallery_other_post_processing1.py: Full-Screen Post Processing 1 ============================= Example full-screen post processing. The idea is to render a scene to a texture, and then rendering that texture as a full quad to the screen, while adding noise. In many ways this example is similar to the scene_in_a_scene.py example, except we use a custom object here for the noise. Note that we may get a more streamlined way to implement post-processing effects. .. GENERATED FROM PYTHON SOURCE LINES 17-180 .. code-block:: Python import time import numpy as np import imageio.v3 as iio from wgpu.gui.auto import WgpuCanvas, run import pygfx as gfx from pygfx.renderers.wgpu import Binding, register_wgpu_render_function raise RuntimeError("Post-processing needs to be redesigned") # Create a custom object + material class Fullquad(gfx.WorldObject): def __init__(self, texture, material): super().__init__() self.texture = texture self.material = material class NoiseMaterial(gfx.materials.Material): # Note that this inherits fields from the base Material uniform_type = { "time": "f4", "noise": "f4", } def __init__(self, noise=1): super().__init__() self.uniform_buffer = gfx.Buffer( gfx.utils.array_from_shadertype(self.uniform_type) ) self.uniform_buffer.data["time"] = 0 self.uniform_buffer.data["noise"] = noise def tick(self): self.uniform_buffer.data["time"] = time.time() % 1 self.uniform_buffer.update_full() shader_source = """ struct VertexOutput { @location(0) texcoord: vec2, @builtin(position) pos: vec4, }; struct FragmentOutput { @location(0) color: vec4, @location(1) pick: vec4, }; struct Render { opacity: f32, time: f32, noise: f32, }; @group(0) @binding(0) var u_render: Render; @group(1) @binding(0) var r_sampler: sampler; @group(1) @binding(1) var r_tex: texture_2d; @vertex fn vs_main(@builtin(vertex_index) index: u32) -> VertexOutput { var positions = array, 4>(vec2(0.0, 1.0), vec2(0.0, 0.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); let pos = positions[index]; var out: VertexOutput; out.texcoord = vec2(pos.x, 1.0 - pos.y); out.pos = vec4(pos * 2.0 - 1.0, 0.0, 1.0); return out; } @fragment fn fs_main(in: VertexOutput) -> FragmentOutput { let u_render_time = 0.0; let u_render_noise = 1.0; let xy = in.texcoord.xy; let random_nr = fract(sin(dot(xy, vec2(12.9898, 78.233)) + u_render.time) * 43758.5453); let noise = u_render.noise * random_nr; var out: FragmentOutput; out.color = textureSample(r_tex, r_sampler, xy) + vec4(noise, noise, noise, 1.0); return out; } """ # Tell pygfx to use this render function for a Fullquad with NoiseMaterial. @register_wgpu_render_function(Fullquad, NoiseMaterial) def triangle_render_function(wobject, render_info): return [ { "vertex_shader": (shader_source, "vs_main"), "fragment_shader": (shader_source, "fs_main"), "primitive_topology": "triangle-strip", "indices": 4, "bindings0": { 0: Binding( "u_render", "buffer/uniform", wobject.material.uniform_buffer ), }, "bindings1": { 0: Binding( "r_sampler", "sampler/filtering", wobject.texture.get_view() ), 1: Binding("r_tex", "texture/auto", wobject.texture.get_view()), }, }, ] # The application # The canvas for eventual display canvas = WgpuCanvas(size=(640, 480)) # The texture to render the scene into texture = gfx.Texture(dim=2, size=(640, 480, 1), format="rgba8unorm") # The regular scene renderer1 = gfx.renderers.WgpuRenderer(texture) scene = gfx.Scene() im = iio.imread("imageio:astronaut.png").astype(np.float32) / 255 tex = gfx.Texture(im, dim=2).get_view(filter="linear", address_mode="repeat") geometry = gfx.box_geometry(200, 200, 200) material = gfx.MeshBasicMaterial(map=tex) cube = gfx.Mesh(geometry, material) scene.add(cube) camera = gfx.PerspectiveCamera(70, 16 / 9) camera.position.z = 400 # The post processing scene renderer2 = gfx.renderers.WgpuRenderer(canvas) noise_object = Fullquad(texture, NoiseMaterial(0.2)) def animate(): rot = gfx.linalg.Quaternion().set_from_euler(gfx.linalg.Euler(0.005, 0.01)) cube.rotation.multiply(rot) noise_object.material.tick() renderer1.render(scene, camera) renderer2.render(noise_object, gfx.NDCCamera()) canvas.request_draw() if __name__ == "__main__": canvas.request_draw(animate) run() .. _sphx_glr_download__gallery_other_post_processing1.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: post_processing1.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: post_processing1.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: post_processing1.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_