forked from bartvdbraak/blender
ded780f13e
found by Omar Ahmad
107 lines
5.3 KiB
Python
107 lines
5.3 KiB
Python
"""
|
|
Geometry Batches
|
|
++++++++++++++++
|
|
|
|
Geometry is drawn in batches.
|
|
A batch contains the necessary data to perform the drawing.
|
|
That includes an 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 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 the attributes stored per vertex and their types.
|
|
|
|
The following code demonstrates the creation of a vertex buffer that contains 6 vertices.
|
|
For each vertex 2 attributes will be stored: The position and the normal::
|
|
|
|
import gpu
|
|
vertex_positions = [(0, 0, 0), ...]
|
|
vertex_normals = [(0, 0, 1), ...]
|
|
|
|
fmt = gpu.types.GPUVertFormat()
|
|
fmt.attr_add(id="pos", comp_type='F32', len=3, fetch_mode='FLOAT')
|
|
fmt.attr_add(id="normal", comp_type='F32', len=3, fetch_mode='FLOAT')
|
|
|
|
vbo = gpu.types.GPUVertBuf(len=6, format=fmt)
|
|
vbo.attr_fill(id="pos", data=vertex_positions)
|
|
vbo.attr_fill(id="normal", data=vertex_normals)
|
|
|
|
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
|
|
+++++++++++++
|
|
|
|
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::
|
|
|
|
positions = (
|
|
(-1, 1), (1, 1),
|
|
(-1, -1), (1, -1))
|
|
|
|
indices = ((0, 1, 2), (2, 1, 3))
|
|
|
|
ibo = gpu.types.GPUIndexBuf(type='TRIS', seq=indices)
|
|
|
|
Here the first tuple in `indices` describes which vertices should be used for the first triangle (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
|
|
+++++++++++++++++++
|
|
|
|
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 means that once Blender discards this context (i.e. the window is closed), the offscreen instance will be freed.
|
|
|
|
Examples
|
|
++++++++
|
|
|
|
To try these examples, just copy them into Blenders text editor and execute them.
|
|
To keep the examples relatively small, they just register a draw function that can't easily be removed anymore.
|
|
Blender has to be restarted in order to delete the draw handlers.
|
|
""" |