Source code for plato.draw.vispy.Spheropolygons

import itertools

import numpy as np

from ... import mesh
from .internal import GLPrimitive, GLShapeDecorator
from ... import draw
from ..internal import ShapeAttribute

[docs]@GLShapeDecorator class Spheropolygons(draw.Spheropolygons, GLPrimitive): __doc__ = draw.Spheropolygons.__doc__ shaders = {} shaders['vertex'] = """ uniform mat4 camera; uniform vec4 rotation; uniform vec3 translation; uniform float radius; attribute vec4 color; attribute vec2 position; attribute vec2 image; attribute vec2 inner_image; attribute vec4 orientation; attribute vec4 shape_id; varying vec4 v_color; varying vec2 v_imageDelta; varying vec4 v_shape_id; vec2 rotate(vec2 point, vec4 quat) { vec3 point3d = vec3(point.xy, 0.0); vec3 result = (quat.x*quat.x - dot(quat.yzw, quat.yzw))*point3d; result += 2.0*quat.x*cross(quat.yzw, point3d); result += 2.0*dot(quat.yzw, point3d)*quat.yzw; return result.xy; } void main() { vec2 real_image = (image - inner_image)*radius + inner_image; vec2 vertexPos = position + rotate(real_image, orientation); vertexPos = rotate(vertexPos, rotation) + translation.xy; vec4 screenPosition = camera * vec4(vertexPos, translation.z, 1.0); // transform to screen coordinates gl_Position = screenPosition; v_color = color; v_imageDelta = real_image - inner_image; v_shape_id = shape_id; } """ shaders['fragment'] = """ uniform float outline; uniform float radius; varying vec4 v_color; varying vec2 v_imageDelta; void main() { float lambda1 = 1.0; float rsq = dot(v_imageDelta, v_imageDelta); float r = sqrt(rsq); if(outline > 1e-6) { lambda1 = (radius - r)/outline; lambda1 *= lambda1; lambda1 *= lambda1; lambda1 *= lambda1; lambda1 *= lambda1; lambda1 = min(lambda1, 1.0); } float lambda2 = 1.0; if(r > radius) discard; else if(outline <= 1e-6) { lambda2 = r/radius; lambda2 *= lambda2; lambda2 *= lambda2; lambda2 *= lambda2; lambda2 *= lambda2; lambda2 *= lambda2; lambda2 *= lambda2; lambda2 *= lambda2; lambda2 = 1.0 - min(lambda2, 1.0); } else if(r > radius - outline) { lambda2 = (r - radius + outline)/outline; lambda2 *= lambda2; lambda2 *= lambda2; lambda2 *= lambda2; lambda2 *= lambda2; lambda2 = 1.0 - min(lambda2, 1.0); } gl_FragColor = vec4(lambda1*v_color.xyz, lambda2*v_color.w); } """ shaders['fragment_pick'] = """ uniform float radius; uniform vec4 pick_prim_index; varying vec2 v_imageDelta; varying vec4 v_shape_id; void main() { float rsq = dot(v_imageDelta, v_imageDelta); float r = sqrt(rsq); if(r > radius) discard; gl_FragColor = pick_prim_index + v_shape_id; } """ _vertex_attribute_names = ['shape_id', 'position', 'orientation', 'color', 'image', 'inner_image'] _GL_UNIFORMS = list(itertools.starmap(ShapeAttribute, [ ('camera', np.float32, np.eye(4), 2, False, 'Internal: 4x4 Camera matrix for world projection'), ('rotation', np.float32, (1, 0, 0, 0), 1, False, 'Internal: Rotation to be applied to each scene as a quaternion'), ('translation', np.float32, (0, 0, 0), 1, False, 'Internal: Translation to be applied to the scene'), ('outline', np.float32, 0, 0, False, 'Outline width for shapes'), ('radius', np.float32, 0, 0, False, 'Rounding radius for shapes') ])) def __init__(self, *args, **kwargs): GLPrimitive.__init__(self) draw.Spheropolygons.__init__(self, *args, **kwargs) def update_arrays(self): if 'vertices' in self._dirty_attributes: vertices = self.vertices if len(vertices) < 3: thetas = np.linspace(0, 2*np.pi, 3, endpoint=False) vertices = np.array([np.cos(thetas), np.sin(thetas)], dtype=np.float32).T mesh_ = mesh.spheropolygonMesh(vertices, 1, granularity=2) self._gl_attributes['image'] = mesh_.image.astype(np.float32) self._gl_attributes['inner_image'] = mesh_.innerImage.astype(np.float32) self._gl_attributes['indices'] = mesh_.indices try: for name in self._dirty_attributes: if name == 'vertices': raise ValueError else: self._gl_vertex_arrays[name][:] = self._attributes[name] self._dirty_vertex_attribs.add(name) except (ValueError, KeyError): shape_ids = np.arange(len(self), dtype=np.uint32).view(np.uint8).reshape((-1, 4)) shape_ids = shape_ids.astype(np.float32)/255 vertex_arrays = mesh.unfoldProperties( [shape_ids, self.positions, self.orientations, self.colors], [self._gl_attributes['image'], self._gl_attributes['inner_image']]) unfolded_shape = vertex_arrays[0].shape[:-1] indices = (np.arange(unfolded_shape[0])[:, np.newaxis, np.newaxis]*unfolded_shape[1] + self._gl_attributes['indices']) indices = indices.reshape((-1, 3)) self._finalize_array_updates(indices, vertex_arrays) self._dirty_attributes.clear()