Cleanup: gpu docs

This commit is contained in:
Campbell Barton 2018-11-20 07:32:49 +11:00
parent 5f21030a81
commit 3c8c976086
12 changed files with 130 additions and 86 deletions

View File

@ -4,7 +4,8 @@ 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.
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.
@ -12,25 +13,29 @@ 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.
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.
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::
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), ...]
.. code-block:: python
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')
import gpu
vertex_positions = [(0, 0, 0), ...]
vertex_normals = [(0, 0, 1), ...]
vbo = gpu.types.GPUVertBuf(len=6, format=fmt)
vbo.attr_fill(id="pos", data=vertex_positions)
vbo.attr_fill(id="normal", data=vertex_normals)
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.
@ -42,19 +47,24 @@ 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*.
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))
For instance, to draw a rectangle composed of two triangles, one could use an index buffer.
indices = ((0, 1, 2), (2, 1, 3))
.. code-block:: python
ibo = gpu.types.GPUIndexBuf(type='TRIS', seq=indices)
positions = (
(-1, 1), (1, 1),
(-1, -1), (1, -1))
Here the first tuple in `indices` describes which vertices should be used for the first triangle (same for the second tuple).
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
@ -66,7 +76,8 @@ 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`.
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.
@ -89,14 +100,18 @@ 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.
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.
`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
++++++++
@ -104,4 +119,4 @@ 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.
"""
"""

View File

@ -3,7 +3,8 @@ Rendering the 3D View into a Texture
------------------------------------
The scene has to have a camera for this example to work.
You could also make this independent of a specific camera, but Blender does not expose good functions to create view and projection matrices yet.
You could also make this independent of a specific camera,
but Blender does not expose good functions to create view and projection matrices yet.
"""
import bpy
import bgl
@ -15,6 +16,7 @@ HEIGHT = 256
offscreen = gpu.types.GPUOffScreen(WIDTH, HEIGHT)
def draw():
context = bpy.context
scene = context.scene
@ -35,4 +37,5 @@ def draw():
bgl.glDisable(bgl.GL_DEPTH_TEST)
draw_texture_2d(offscreen.color_texture, (10, 10), WIDTH, HEIGHT)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')

View File

@ -3,8 +3,9 @@ Custom Shader for dotted 3D Line
--------------------------------
In this example the arc length (distance to the first point on the line) is calculated in every vertex.
Between the vertex and fragment shader that value is automatically interpolated for all points that will be visible on the screen.
In the fragment shader the `sin` of the arc length is calculated.
Between the vertex and fragment shader that value is automatically interpolated
for all points that will be visible on the screen.
In the fragment shader the ``sin`` of the arc length is calculated.
Based on the result a decision is made on whether the fragment should be drawn or not.
"""
import bpy
@ -47,9 +48,11 @@ for a, b in zip(coords[:-1], coords[1:]):
arc_lengths.append(arc_lengths[-1] + (a - b).length)
shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
batch = batch_for_shader(shader, 'LINE_STRIP',
{"position" : coords,
"arcLength" : arc_lengths})
batch = batch_for_shader(
shader, 'LINE_STRIP',
{"position": coords, "arcLength": arc_lengths},
)
def draw():
shader.bind()
@ -58,4 +61,5 @@ def draw():
shader.uniform_float("u_Scale", 10)
batch.draw(shader)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

View File

@ -8,12 +8,13 @@ from gpu_extras.batch import batch_for_shader
coords = [(1, 1, 1), (-2, 0, 0), (-2, -1, 3), (0, 1, 1)]
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'LINES', {"pos" : coords})
batch = batch_for_shader(shader, 'LINES', {"pos": coords})
def draw():
shader.bind()
shader.uniform_float("color", (1, 1, 0, 1))
batch.draw(shader)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

View File

@ -32,7 +32,8 @@ fragment_shader = '''
coords = [(1, 1, 1), (2, 0, 0), (-2, -1, 3)]
shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
batch = batch_for_shader(shader, 'TRIS', {"position" : coords})
batch = batch_for_shader(shader, 'TRIS', {"position": coords})
def draw():
shader.bind()
@ -41,4 +42,5 @@ def draw():
shader.uniform_float("brightness", 0.5)
batch.draw(shader)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

View File

@ -7,10 +7,10 @@ import gpu
from gpu_extras.batch import batch_for_shader
coords = (
(-1, -1, -1), ( 1, -1, -1),
(-1, 1, -1), ( 1, 1, -1),
(-1, -1, 1), ( 1, -1, 1),
(-1, 1, 1), ( 1, 1, 1))
(-1, -1, -1), (+1, -1, -1),
(-1, +1, -1), (+1, +1, -1),
(-1, -1, +1), (+1, -1, +1),
(-1, +1, +1), (+1, +1, +1))
indices = (
(0, 1), (0, 2), (1, 3), (2, 3),
@ -18,11 +18,13 @@ indices = (
(0, 4), (1, 5), (2, 6), (3, 7))
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'LINES', {"pos" : coords}, indices=indices)
batch = batch_for_shader(shader, 'LINES', {"pos": coords}, indices=indices)
def draw():
shader.bind()
shader.uniform_float("color", (1, 0, 0, 1))
batch.draw(shader)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

View File

@ -14,20 +14,23 @@ mesh.calc_loop_triangles()
vertices = np.empty((len(mesh.vertices), 3), 'f')
indices = np.empty((len(mesh.loop_triangles), 3), 'i')
mesh.vertices.foreach_get("co",
np.reshape(vertices, len(mesh.vertices) * 3))
mesh.loop_triangles.foreach_get("vertices",
np.reshape(indices, len(mesh.loop_triangles) * 3))
mesh.vertices.foreach_get(
"co", np.reshape(vertices, len(mesh.vertices) * 3))
mesh.loop_triangles.foreach_get(
"vertices", np.reshape(indices, len(mesh.loop_triangles) * 3))
vertex_colors = [(random(), random(), random(), 1) for _ in range(len(mesh.vertices))]
shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR')
batch = batch_for_shader(shader, 'TRIS',
{"pos" : vertices,
"color" : vertex_colors},
indices=indices)
batch = batch_for_shader(
shader, 'TRIS',
{"pos": vertices, "color": vertex_colors},
indices=indices,
)
def draw():
batch.draw(shader)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

View File

@ -14,11 +14,13 @@ indices = (
(0, 1, 2), (2, 1, 3))
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'TRIS', {"pos" : vertices}, indices=indices)
batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=indices)
def draw():
shader.bind()
shader.uniform_float("color", (0, 0.5, 0.5, 1.0))
batch.draw(shader)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')

View File

@ -13,13 +13,18 @@ IMAGE_NAME = "Untitled"
image = bpy.data.images[IMAGE_NAME]
shader = gpu.shader.from_builtin('2D_IMAGE')
batch = batch_for_shader(shader, 'TRI_FAN',
{"pos" : ((100, 100), (200, 100), (200, 200), (100, 200)),
"texCoord" : ((0, 0), (1, 0), (1, 1), (0, 1))})
batch = batch_for_shader(
shader, 'TRI_FAN',
{
"pos": ((100, 100), (200, 100), (200, 200), (100, 200)),
"texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)),
},
)
if image.gl_load():
raise Exception()
def draw():
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)
@ -28,4 +33,5 @@ def draw():
shader.uniform_int("image", 0)
batch.draw(shader)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')

View File

@ -2,10 +2,10 @@
Generate a texture using Offscreen Rendering
--------------------------------------------
1. Create an :class:`gpu.types.GPUOffScreen` object.
2. Draw some circles into it.
3. Make a new shader for drawing a planar texture in 3D.
4. Draw the generated texture using the new shader.
#. Create an :class:`gpu.types.GPUOffScreen` object.
#. Draw some circles into it.
#. Make a new shader for drawing a planar texture in 3D.
#. Draw the generated texture using the new shader.
"""
import bpy
import gpu
@ -63,9 +63,13 @@ fragment_shader = '''
'''
shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
batch = batch_for_shader(shader, 'TRI_FAN',
{"position" : ((-1, -1), (1, -1), (1, 1), (-1, 1)),
"uv" : ((0, 0), (1, 0), (1, 1), (0, 1))})
batch = batch_for_shader(
shader, 'TRI_FAN',
{
"position": ((-1, -1), (1, -1), (1, 1), (-1, 1)),
"uv": ((0, 0), (1, 0), (1, 1), (0, 1)),
},
)
def draw():
@ -78,4 +82,5 @@ def draw():
shader.uniform_float("image", 0)
batch.draw(shader)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

View File

@ -6,7 +6,8 @@ This will create a new image with the given name.
If it already exists, it will override the existing one.
Currently almost all of the execution time is spent in the last line.
In the future this will hopefully be solved by implementing the Python buffer protocol for `bgl.Buffer` and `Image.pixels` (aka `bpy_prop_array`).
In the future this will hopefully be solved by implementing the Python buffer protocol
for :class:`bgl.Buffer` and :class:`bpy.types.Image.pixels` (aka ``bpy_prop_array``).
"""
import bpy
import gpu
@ -35,7 +36,6 @@ with offscreen.bind():
(random.uniform(-1, 1), random.uniform(-1, 1)),
(1, 1, 1, 1), random.uniform(0.1, 1), 20)
buffer = bgl.Buffer(bgl.GL_BYTE, WIDTH * HEIGHT * 4)
bgl.glReadBuffer(bgl.GL_BACK)
bgl.glReadPixels(0, 0, WIDTH, HEIGHT, bgl.GL_RGBA, bgl.GL_UNSIGNED_BYTE, buffer)
@ -47,4 +47,4 @@ if not IMAGE_NAME in bpy.data.images:
bpy.data.images.new(IMAGE_NAME, WIDTH, HEIGHT)
image = bpy.data.images[IMAGE_NAME]
image.scale(WIDTH, HEIGHT)
image.pixels = [v / 255 for v in buffer]
image.pixels = [v / 255 for v in buffer]

View File

@ -4,32 +4,33 @@ Built-in shaders
All built-in shaders have the ``mat4 ModelViewProjectionMatrix`` uniform.
The value of it can only be modified using the :class:`gpu.matrix` module.
"""
2D_UNIFORM_COLOR:
attributes: vec3 pos
uniforms: vec4 color
attributes: vec3 pos
uniforms: vec4 color
2D_FLAT_COLOR:
attributes: vec3 pos, vec4 color
uniforms: -
attributes: vec3 pos, vec4 color
uniforms: -
2D_SMOOTH_COLOR:
attributes: vec3 pos, vec4 color
uniforms: -
attributes: vec3 pos, vec4 color
uniforms: -
2D_IMAGE:
attributes: vec3 pos, vec2 texCoord
uniforms: sampler2D image
attributes: vec3 pos, vec2 texCoord
uniforms: sampler2D image
3D_UNIFORM_COLOR:
attributes: vec3 pos
uniforms: vec4 color
attributes: vec3 pos
uniforms: vec4 color
3D_FLAT_COLOR:
attributes: vec3 pos, vec4 color
uniforms: -
attributes: vec3 pos, vec4 color
uniforms: -
3D_SMOOTH_COLOR:
attributes: vec3 pos, vec4 color
uniforms: -
attributes: vec3 pos, vec4 color
uniforms: -
"""