Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# Uniform

At some point you will need to make a lot of small changes to your rendering. Changing the screen aspect ratio, viewing angle, changing perspective/orthographic projection and much more. And in many situations it will be very convenient to use `Uniform` -s.

`Uniform` -s can be specified and used at any time during rendering. They allow you to replace all constants in the shader with variables and change them as needed. The `Uniform` is initialized in the shader as follows:

    uniform float var1;

Changing the `Uniform` -s value in ModernGL is very easy. For example, setting the value for our variable `140.02` is done as follows:

    vao.program['var1'].value = 140.02

    # or (using `__setitem__` shortcut)
    vao.program['var1'] = 140.02

If the variable type is not `float`, but `vec4`, simply list the values separated by commas:

    vao.program['var2'] = 1, 2, 3, 4
    # or
    vao.program['var2'] = [1, 2, 3, 4]
    # or
    vao.program['var2'] = (1, 2, 3, 4)

You need to list as many values as the value type takes: `float` will take 1 number, `vec2` will take 2 numbers, `vec4` will take 4 numbers, `mat4` will take 16 numbers, etc.

Let’s consider a case where we need to change the size of our triangle. Take the original triangle drawing code and make the following changes.

To change the scale (size) of the triangle, add a `scale` `Uniform`. In the vertex shader it will be multiplied by all vertices and thus allow us to control the size of all triangles.

Entire source

     1import moderngl
     2import numpy as np
     3
     4from PIL import Image
     5
     6ctx = moderngl.create_context(standalone=True)
     7
     8prog = ctx.program(
     9    vertex_shader="""
    10        #version 330
    11
    12        in vec2 in_vert;
    13        in vec3 in_color;
    14
    15        uniform float scale;
    16
    17        out vec3 v_color;
    18
    19        void main() {
    20            v_color = in_color;
    21            gl_Position = vec4(in_vert * scale, 0.0, 1.0);
    22        }
    23    """,
    24    fragment_shader="""
    25        #version 330
    26
    27        in vec3 v_color;
    28
    29        out vec3 f_color;
    30
    31        void main() {
    32            f_color = v_color;
    33        }
    34    """,
    35)
    36
    37vertices = np.asarray([
    38
    39    -0.75, -0.75,  1, 0, 0,
    40    0.75, -0.75,  0, 1, 0,
    41    0.0, 0.649,  0, 0, 1
    42
    43], dtype='f4')
    44
    45vbo = ctx.buffer(vertices.tobytes())
    46vao = ctx.vertex_array(prog, vbo, "in_vert", "in_color")
    47
    48fbo = ctx.framebuffer(
    49    color_attachments=[ctx.texture((512, 512), 3)]
    50)
    51fbo.use()
    52fbo.clear(0.0, 0.0, 0.0, 1.0)
    53
    54vao.program['scale'] = 2
    55
    56vao.render()  # "mode" is moderngl.TRIANGLES by default
    57
    58Image.frombytes(
    59    "RGB", fbo.size, fbo.color_attachments[0].read(),
    60    "raw", "RGB", 0, -1
    61).show()

We set the scale value to `2.0`, which means our triangle will be enlarged by 2 times.

Enlarged triangle

Now let’s set the scale value to `0.5` to reduce the triangle by 2 times:

    vao.program['scale'] = 0.5

Reduced triangle

Uniforms can not only be set, but also read. This is done as follows:

    scale = vao.program['scale'].value

Also Uniforms can be written or read directly, in the form of bytes:

    # write
    scale = 2
    b_scale = numpy.asarray([scale], dtype='f4').tobytes()
    vao.program['scale'].write(b_scale)

    # read
    b_scale = vao.program['scale'].read()
    scale = numpy.frombuffer(b_scale, dtype='f4')[0]

    # `numpy.frombuffer()` converts a byte string into an array,
    # since we have one number, we select it from the array.

In most cases, directly using `Uniform` -s `.read()/.write()` methods can speed up the code, but constantly manually converting variables into bytes does not make sense, since ModernGL already does it in the most optimized way.