Py API Docs: Restructure gpu module introduction
This commit is contained in:
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
|
@ -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
|
||||
++++++++
|
||||
|
|
Loading…
Reference in New Issue