Module simple_3dviz.scenes
A scene defines the type of framebuffer to create and allows manipulation of the programs uniforms, such as the camera position and light.
Expand source code
"""A scene defines the type of framebuffer to create and allows manipulation of
the programs uniforms, such as the camera position and light."""
import moderngl
import numpy as np
from pyrr import Matrix44, Vector3
class BaseScene(object):
"""Base scene holds the opengl context and defines utilities that will be
useful for all scenes.
Arguments
---------
size: (width, height) of the framebuffer
background: The color of the background frame buffer
ctx: A moderngl context or None to create a standalone context
"""
def __init__(self, size=(256, 256), background=(1, 1, 1, 1), ctx=None):
if ctx is None:
self._ctx = moderngl.create_standalone_context()
self._ctx.enable(moderngl.BLEND)
self._ctx.blend_func = (
moderngl.SRC_ALPHA,
moderngl.ONE_MINUS_SRC_ALPHA
)
self._framebuffer = self._ctx.framebuffer(
self._ctx.renderbuffer(size),
self._ctx.depth_renderbuffer(size)
)
else:
self._ctx = ctx
self._framebuffer = None
self._background = background
self._renderables = dict()
@property
def size(self):
return self._ctx.fbo.size
@property
def background(self):
return self._background
@background.setter
def background(self, v):
b = list(self._background)
for i in range(len(v)):
b[i] = v[i]
self._background = tuple(b)
@property
def renderables(self):
return self._renderables.values()
def add(self, renderable):
if renderable not in self._renderables:
renderable.init(self._ctx)
self._renderables[renderable] = renderable
def remove(self, renderable):
if renderable in self._renderables:
self._renderables[renderable].release()
del self._renderables[renderable]
def clear(self):
for r in self._renderables:
r.release()
self._renderables.clear()
@property
def uniforms(self):
"""Return list of tuples with uniform name and value provided by the
scene."""
return []
def render(self):
# Update the uniforms
uniforms = self.uniforms
for r in self.renderables:
r.update_uniforms(uniforms)
# Render the scene
if self._framebuffer is not None:
self._framebuffer.use()
self._ctx.enable(moderngl.DEPTH_TEST)
self._ctx.clear(*self._background)
for r in self.renderables:
r.render()
@property
def frame(self):
if self._framebuffer is not None:
return np.frombuffer(
self._framebuffer.read(components=4),
dtype=np.uint8
).reshape(*(self._framebuffer.size + (4,)))
else:
raise RuntimeError(("This scene is rendering on a framebuffer "
"managed by someone else (gui perhaphs). "
"Access the frame from there."))
class Scene(BaseScene):
def __init__(self, size=(256, 256), background=(1, 1, 1, 1), ctx=None):
super(Scene, self).__init__(size, background, ctx)
self._camera = (
Matrix44.perspective_projection(45., 1., 0.1, 1000.)
).astype(np.float32)
self._camera_position = Vector3([-2., -2, -2], dtype="float32")
self._camera_target = Vector3([0., 0, 0], dtype="float32")
self._rotation = Matrix44.identity().astype(np.float32)
self._up_vector = Vector3([0, 0, 1], dtype="float32")
self._light = Vector3([-0.5, -0.8, -2], dtype="float32")
self._uniforms = dict(
# raw uniforms
light=self._light,
camera=self._camera,
camera_position=self._camera_position,
camera_target=self._camera_target,
rotation=self._rotation,
up_vector=self._up_vector,
# derivative uniforms
vm=self.vm,
mv=self.mv,
mvp=self.mvp
)
def _update_uniforms(self):
self._uniforms["mvp"] = self.mvp
self._uniforms["mv"] = self.mv
self._uniforms["vm"] = self.vm
@property
def vm(self):
return self.mv.inverse
@property
def mv(self):
return (Matrix44.look_at(
self._camera_position,
self._camera_target,
self._up_vector
) * self._rotation).astype(np.float32)
@property
def mvp(self):
return (self._camera * self.mv).astype(np.float32)
@property
def light(self):
return self._light.copy()
@light.setter
def light(self, l):
self._light[...] = l
@property
def camera_matrix(self):
return self._camera.copy()
@camera_matrix.setter
def camera_matrix(self, cam):
self._camera[...] = cam
self._update_uniforms()
@property
def camera_position(self):
return self._camera_position.copy()
@camera_position.setter
def camera_position(self, pos):
self._camera_position[...] = pos
self._update_uniforms()
@property
def camera_target(self):
return self._camera_target.copy()
@camera_target.setter
def camera_target(self, target):
self._camera_target[...] = target
self._update_uniforms()
@property
def up_vector(self):
return self._up_vector.copy()
@up_vector.setter
def up_vector(self, up):
self._up_vector[...] = up
self._update_uniforms()
@property
def rotation(self):
return self._rotation.copy()
@rotation.setter
def rotation(self, rot):
self._rotation[...] = rot
self._update_uniforms()
def rotate_x(self, angle):
self._rotation *= Matrix44.from_x_rotation(angle)
self._update_uniforms()
def rotate_y(self, angle):
self._rotation *= Matrix44.from_y_rotation(angle)
self._update_uniforms()
def rotate_z(self, angle):
self._rotation *= Matrix44.from_z_rotation(angle)
self._update_uniforms()
@property
def uniforms(self):
return list(self._uniforms.items())
Classes
class BaseScene (size=(256, 256), background=(1, 1, 1, 1), ctx=None)
-
Base scene holds the opengl context and defines utilities that will be useful for all scenes.
Arguments
size: (width, height) of the framebuffer background: The color of the background frame buffer ctx: A moderngl context or None to create a standalone context
Expand source code
class BaseScene(object): """Base scene holds the opengl context and defines utilities that will be useful for all scenes. Arguments --------- size: (width, height) of the framebuffer background: The color of the background frame buffer ctx: A moderngl context or None to create a standalone context """ def __init__(self, size=(256, 256), background=(1, 1, 1, 1), ctx=None): if ctx is None: self._ctx = moderngl.create_standalone_context() self._ctx.enable(moderngl.BLEND) self._ctx.blend_func = ( moderngl.SRC_ALPHA, moderngl.ONE_MINUS_SRC_ALPHA ) self._framebuffer = self._ctx.framebuffer( self._ctx.renderbuffer(size), self._ctx.depth_renderbuffer(size) ) else: self._ctx = ctx self._framebuffer = None self._background = background self._renderables = dict() @property def size(self): return self._ctx.fbo.size @property def background(self): return self._background @background.setter def background(self, v): b = list(self._background) for i in range(len(v)): b[i] = v[i] self._background = tuple(b) @property def renderables(self): return self._renderables.values() def add(self, renderable): if renderable not in self._renderables: renderable.init(self._ctx) self._renderables[renderable] = renderable def remove(self, renderable): if renderable in self._renderables: self._renderables[renderable].release() del self._renderables[renderable] def clear(self): for r in self._renderables: r.release() self._renderables.clear() @property def uniforms(self): """Return list of tuples with uniform name and value provided by the scene.""" return [] def render(self): # Update the uniforms uniforms = self.uniforms for r in self.renderables: r.update_uniforms(uniforms) # Render the scene if self._framebuffer is not None: self._framebuffer.use() self._ctx.enable(moderngl.DEPTH_TEST) self._ctx.clear(*self._background) for r in self.renderables: r.render() @property def frame(self): if self._framebuffer is not None: return np.frombuffer( self._framebuffer.read(components=4), dtype=np.uint8 ).reshape(*(self._framebuffer.size + (4,))) else: raise RuntimeError(("This scene is rendering on a framebuffer " "managed by someone else (gui perhaphs). " "Access the frame from there."))
Subclasses
Instance variables
var background
-
Expand source code
@property def background(self): return self._background
var frame
-
Expand source code
@property def frame(self): if self._framebuffer is not None: return np.frombuffer( self._framebuffer.read(components=4), dtype=np.uint8 ).reshape(*(self._framebuffer.size + (4,))) else: raise RuntimeError(("This scene is rendering on a framebuffer " "managed by someone else (gui perhaphs). " "Access the frame from there."))
var renderables
-
Expand source code
@property def renderables(self): return self._renderables.values()
var size
-
Expand source code
@property def size(self): return self._ctx.fbo.size
var uniforms
-
Return list of tuples with uniform name and value provided by the scene.
Expand source code
@property def uniforms(self): """Return list of tuples with uniform name and value provided by the scene.""" return []
Methods
def add(self, renderable)
-
Expand source code
def add(self, renderable): if renderable not in self._renderables: renderable.init(self._ctx) self._renderables[renderable] = renderable
def clear(self)
-
Expand source code
def clear(self): for r in self._renderables: r.release() self._renderables.clear()
def remove(self, renderable)
-
Expand source code
def remove(self, renderable): if renderable in self._renderables: self._renderables[renderable].release() del self._renderables[renderable]
def render(self)
-
Expand source code
def render(self): # Update the uniforms uniforms = self.uniforms for r in self.renderables: r.update_uniforms(uniforms) # Render the scene if self._framebuffer is not None: self._framebuffer.use() self._ctx.enable(moderngl.DEPTH_TEST) self._ctx.clear(*self._background) for r in self.renderables: r.render()
class Scene (size=(256, 256), background=(1, 1, 1, 1), ctx=None)
-
Base scene holds the opengl context and defines utilities that will be useful for all scenes.
Arguments
size: (width, height) of the framebuffer background: The color of the background frame buffer ctx: A moderngl context or None to create a standalone context
Expand source code
class Scene(BaseScene): def __init__(self, size=(256, 256), background=(1, 1, 1, 1), ctx=None): super(Scene, self).__init__(size, background, ctx) self._camera = ( Matrix44.perspective_projection(45., 1., 0.1, 1000.) ).astype(np.float32) self._camera_position = Vector3([-2., -2, -2], dtype="float32") self._camera_target = Vector3([0., 0, 0], dtype="float32") self._rotation = Matrix44.identity().astype(np.float32) self._up_vector = Vector3([0, 0, 1], dtype="float32") self._light = Vector3([-0.5, -0.8, -2], dtype="float32") self._uniforms = dict( # raw uniforms light=self._light, camera=self._camera, camera_position=self._camera_position, camera_target=self._camera_target, rotation=self._rotation, up_vector=self._up_vector, # derivative uniforms vm=self.vm, mv=self.mv, mvp=self.mvp ) def _update_uniforms(self): self._uniforms["mvp"] = self.mvp self._uniforms["mv"] = self.mv self._uniforms["vm"] = self.vm @property def vm(self): return self.mv.inverse @property def mv(self): return (Matrix44.look_at( self._camera_position, self._camera_target, self._up_vector ) * self._rotation).astype(np.float32) @property def mvp(self): return (self._camera * self.mv).astype(np.float32) @property def light(self): return self._light.copy() @light.setter def light(self, l): self._light[...] = l @property def camera_matrix(self): return self._camera.copy() @camera_matrix.setter def camera_matrix(self, cam): self._camera[...] = cam self._update_uniforms() @property def camera_position(self): return self._camera_position.copy() @camera_position.setter def camera_position(self, pos): self._camera_position[...] = pos self._update_uniforms() @property def camera_target(self): return self._camera_target.copy() @camera_target.setter def camera_target(self, target): self._camera_target[...] = target self._update_uniforms() @property def up_vector(self): return self._up_vector.copy() @up_vector.setter def up_vector(self, up): self._up_vector[...] = up self._update_uniforms() @property def rotation(self): return self._rotation.copy() @rotation.setter def rotation(self, rot): self._rotation[...] = rot self._update_uniforms() def rotate_x(self, angle): self._rotation *= Matrix44.from_x_rotation(angle) self._update_uniforms() def rotate_y(self, angle): self._rotation *= Matrix44.from_y_rotation(angle) self._update_uniforms() def rotate_z(self, angle): self._rotation *= Matrix44.from_z_rotation(angle) self._update_uniforms() @property def uniforms(self): return list(self._uniforms.items())
Ancestors
Instance variables
var camera_matrix
-
Expand source code
@property def camera_matrix(self): return self._camera.copy()
var camera_position
-
Expand source code
@property def camera_position(self): return self._camera_position.copy()
var camera_target
-
Expand source code
@property def camera_target(self): return self._camera_target.copy()
var light
-
Expand source code
@property def light(self): return self._light.copy()
var mv
-
Expand source code
@property def mv(self): return (Matrix44.look_at( self._camera_position, self._camera_target, self._up_vector ) * self._rotation).astype(np.float32)
var mvp
-
Expand source code
@property def mvp(self): return (self._camera * self.mv).astype(np.float32)
var rotation
-
Expand source code
@property def rotation(self): return self._rotation.copy()
var up_vector
-
Expand source code
@property def up_vector(self): return self._up_vector.copy()
var vm
-
Expand source code
@property def vm(self): return self.mv.inverse
Methods
def rotate_x(self, angle)
-
Expand source code
def rotate_x(self, angle): self._rotation *= Matrix44.from_x_rotation(angle) self._update_uniforms()
def rotate_y(self, angle)
-
Expand source code
def rotate_y(self, angle): self._rotation *= Matrix44.from_y_rotation(angle) self._update_uniforms()
def rotate_z(self, angle)
-
Expand source code
def rotate_z(self, angle): self._rotation *= Matrix44.from_z_rotation(angle) self._update_uniforms()
Inherited members