# pi3d Package¶

## Buffer Module¶

class pi3d.Buffer.Buffer(shape, pts, texcoords, faces, normals=None, smooth=True)[source]

Holds the vertex, normals, incices and tex_coords for each part of a Shape that needs to be rendered with a different material or texture Shape holds an array of Buffer objects.

Generate a vertex buffer to hold data and indices. If no normals are provided then these are generated.

Arguments:
shape
Shape object that this Buffer is a child of
pts
array of vertices tuples i.e. [(x0,y0,z0), (x1,y1,z1),…]
texcoords
array of texture (uv) coordinates tuples i.e. [(u0,v0), (u1,v1),…]
faces
array of indices (of pts array) defining triangles i.e. [(a0,b0,c0), (a1,b1,c1),…]
Keyword arguments:
normals
array of vector component tuples defining normals at each vertex i.e. [(x0,y0,z0), (x1,y1,z1),…]
smooth
if calculating normals then average normals for all faces meeting at this vertex, otherwise just use first (for speed).
unib = None

pass to shader array of vec3 uniform variables:

vec3 description python
index   from to
0 ntile, shiny, blend 0 2
1 material 3 5
2 umult, vmult, point_size 6 8
3 u_off, v_off, line_width/bump 9 10
4 specular RGB value *_reflect 11 14

NB line width and bump factor clash but shouldn’t be an issue

calc_normals()[source]
re_init(pts=None, texcoords=None, normals=None, offset=0)[source]

Only reset the opengl buffer variables: vertices, tex_coords, normals (which will not be generated if not supplied) NB this method will go horribly wrong if you change the size of the arrays supplied in the argument as the opengles buffers are reused At least one of pts, texcoords or normals must be a list This method will run faster if the new data is passed as numpy 2D arrays.

Arguments:
pts
numpy 2D array or list of (x,y,z) tuples, default None
texcoords
numpy 2D array or list of (u,v) tuples, default None
normals
numpy 2D array or list of (x,y,z) tuples, default None
offset
number of vertices offset from the start of vertices, default 0
set_draw_details(shader, textures, ntiles=0.0, shiny=0.0, umult=1.0, vmult=1.0, bump_factor=1.0)[source]

Can be used to set information needed for drawing as a one off rather than sending as arguments to draw().

Arguments:
textures
array of Texture objects
Keyword arguments:
ntiles
multiple for tiling normal map which can be less than or greater than 1.0. 0.0 disables the normal mapping, float
shiny
how strong to make the reflection 0.0 to 1.0, float
umult
multiplier for tiling the texture in the u direction
vmult
multiplier for tiling the texture in the v direction
bump_factor
multiplier for the normal map surface distortion effect
set_material(mtrl)[source]
set_textures(textures)[source]
set_offset(offset=(0.0, 0.0))[source]
draw(shape=None, M=None, unif=None, shader=None, textures=None, ntl=None, shny=None, fullset=True)[source]

Draw this Buffer, called by the parent Shape.draw()

Keyword arguments:
shape
Shape object this Buffer belongs to, has to be passed at draw to avoid circular reference
textures
array of Texture objects
ntl
multiple for tiling normal map which can be less than or greater than 1.0. 0.0 disables the normal mapping, float
shiny
how strong to make the reflection 0.0 to 1.0, float

## Camera Module¶

class pi3d.Camera.Camera(at=(0, 0, 0), eye=(0, 0, -0.1), lens=None, is_3d=True, scale=1.0, absolute=True)[source]

Bases: pi3d.util.DefaultInstance.DefaultInstance

required object for creating and drawing Shape objects. Default instance created if none specified in script prior to creating a Shape

Set up view matrix to look from eye to at including perspective

Arguments:
at
tuple (x,y,z) location to look at
eye
tuple (x,y,z) location to look from
lens
tuple (near plane dist, far plane dist, VERTICAL field of view in degrees, display aspect ratio w/h)
is_3d
determines whether the camera uses a perspective or orthographic projection matrix
scale
number of pixels per unit of size for orthographic camera or divisor for fov if perspective
absolute
when True (default) then all rotations are relative to the absolute frame of reference. When False then rotations are relative to the rotated position
reset(lens=None, is_3d=True, scale=1.0)[source]

Has to be called each loop if the camera position or rotation changes

point_at(target=[0.0, 0.0, 10000.0])[source]

point the camera at a point also return the tilt and rotation values

Keyword argument:
target
Location as [x,y,z] array to point at, defaults to a high +ve z value as a kind of compass!
get_direction()[source]

returns the direction that the Camera is pointing as a numpy unit vector [x,y,z] this can be used directly for positioning the view position without resorting to trig functions. Also see relocate()

relocate(rot=None, tilt=None, point=array([ 0., 0., 0.]), distance=array([ 0., 0., 0.]), normal=None, slope_factor=0.5, crab=False)[source]

A convenience function for frequently used Camera animation steps. The camera is reset and the rotation and tilt are applied. If a normal is not supplied the camera is positioned using the distance and point vectors. If there is a normal then the camera is moved to the point and the new position relative to this is returned. This behaviour allows the y coordinate to be subsequently adjusted (in the calling program) using ElevationMap.calcHeight()

The normal vector is also used in conjunction with the slope_factor to determine an adjustment to the distance moved each frame.

rot
absolute y rotation of the Camera
tilt
x rotation
point
3D vector to move relative to (or to if normal is None)
distance
3D vector from point to Camera
normal
3D vector normal to surface at point
slope_factor
effect of normal vector on movement
crab
if True then distance is horizontally at right angles to direction that the Camera is pointing
position(pt)[source]

position camera

Arguments:
pt
tuple (x, y, z) floats
rotateZ(angle)[source]

Rotate camera z axis

Arguments:
angle
in degrees
rotateY(angle)[source]

Rotate camera y axis

Arguments:
angle
in degrees
rotateX(angle)[source]

Rotate camera x axis

Arguments:
angle
in degrees
rotate(rx, ry, rz)[source]

Rotate camera

Arguments:
rx
x rotation in degrees
ry
y rotation in degrees
rz
z rotation in degrees
offset(pt)[source]

position camera

Arguments:
pt
tuple (x, y, z) floats
make_mtrx()[source]
euler_angles(matrix=None)[source]

Or more correctly Tait-Bryan angles. Argument

matrix
can supply a rotation matrix to use (as generated by the following method.) Defaults to using the Camera.r_mtrx

in pi3d arrangement (C type and Z into screen):

cz.cx-sz.sx.sy  cy.sz+cz.sx.sy  -cx.sy
-cx.sz          cz.cx            sx
cz.sy+cy.sz.sx  sz.sy-cz.cy.sx   cx.cy

matrix_from_two_vectors(start_vector, vector)[source]

uses two 3D vectors (arrays) to generate a rotation vector representing the movement from one direction to another. NB because there are many ways of doing this the z rotation may not match so this this method might be best combined with the euler_angles system above. See the pi3d_demos/ForestStereo.py example - key press ‘k’

matrix_from_two_vecors(start_vector, vector)

uses two 3D vectors (arrays) to generate a rotation vector representing the movement from one direction to another. NB because there are many ways of doing this the z rotation may not match so this this method might be best combined with the euler_angles system above. See the pi3d_demos/ForestStereo.py example - key press ‘k’

## Display Module¶

class pi3d.Display.Display(tkwin=None, use_pygame=False)[source]

Bases: object

This is the central control object of the pi3d system and an instance must be created before some of the other class methods are called.

Constructs a raw Display. Use pi3d.Display.create to create an initialized Display.

tkwin
An optional Tk window.
use_pygame
Flag to opt for pygame
INSTANCE = None

The current unique instance of Display.

loop_running()[source]

loop_running is the main event loop for the Display.

Most pi3d code will look something like this:

DISPLAY = Display.create()

# Initialize objects and variables here.
# ...

while DISPLAY.loop_running():
# Update the frame, using DISPLAY.time for the current time.
# ...

# Check for quit, then call DISPLAY.stop.
if some_quit_condition():
DISPLAY.stop()


Display.loop_running() must be called on the main Python thread, or else white screens and program crashes are likely.

The Display loop can run in two different modes - free or framed.

If DISPLAY.frames_per_second is empty or 0 then the loop runs free - when it finishes one frame, it immediately starts working on the next frame.

If Display.frames_per_second is a positive number then the Display is framed - when the Display finishes one frame before the next frame_time, it waits till the next frame starts.

A free Display gives the highest frame rate, but it will also consume more CPU, to the detriment of other threads or other programs. There is also the significant drawback that the framerate will fluctuate as the numbers of CPU cycles consumed per loop, resulting in jerky motion and animations.

A framed Display has a consistent if smaller number of frames, and also allows for potentially much smoother motion and animation. The ability to throttle down the number of frames to conserve CPU cycles is essential for programs with other important threads like audio.

Display.frames_per_second can be set at construction in Display.create or changed on-the-fly during the execution of the program. If Display.frames_per_second is set too high, the Display doesn’t attempt to “catch up” but simply runs freely.

resize(x=0, y=0, w=0, h=0)[source]

Reshape the window with the given coordinates.

change_layer(layer=0)[source]
add_sprites(*sprites)[source]

Add one or more sprites to this Display.

remove_sprites(*sprites)[source]

Remove one or more sprites from this Display.

stop()[source]

Stop the Display.

destroy()[source]

Destroy the current Display and reset Display.INSTANCE.

clear()[source]

Clear the Display.

set_background(r, g, b, alpha)[source]

Set the Display background. NB the actual drawing of the background happens during the rendering of the framebuffer by the shader so if no draw() is done by anything during each Display loop the screen will remain black If you want to see just the background you will have to draw() something out of view (i.e. behind) the Camera.

r, g, b
Color values for the display
alpha
Opacity of the color. An alpha of 0 means a transparent background, an alpha of 1 means full opaque.
mouse_position()[source]

The current mouse position as a tuple.

swap_buffers()[source]
pi3d.Display.create(x=None, y=None, w=None, h=None, near=None, far=None, fov=45.0, depth=24, background=None, tk=False, window_title='', window_parent=None, mouse=False, frames_per_second=None, samples=0, use_pygame=False, layer=0, display_config=0)[source]

Creates a pi3d Display.

x
Left x coordinate of the display. If None, defaults to the x coordinate of the tkwindow parent, if any.
y
Top y coordinate of the display. If None, defaults to the y coordinate of the tkwindow parent, if any.
w
Width of the display. If None, full the width of the screen.
h
Height of the display. If None, full the height of the screen.
near
This will be used for the default instance of Camera near plane
far
This will be used for the default instance of Camera far plane
fov
Used to define the Camera lens field of view
depth
The bit depth of the display - must be 8, 16 or 24.
background
r,g,b,alpha (opacity)
tk
Do we use the tk windowing system?
window_title
A window title for tk windows only.
window_parent
An optional tk parent window.
mouse
Automatically create a Mouse.
frames_per_second
Maximum frames per second to render (None means “free running”).
samples
EGL_SAMPLES default 0, set to 4 for improved anti-aliasing
use_pygame
To use pygame for display surface, mouse and keyboard - as per windows This almost certainly would conflict if attempting to use in combination with tk=True. Default False
layer
display layer height - used by dispmanx on Raspberry Pi only. -128 will move the pi3d window behind the X11 desktop
display_config
Configuration of display - See pi3d.constants for DISPLAY_CONFIG options

## Keyboard Module¶

pi3d.Keyboard.USE_CURSES = True

Non-blocking keyboard which requires curses and only works on the current terminal window or session.

class pi3d.Keyboard.CursesKeyboard[source]

Bases: object

read()[source]
read_code()[source]
close()[source]
class pi3d.Keyboard.SysKeyboard[source]

Bases: object

read()[source]
read_code()[source]
close()[source]
class pi3d.Keyboard.x11Keyboard[source]

Bases: object

KEYBOARD = [[0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [27, 'Escape'], [49, '1'], [50, '2'], [51, '3'], [52, '4'], [53, '5'], [54, '6'], [55, '7'], [56, '8'], [57, '9'], [48, '0'], [45, '-'], [61, '='], [8, 'BackSpace'], [9, 'Tab'], [113, 'q'], [119, 'w'], [101, 'e'], [114, 'r'], [116, 't'], [121, 'y'], [117, 'u'], [105, 'i'], [111, 'o'], [112, 'p'], [91, '['], [93, ']'], [13, 'Return'], [0, 'Control_L'], [97, 'a'], [115, 's'], [100, 'd'], [102, 'f'], [103, 'g'], [104, 'h'], [106, 'j'], [107, 'k'], [108, 'l'], [59, ';'], [39, "'"], [96, ''], [0, 'Shift_L'], [35, '#'], [122, 'z'], [120, 'x'], [99, 'c'], [118, 'v'], [98, 'b'], [110, 'n'], [109, 'm'], [44, ','], [46, '.'], [47, '/'], [0, 'Shift_R'], [0, ''], [0, 'Alt_L'], [32, 'space'], [0, 'Caps'], [145, 'F1'], [146, 'F2'], [147, 'F3'], [148, 'F4'], [149, 'F5'], [150, 'F6'], [151, 'F7'], [152, 'F8'], [153, 'F9'], [154, 'F10'], [0, 'Num_Lock'], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [92, '\\'], [155, 'F11'], [156, 'F12'], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [13, 'KP_Enter'], [0, 'Control_R'], [0, ''], [0, ''], [0, 'Alt_R'], [0, ''], [129, 'Home'], [134, 'Up'], [130, 'Page_Up'], [136, 'Left'], [137, 'Right'], [132, 'End'], [135, 'Down'], [133, 'Page_Down'], [128, 'Insert'], [131, 'DEL']]
read()[source]
read_code()[source]
close()[source]
class pi3d.Keyboard.AndroidKeyboard[source]

Bases: object

read()[source]
read_code()[source]
close()[source]
class pi3d.Keyboard.PygameKeyboard[source]

Bases: object

In this case KEYBOARD maps pygame codes to the X11 codes used above

KEYBOARD = {8: [0, 'BackSpace'], 13: [0, 'Return'], 60: [92, '\\'], 127: [131, 'DEL'], 271: [13, 'KP_Enter'], 273: [134, 'Up'], 274: [135, 'Down'], 275: [137, 'Right'], 276: [136, 'Left'], 277: [128, 'Insert'], 278: [129, 'Home'], 279: [132, 'End'], 280: [130, 'Page_Up'], 281: [133, 'Page_Down'], 282: [145, 'F1'], 283: [146, 'F2'], 284: [147, 'F3'], 285: [148, 'F4'], 286: [149, 'F5'], 287: [150, 'F6'], 288: [151, 'F7'], 289: [152, 'F8'], 290: [153, 'F9'], 291: [154, 'F10'], 292: [155, 'F11'], 293: [156, 'F12'], 301: [0, 'Caps'], 303: [0, 'Shift_R'], 304: [0, 'Shift_L'], 305: [0, 'Control_R'], 306: [0, 'Control_L'], 307: [0, 'Alt_R'], 308: [0, 'Alt_L']}
read()[source]
read_code()[source]
close()[source]
pi3d.Keyboard.Keyboard(use_curses=True)[source]

Wrapper for the various keyboards appropriate to the PLATFORM

argument:

use_curses
default True, use CursesKeyboard on raspberry pi rather than SysKeyboard
pi3d.Keyboard.KeyboardContext(use_curses=True)[source]

Using a context manager alows curses to restore the terminal to its initial tidy state even if the program is quitted using Ctrl+c. Typical usage:

with KeyboardContext() as keys:
while DISPLAY.loop_running():
sprite.draw()
break


## Light Module¶

class pi3d.Light.Light(lightpos=(10, -10, -5), lightcol=(1.0, 1.0, 1.0), lightamb=(0.1, 0.1, 0.2), is_point=False)[source]

Bases: pi3d.util.DefaultInstance.DefaultInstance

set light values. These are set in Shape.unif as part of the Shape constructor. They can be changed using Shape.set_light() The pixel shade is calculated as:

(lightcol * texture) * dot(lightpos, -normal) + (lightamb * texture)


where * means component multiplying if between two vectors and dot() is the dot product of two vectors.

Arguments:
lightpos
tuple (x,y,z) vector direction from the light i.e. an object at position (0,0,0) would appear to be lit from a light at (-3,4,-5) (left, above and nearer) if lightpos=(3,-4,5). ALTERNATIVELY if is_point is set to True then this is the actual position of the light
lightcol
tuple (r,g,b) defines shade and brightness 0.0 to 1.0 but see below for point lights
lightamb
tuple (r,g,b) ambient lighting values
is_point
the light behaves as a point and brightness falls off with distance. This means that the r,g,b values of lightcol usually have to be set higher than 1.0, objects close to the light will ‘white out’
position(lightpos)[source]
color(lightcol)[source]
ambient(lightamb)[source]
make_point()[source]
make_directional()[source]

## Mouse Module¶

pi3d.Mouse.Mouse(*args, **kwds)[source]

## Shader Module¶

class pi3d.Shader.Shader(shfile=None, vshader_source=None, fshader_source=None)[source]

Bases: pi3d.util.DefaultInstance.DefaultInstance

This compiles and holds the shaders to be used to render the Shape Buffers using their draw() methods. Generally you will choose and load the Shader explicitly as part of the program, however some i.e. defocus are loaded automatically when you create an instance of the Defocus class. Shaders can be ‘re-used’ to draw different objects and the same object can be drawn using different Shaders.

The shaders included with the pi3d module fall into two categories:

• Textured - generally defined using the uv prefix, where an image needs to be loaded via the Texture class which is then mapped to the surface of the object. The 2d_flat shader is a special case of a textured shader which maps pixels in an image to pixels on the screen with an optional scaling and offset.
• Material - generally defined using the mat prefix, where a material shade (rgb) has to be set for the object to be rendered

Within these categories the shaders have been subdivided with a postfix to give full names like uv_flat, mat_bump etc:

• flat - no lighting is used, the shade rendered is the rgb value of the texture or material
• light - Light direction, shade and ambient shade are used give a 3D effect to the surface
• bump - a normal map texture needs to be loaded as well and this will be used to give much finer 3D effect to the surface than can be defined by the resolution of the vertices. The effect of the normal map drops with distance to give a detailed foreground without tiling artifacts in the distance. The shader is passed a variable to use for tiling the normal map which may be different from the tiling of the general texture. If set to 0.0 then no normal mapping will occur.
• reflect - in addition to a normal map an image needs to be supplied to act as a reflection. The shader is passed a value from 0.0 to 1.0 to determine the strength of the reflection.

The reason for using a host of different shaders rather than one that can do everything is that ‘if’ statements within the shader language are very time consuming.

Arguments:
shfile
Pathname without vs or fs ending i.e. “shaders/uv_light”
String with the code for the vertex shader.
String with the code for the fragment shader.
use()[source]

showshaderlog(shader, src)[source]

Prints the compile log for a shader

showprogramlog(shader)[source]

Prints the compile log for a program

## Shape Module¶

class pi3d.Shape.Shape(camera, light, name, x, y, z, rx, ry, rz, sx, sy, sz, cx, cy, cz)[source]

inherited by all shape objects, including simple 2D sprite types

Arguments:
light
Light instance: if None then Light.instance() will be used.
name
Name string for identification.
x, y, z
Location of the origin of the shape, stored in a uniform array.
rx, ry, rz
Rotation of shape in degrees about each axis.
sx, sy, sz
Scale in each direction.
cx, cy, cz
Offset vertices from origin in each direction.
unif = None

pass to shader array of vec3 uniform variables:

vec3 description python
index   from to
0 location 0 2
1 rotation 3 5
2 scale 6 8
3 offset 9 11
5 fog distance, fog alpha, shape alpha 15 17
6 camera position 18 20
7 point light if 1: light0, light1, unused 21 23
8 light0 position, direction vector 24 26
9 light0 strength per shade 27 29
10 light0 ambient values 30 32
11 light1 position, direction vector 33 35
12 light1 strength per shade 36 38
13 light1 ambient values 39 41
14 defocus dist_from, dist_to, amount 42 43 # also 2D x, y
15 defocus frame width, height (only 2 used) 45 46 # also 2D w, h, tot_ht
16 custom data space 48 50
17 custom data space 51 53
18 custom data space 54 56
19 custom data space 57 59

Note: the fractional part of fog distance (i.e. 0.95 in 200.95) is interpretted as the start of fogging (i.e. start 190.90.. full by 200.95) If fog distance is a whole number then a value of 0.333 will be used (200 -> start 66.6.. full by 200.0)

buf = None

self.buf contains a buffer for each part of this shape that needs rendering with a different Shader/Texture. self.draw() relies on objects inheriting from this filling buf with at least one element.

draw(shader=None, txtrs=None, ntl=None, shny=None, camera=None, next_m=None, light_camera=None)[source]

If called without parameters, there has to have been a previous call to set_draw_details() for each Buffer in buf[]. NB there is no facility for setting umult and vmult with draw: they must be set using set_draw_details or Buffer.set_draw_details.

set_shader(shader)[source]

Wrapper method to set just the Shader for all the Buffer objects of this Shape. Used, for instance, in a Model where the Textures have been defined in the obj & mtl files, so you can’t use set_draw_details.

Arguments:

set_normal_shine(normtex, ntiles=1.0, shinetex=None, shiny=0.0, is_uv=True, bump_factor=1.0)[source]

Used to set some of the draw details for all Buffers in Shape. This is useful where a Model object has been loaded from an obj file and the textures assigned automatically.

Arguments:
normtex
Normal map Texture to use.
Keyword arguments:
ntiles
Multiplier for the tiling of the normal map.
shinetex
Reflection Texture to use.
shiny
Strength of reflection (ranging from 0.0 to 1.0).
is_uv
If True then the normtex will be textures[1] and shinetex will be textures[2] i.e. if using a ‘uv’ type Shader. However, for ‘mat’ type Shaders they are moved down one, as the basic shade is defined by material rgb rather than from a Texture.
bump_factor
multiplier for the normal map surface distortion effect
set_draw_details(shader, textures, ntiles=0.0, shiny=0.0, umult=1.0, vmult=1.0, bump_factor=1.0)[source]

Wrapper to call set_draw_details() for each Buffer object.

Arguments:
textures
array of Texture objects
Keyword arguments:
ntiles
multiple for tiling normal map which can be less than or greater than 1.0. 0.0 disables the normal mapping, float
shiny
how strong to make the reflection 0.0 to 1.0, float
umult,vmult
multipliers for tiling the texture in the u,v directions
bump_factor
multiplier for the normal map surface distortion effect
set_material(material)[source]

Wrapper for setting material shade in each Buffer object.

Arguments:
material
tuple (rgb)
set_textures(textures)[source]

Wrapper for setting textures in each Buffer object.

Arguments:
textures
list of Texture objects
set_specular(rgb)[source]
Arguments:
rgb
tuple of red, green, blue values for Phong specular effect
set_offset(offset)[source]

Wrapper for setting uv texture offset in each Buffer object.

Arguments:
offset
tuple (u_off, v_off) values between 0.0 and 1.0 to offset the texture sampler by
offset()[source]

Get offset as (u, v) tuple of (first) buf uv. Doesnt check that buf array exists and has at least one value and only returns offset for that value

set_fog(fogshade, fogdist)[source]

Set fog for this Shape only, it uses the shader smoothblend function over a variable proportion of fogdist (defaulting to 33.33% -> 100%).

Arguments:
tuple (rgba)
fogdist
distance from Camera at which Shape is 100% fogshade. The start of the fog depends on the decimal part of this value. i.e. 100.5 would start at 50, 100.9 would start at 90. If the decimal is 0 then the default start distance is 1/3 of fogdist i.e. 100 would start at 33
set_alpha(alpha=1.0)[source]

Set alpha for this Shape only

Arguments:
alpha
alpha value between 0.0 and 1.0 (default)
alpha()[source]

Get value of alpha

set_light(light, num=0)[source]

Set the values of the lights.

Arguments:
light
Light object to use
num
number of the light to set
set_2d_size(w=None, h=None, x=0, y=0)[source]

saves size to be drawn and location in pixels for use by 2d shader

Keyword arguments:

w
Width, pixels.
h
Height, pixels.
x
Left edge of image from left edge of display, pixels.
y
Top of image from top of display, pixels
set_2d_location(x, y)[source]

saves location in pixels for use by 2d shader

Arguments:

x
Left edge of image from left edge of display, pixels.
y
Top of image from top of display, pixels
set_custom_data(index_from, data)[source]

save general purpose custom data for use by any shader NB it is up to the user to provide data in the form of a suitable array of values that will fit into the space available in the unif array

Arguments:

index_from
start index in unif array for filling data should be 48 to 59 42 to 47 could be used if they do not conflict with existing shaders i.e. 2d_flat, defocus etc
data
2D array of values to put in [[a,b,c],[d,e,f]]
set_point_size(point_size=1.0)[source]

This will set the draw_method in all Buffers of this Shape. point_size less than or equal 0.0 will switch back to GL_TRIANGLES

set_line_width(line_width=1.0, strip=True, closed=False)[source]

This will set the draw_method in all Buffers of this Shape

line-width
line width default 1. If set to <= 0.0 this will switch back to GL_TRIANGLES
strip
If True (default) then the line is drawn continuously from one point to the next i.e. each line after the first one is defined by a single addtional point. If false then each line is defined by pairs of points.
closed
if set to True then the last leg will be filled in. ie polygon. This only has any effect if strip is True

NB it differs from point size in that glLineWidth() is called here and that line width will be used for all subsequent draw() operations so if you want to draw shapes with different thickness lines you will have to call this method repeatedly just before each draw()

Also, there doens’t seem to be an equivalent of gl_PointSize as used in the shader language to make lines shrink with distance.

If you are drawing lines with high contrast they will look better anti aliased which is done by Display.create(samples=4)

re_init(pts=None, texcoords=None, normals=None, offset=0)[source]

wrapper for Buffer.re_init()

add_child(child)[source]

puts a Shape into the Shape.children list

x()[source]

get value of x

y()[source]

get value of y

z()[source]

get value of z

get_bounds()[source]

Find the limits of vertices in three dimensions. Returns a tuple (left, bottom, front, right, top, back)

scale(sx, sy, sz)[source]

Arguments:

sx
x scale
sy
y scale
sz
z scale
position(x, y, z)[source]

Arguments:

x
x position
y
y position
z
z position

self.tr1[3, 0] = x - self.unif[9] self.tr1[3, 1] = y - self.unif[10] self.tr1[3, 2] = z - self.unif[11] self.unif[0] = x self.unif[1] = y self.unif[2] = z self.MFlg = True

positionX(v)[source]

Arguments:

v
x position
positionY(v)[source]

Arguments:

v
y position
positionZ(v)[source]

Arguments:

v
z position
translate(dx, dy, dz)[source]

Arguments:

dx
x translation
dy
y translation
dz
z translation
translateX(v)[source]

Arguments:

v
x translation
translateY(v)[source]

Arguments:

v
y translation
translateZ(v)[source]

Arguments:

v
z translation
rotateToX(v)[source]

Arguments:

v
x rotation
rotateToY(v)[source]

Arguments:

v
y rotation
rotateToZ(v)[source]

Arguments:

v
z rotation
rotateIncX(v)[source]

Arguments:

v
x rotational increment
rotateIncY(v)[source]

Arguments:

v
y rotational increment
rotateIncZ(v)[source]

Arguments:

v
z rotational increment
xyz
rxryrz
sxsysz
cxcycz
rotate_to_direction(direction, forward=[0.0, 0.0, 1.0])[source]

works out the XYZ euler rotations to rotate this shape from forward to direction vectors

Arguments:
direction
3vector tuple, array or numpy array
forward
3vector, usually +ve z direction
transform_direction(direction, origin=[0.0, 0.0, 0.0])[source]

Returns a tuple of two 3D numpy arrays representing the transformed origin of this Shape and the transformed direction vector

Arguments:
direction
3vector tuple, array or numpy array
origin
3D point to use as origin of direction vector (i.e. if displaced from origin of shape)
shallow_clone()[source]

Returns a copy of this shape with its own transform details, location, rotation etc but textures and buf arrays point to the existing objects without copying them.

## Texture Module¶

pi3d.Texture.round_up_to_power_of_2(x)[source]
class pi3d.Texture.Texture(file_string, blend=False, flip=False, size=0, defer=True, mipmap=True, m_repeat=False, free_after_load=False, i_format=None, filter=None, normal_map=None, automatic_resize=True)[source]

loads an image file from disk and converts it into an array that can be used by shaders. It inherits from Loadable in order that the file access work can happen in another thread. and the conversion to opengl format can happen just in time when tex() is first called.

NB images loaded as textures can cause distortion effects unless they are certain sizes (below). If the image width is a value not in this list then it will be rescaled with a resulting loss of clarity

Allowed widths 4, 8, 16, 32, 48, 64, 72, 96, 128, 144, 192, 256, 288, 384, 512, 576, 640, 720, 768, 800, 960, 1024, 1080, 1920

Arguments:
file_string
path and name of image file relative to top dir. Can now pass an already created PIL.Image object or a numpy array instead. The alpha value of Texture willl be set according to the ‘mode’ of Image objects or the size of the last dimension of numpy arrays (4 -> alpha is True)
blend
controls if low alpha pixels are discarded (if False) or drawn by the shader. If set to true then this texture needs to be drawn AFTER other objects that are FURTHER AWAY
flip
flips the image [not used for numpy arrays]. Now this parameter could be an integer value. If bit #0 is 1, a up-down flip is perfomed, also if bit #1 is set, a left-right flip occurs
size
to resize image to [not used for numpy arrays]
defer
can load from file in other thread and defer opengl work until texture needed, default True
mipmap
create and use mipmaps for this texture (if true - linear interpolation will be used by default, else nearest interpolation). see filter to control this behavior NB BECAUSE THIS BEHAVIOUR IS SET GLOBALLY AT THE TIME THAT THE TEXTURE IS LOADED IT WILL BE SET BY THE LAST TEXTURE TO BE LOADED PRIOR TO DRAWING TODO possibly reset in Buffer.draw() each time a texture is loaded?
m_repeat
if the texture is repeated (see umult and vmult in Shape.set_draw_details) then this can be used to make a non-seamless texture tile
i_format
opengl internal format for the texture - see glTexImage2D
filter
interpolation to use for for textures: GL_NEAREST or GL_LINEAR. if mipmap is true: NEAREST_MIPMAP_NEAREST or LINEAR_MIPMAP_NEAREST (default) will be used as minfilter if mipmap is false: NEAREST (default) or LINEAR will be used as filter
normal_map
if a value is not None then the image file will be converted into a normal map where Luminance value is proportional to height. The value of nomral_map is used the scale the effect (see _normal_map())
automatic_resize
default to True, this can be overridden if running on a machine other than the RPi where the GPU can cope with any image dimension - or alternatively where you know that the images will comply and don’t need to check.
tex()[source]

do the deferred opengl work and return texture

update_ndarray(new_array=None, texture_num=None)[source]

to allow numpy arrays to be patched in to textures without regenerating new glTextureBuffers i.e. for movie textures

new_array
ndarray, if supplied this will be the pixel data for the new Texture2D
texture_num
int, if supplied this will make the update effective for a specific sampler number i.e. as held in the Buffer.textures array. This will be required where multiple textures are used on some of the Buffers being drawn in the scene
class pi3d.Texture.TextureCache(max_size=None)[source]

Bases: object

clear()[source]
create`(file_string, blend=False, flip=False, size=0, **kwds)[source]