Skip to main content
`Ctrl`+`K`

Note

Go to the end to download the full example code.

# Animate an Image

Use a timer to trigger updating an image.

This example demonstrates a 3D Texture. The volume contains noise that is smoothed in the z-direction. Shown is one slice through that volume to give the effect of “morphing” noise.

    import numpy as np

    from vispy.util.transforms import ortho
    from vispy import gloo
    from vispy import app
    from vispy.visuals.shaders import ModularProgram

    # Shape of image to be displayed
    D, H, W = 30, 60, 90

    # Modulated image
    img_array = np.random.uniform(0, 0.1, (D, H, W, 3)).astype(np.float32)
    # Depth slices are dark->light
    img_array[...] += np.linspace(0, 0.9, D)[:, np.newaxis, np.newaxis, np.newaxis]
    # Make vertical direction more green moving upward
    img_array[..., 1] *= np.linspace(0, 1, H)[np.newaxis, :, np.newaxis]
    # Make horizontal direction more red moving rightward
    img_array[..., 0] *= np.linspace(0, 1, W)[np.newaxis, np.newaxis, :]

    # A simple texture quad
    data = np.zeros(4, dtype=[('a_position', np.float32, 2),
                              ('a_texcoord', np.float32, 2)])
    data['a_position'] = np.array([[0, 0], [W, 0], [0, H], [W, H]])
    data['a_texcoord'] = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])

    VERT_SHADER = """
    // Uniforms
    uniform mat4 u_model;
    uniform mat4 u_view;
    uniform mat4 u_projection;

    // Attributes
    attribute vec2 a_position;
    attribute vec2 a_texcoord;

    // Varyings
    varying vec2 v_texcoord;

    // Main
    void main (void)
    {
        v_texcoord = a_texcoord;
        gl_Position = u_projection * u_view * u_model * vec4(a_position,0.0,1.0);
    }
    """

    FRAG_SHADER = """
    uniform $sampler_type u_texture;
    uniform float i;
    varying vec2 v_texcoord;
    void main()
    {
        // step through gradient with i, note that slice (depth) comes last here!
        gl_FragColor = $sample(u_texture, vec3(v_texcoord, i));
        gl_FragColor.a = 1.0;
    }

    """

    class Canvas(app.Canvas):

        def __init__(self, emulate3d=True):
            app.Canvas.__init__(self, keys='interactive', size=((W*5), (H*5)))

            if emulate3d:
                tex_cls = gloo.TextureEmulated3D
            else:
                tex_cls = gloo.Texture3D
            self.texture = tex_cls(img_array, interpolation='nearest',
                                   wrapping='clamp_to_edge')

            self.program = ModularProgram(VERT_SHADER, FRAG_SHADER)
            self.program.frag['sampler_type'] = self.texture.glsl_sampler_type
            self.program.frag['sample'] = self.texture.glsl_sample
            self.program['u_texture'] = self.texture
            self.program['i'] = 0.0
            self.program.bind(gloo.VertexBuffer(data))

            self.view = np.eye(4, dtype=np.float32)
            self.model = np.eye(4, dtype=np.float32)
            self.projection = np.eye(4, dtype=np.float32)

            self.program['u_model'] = self.model
            self.program['u_view'] = self.view
            self.projection = ortho(0, W, 0, H, -1, 1)
            self.program['u_projection'] = self.projection

            self.i = 0

            gloo.set_clear_color('white')

            self._timer = app.Timer('auto', connect=self.on_timer, start=True)

            self.show()

        def on_resize(self, event):
            width, height = event.physical_size
            gloo.set_viewport(0, 0, width, height)
            self.projection = ortho(0, width, 0, height, -100, 100)
            self.program['u_projection'] = self.projection

            # Compute the new size of the quad
            r = width / float(height)
            R = W / float(H)
            if r < R:
                w, h = width, width / R
                x, y = 0, int((height - h) / 2)
            else:
                w, h = height * R, height
                x, y = int((width - w) / 2), 0
            data['a_position'] = np.array(
                [[x, y], [x + w, y], [x, y + h], [x + w, y + h]])
            self.program.bind(gloo.VertexBuffer(data))

        def on_timer(self, event):
            # cycle every 2 sec
            self.i = (self.i + 1./120.) % 1.0
            self.update()

        def on_draw(self, event):
            gloo.clear(color=True, depth=True)
            self.program['i'] = 1.9 * np.abs(0.5 - self.i)
            self.program.draw('triangle_strip')

    if __name__ == '__main__':
        # Use emulated3d to switch from an emulated 3D texture to an actual one
        canvas = Canvas(emulate3d=True)
        app.run()

Total running time of the script: (0 minutes 0.596 seconds)

Gallery generated by Sphinx-Gallery