Note
Go to the end to download the full example code.
Triangle GLSL
The triangle example, using GLSL shaders.
import wgpu
from rendercanvas.auto import RenderCanvas, loop
vertex_shader = """
#version 450 core
layout(location = 0) out vec4 color;
void main()
{
vec2 positions[3] = vec2[3](
vec2(0.0, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.75)
);
vec3 colors[3] = vec3[3]( // srgb colors
vec3(1.0, 1.0, 0.0),
vec3(1.0, 0.0, 1.0),
vec3(0.0, 1.0, 1.0)
);
int index = int(gl_VertexID);
gl_Position = vec4(positions[index], 0.0, 1.0);
color = vec4(colors[index], 1.0);
}
"""
fragment_shader = """
#version 450 core
out vec4 FragColor;
layout(location = 0) in vec4 color;
void main()
{
vec3 physical_color = pow(color.rgb, vec3(2.2)); // gamma correct
FragColor = vec4(physical_color, color.a);
}
"""
# adapter is required to create the device object, which is the general entry point to create most wgpu objects.
# for convenience and interoperability `wgpu.utils.get_default_device()` and associated configuration are provided.
adapter = wgpu.gpu.request_adapter_sync()
device = adapter.request_device_sync()
# setting up a canvas, so we can see what we draw
canvas = RenderCanvas(size=(640, 480), title="wgpu triangle example")
context = canvas.get_wgpu_context()
render_texture_format = context.get_preferred_format(device.adapter)
context.configure(device=device, format=render_texture_format)
# creating the shader module compiles the shader code for your GPU.
vert_shader = device.create_shader_module(label="triangle_vert", code=vertex_shader)
frag_shader = device.create_shader_module(label="triangle_frag", code=fragment_shader)
# in wgpu-py, methods that take descriptors will take the keyword arguments instead.
# descriptors and other structs can still be accessed via wgpu.structs or top level wgpu.
render_pipeline = device.create_render_pipeline(
**wgpu.RenderPipelineDescriptor(
layout=wgpu.AutoLayoutMode.auto,
vertex=wgpu.VertexState(module=vert_shader),
depth_stencil=None,
multisample=None,
fragment=wgpu.FragmentState(
module=frag_shader,
targets=[wgpu.ColorTargetState(format=render_texture_format)],
),
)
)
# this function gets called for every frame. It ends with submitting a buffer of work onto the GPU queue.
def drawing_function():
command_encoder = device.create_command_encoder()
current_texture_view = context.get_current_texture().create_view()
render_pass = command_encoder.begin_render_pass(
color_attachments=[
wgpu.RenderPassColorAttachment(
view=current_texture_view,
clear_value=(0, 0.2, 0, 1), # a green background
load_op=wgpu.LoadOp.clear,
store_op=wgpu.StoreOp.store,
)
],
)
render_pass.set_pipeline(render_pipeline)
render_pass.draw(3)
render_pass.end()
device.queue.submit([command_encoder.finish()])
if __name__ == "__main__":
canvas.request_draw(drawing_function)
loop.run()
Gallery generated by Sphinx-Gallery
Interactive example
This uses Pyodide. If this does not work, your browser may not have sufficient support for wasm/pyodide/wgpu (check your browser dev console). Stdout (print statements) will also appear in the browser console.