Py API Docs: Restructure gpu module introduction

This commit is contained in:
Jacques Lucke 2018-11-12 12:14:07 +01:00
parent e37a6be9e1
commit 492dbae4d1
Notes: blender-bot 2023-02-14 10:18:56 +01:00
Referenced by issue #57869, No pressure sensitivity with Surface Pen on Surface Laptop
1 changed files with 64 additions and 69 deletions

View File

@ -2,53 +2,23 @@
Geometry Batches
++++++++++++++++
To draw geometry using the gpu module you need to create a :class:`gpu.types.GPUBatch` object.
Batches contain a sequence of points, lines or triangles and associated geometry attributes.
A batch can be drawn multiple times, so they should be cached whenever possible.
This makes them much faster than using the legacy `glBegin` and `glEnd` method, which would recreate the geometry data every time.
Every batch has a so called `Vertex Buffer`.
It contains the attributes for every vertex.
Typical attributes are `position`, `color` and `uv`.
Which attributes the vertex buffer of a batch contains, depends on the shader that will be used to process the batch. The best way to create a new batch is to use the :class:`gpu_extras.batch.batch_for_shader` function.
Furthermore, when creating a new batch, you have to specify the draw type.
The most used types are ``POINTS``, ``LINES`` and ``TRIS``.
Shaders
+++++++
A shader is a small program that tells the GPU how to draw batch geometry.
There are a couple of built-in shaders for the most common tasks.
Built-in shaders can be accessed with :class:`gpu.shader.from_builtin`.
Every built-in shader has an identifier (e.g. `2D_UNIFORM_COLOR` and `3D_FLAT_COLOR`).
Custom shaders can be used as well.
The :class:`gpu.types.GPUShader` takes the shader code as input and compiles it.
Every shader has at least a vertex and a fragment shader.
Optionally a geometry shader can be used as well.
.. note::
A `GPUShader` is actually a `program` in OpenGL terminology.
Shaders define a set of `uniforms` and `attributes`.
**Uniforms** are properties that are constant for every vertex in a batch.
They have to be set before the batch but after the shader has been bound.
**Attributes** are properties that can be different for every vertex.
The attributes and uniforms used by built-in shaders are listed here: :class:`gpu.shader`
A batch can only be processed/drawn by a shader when it provides all the attributes that the shader specifies.
Geometry is drawn in batches.
A batch contains the necessary data to perform the drawing.
That includes a obligatory *Vertex Buffer* and an optional *Index Buffer*, each of which is described in more detail in the following sections.
A batch also defines a draw type.
Typical draw types are `POINTS`, `LINES` and `TRIS`.
The draw type determines how the data will be interpreted and drawn.
Vertex Buffers
++++++++++++++
A vertex buffer is an array that contains the attributes for every vertex.
To create a new vertex buffer (:class:`gpu.types.GPUVertBuf`) you have to provide two things: 1) the amount of vertices in the buffer and 2) the format of the buffer.
A *Vertex Buffer Object* (VBO) (:class:`gpu.types.GPUVertBuf`) is an array that contains the vertex attributes needed for drawing using a specific shader.
Typical vertex attributes are *location*, *normal*, *color*, and *uv*.
Every vertex buffer has a *Vertex Format* (:class:`gpu.types.GPUVertFormat`) and a length corresponding to the number of vertices in the buffer.
A vertex format describes which attributes are stored per vertex and their types.
The format (:class:`gpu.types.GPUVertFormat`) describes which attributes are stored in the buffer.
E.g. to create a vertex buffer that contains 6 vertices, each with a position and a normal could look like so::
The following code demonstrates the creation of a vertex buffer that contains 6 vertices.
For each each vertex 2 attributes will be stored: The position and the normal::
import gpu
vertex_positions = [(0, 0, 0), ...]
@ -62,46 +32,71 @@ E.g. to create a vertex buffer that contains 6 vertices, each with a position an
vbo.attr_fill(id="pos", data=vertex_positions)
vbo.attr_fill(id="normal", data=vertex_normals)
batch = gpu.types.GPUBatch(type='TRIS', buf=vbo)
This batch contains two triangles now.
Vertices 0-2 describe the first and vertices 3-5 the second triangle.
.. note::
The recommended way to create batches is to use the :class:`gpu_extras.batch.batch_for_shader` function. It makes sure that you provide all the vertex attributes that are necessary to be able to use a specific shader.
This vertex buffer could be used to draw 6 points, 3 separate lines, 5 consecutive lines, 2 separate triangles, ...
E.g. in the case of lines, each two consecutive vertices define a line.
The type that will actually be drawn is determined when the batch is created later.
Index Buffers
+++++++++++++
The main reason why index buffers exist is to reduce the amount of memory required to store and send geometry.
E.g. often the same vertex is used by multiple triangles in a mesh.
Instead of vertex attributes multiple times to the gpu, an index buffer can be used.
An index buffer is an array of integers that describes in which order the vertex buffer should be read.
E.g. when you have a vertex buffer ``[a, b, c]`` and an index buffer ``[0, 2, 1, 2, 1, 0]`` it is like if you just had the vertex buffer ``[a, c, b, c, b, a]``.
Using an index buffer saves memory because usually a single integer is smaller than all attributes for one vertex combined.
Often triangles and lines share one or more vertices.
With only a vertex buffer one would have to store all attributes for the these vertices multiple times.
This is very inefficient because in a connected triangle mesh every vertex is used 6 times on average.
A more efficient approach would be to use an *Index Buffer* (IBO) (:class:`gpu.types.GPUIndexBuf`), sometimes referred to as *Element Buffer*.
An *Index Buffer* is an array that references vertices based on their index in the vertex buffer.
For instance, to draw a rectangle composed of two triangles, one could use an index buffer::
Index buffers can be used like so::
positions = (
(-1, 1), (1, 1),
(-1, -1), (1, -1))
indices = [(0, 1), (2, 0), (2, 3), ...]
ibo = gpu.types.GPUIndexBuf(type='LINES', seq=indices)
batch = gpu.types.GPUBatch(type='LINES', buf=vbo, elem=ibo)
indices = ((0, 1, 2), (2, 1, 3))
.. note::
Instead of creating index buffers object manually, you can also just use the optional `indices` parameter of the :class:`gpu_extras.batch.batch_for_shader` function.
ibo = gpu.types.GPUIndexBuf(type='TRIS', seq=indices)
Here the first tuple in `indices` describes which vertices should be used for the first vertex (same for the second tuple).
Note how the diagonal vertices 1 and 2 are shared between both triangles.
Shaders
+++++++
A shader is a program that runs on the GPU (written in GLSL in our case).
There are multiple types of shaders.
The most important ones are *Vertex Shaders* and *Fragment Shaders*.
Typically multiple shaders are linked together into a *Program*.
However, in the Blender Python API the term *Shader* refers to an OpenGL Program.
Every :class:`gpu.types.GPUShader` consists of a vertex shader, a fragment shader and an optional geometry shader.
For common drawing tasks there are some built-in shaders accessible from :class:`gpu.shader.from_builtin` with an identifier such as `2D_UNIFORM_COLOR` or `3D_FLAT_COLOR`.
Every shader defines a set of attributes and uniforms that have to be set in order to use the shader.
Attributes are properties that are set using a vertex buffer and can be different for individual vertices.
Uniforms are properties that are constant per draw call.
They can be set using the `shader.uniform_*` functions after the shader has been bound.
Batch Creation
++++++++++++++
Batches can be creates by first manually creating VBOs and IBOs.
However, it is recommended to use the :class:`gpu_extras.batch.batch_for_shader` function.
It makes sure that all the vertex attributes necessary for a specific shader are provided.
Consequently, the shader has to be passed to the function as well.
When using this function one rarely has to care about the vertex format, VBOs and IBOs created in the background.
This is still something one should know when drawing stuff though.
Since batches can be drawn multiple times, they should be cached and reused whenever possible.
Offscreen Rendering
+++++++++++++++++++
Everytime something is drawn, the result is written into a framebuffer.
Usually this buffer will later be displayed on the screen.
However, sometimes you might want to draw into a separate "texture" and use it further.
E.g. you could use the render result as a texture on another object or save the rendered result on disk.
Offscreen Rendering is done using the :class:`gpu.types.GPUOffScreen` type.
What one can see on the screen after rendering is called the *Front Buffer*.
When draw calls are issued, batches are drawn on a *Back Buffer* that will only be displayed when all drawing is done and the current back buffer will become the new front buffer.
Sometimes, one might want to draw the batches into a distinct buffer that could be used as texture to display on another object or to be saved as image on disk.
This is called Offscreen Rendering.
In Blender Offscreen Rendering is done using the :class:`gpu.types.GPUOffScreen` type.
.. warning::
``GPUOffScreen`` objects are bound to the opengl context they have been created in.
This also means that once Blender discards this context (i.e. a window is closed) the offscreen instance will also be freed.
`GPUOffScreen` objects are bound to the OpenGL context they have been created in.
This means that once Blender discards this context (i.e. the window is closed), the offscreen instance will be freed.
Examples
++++++++