From 492dbae4d1a05785741b5370fab618b38b8fdfa0 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 12 Nov 2018 12:14:07 +0100 Subject: Py API Docs: Restructure gpu module introduction --- doc/python_api/examples/gpu.1.py | 133 +++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 69 deletions(-) diff --git a/doc/python_api/examples/gpu.1.py b/doc/python_api/examples/gpu.1.py index 1ffa0a58856..cd83d31386d 100644 --- a/doc/python_api/examples/gpu.1.py +++ b/doc/python_api/examples/gpu.1.py @@ -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:: + + 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 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`. -Index buffers can be used like so:: +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. - 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) +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. -.. 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. +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 ++++++++ -- cgit v1.2.3