Recently I've been looking at Povray, pyprocessing, and cfdg (version 3.0) as tools for creating digital images. I have branched two separate blogs where I mainly explore jruby + processing and processing.py

Sunday, 11 November 2012

Using FBO in processing.py

Since processing-2.0 there is the possibility of creating a retained shape (or FBO) this is achieved by creating a PShape object, here is example of that in processing.py. Note: I'm using the current development version on github, except I re-compiled it using jython-2.5.3 (standalone) and the latest version of the processing core.jar (all compiled with jdk1.7.0_09).
   1 from arcball.arcball import ArcBall
   2 
   3 """
   4 test_arcball.py by Martin Prout a processing.py sketch
   5 Sketch features the use of ArcBall class, provides intuitive manipulation of sketch object
   6 ArcBall class uses Quaternions class for efficient calculation of rotation, hold down x, y or z
   7 keys to constrain rotation to that plane otherwise drag mouse for smooth rotation
   8 @todo add mousewheel zoom?
   9 """
  10 X = 0
  11 Y = 1
  12 Z = 2
  13 
  14 def setup():
  15     size(800, 600, P3D)
  16     smooth(16)
  17     global arcball, my_cube
  18     arcball = ArcBall(width/2.0, height/2.0, min(width - 20, height - 20) * 0.5)
  19     my_cube = cube(arcball.radius)
  20 
  21 def draw():
  22     background(0xff66c0ff)
  23     translate(width/2.0, height/2.0)
  24     defineLights()
  25     update()
  26     lights()
  27     shape(my_cube)
  28     
  29     
  30 def update():
  31     """
  32     wrap arcball update and rotation as a local function
  33     """
  34     theta, x, y, z = arcball.update()
  35     rotate(theta, x, y, z)    
  36 
  37 def mousePressed():
  38     arcball.mousePressed(mouseX, mouseY)
  39   
  40 def mouseDragged():
  41     arcball.mouseDragged(mouseX, mouseY) 
  42 
  43 def defineLights():
  44     """
  45     Light up the cube
  46     """
  47     ambientLight(50, 50, 50)
  48     pointLight(150, 100, 0, 200, -150, 0)
  49     directionalLight(0, 102, 255, 1, 0, 0)
  50     spotLight(255, 255, 109, 0, 40, 200, 0, -0.5, -0.5, PI / 2, 2)
  51 
  52 def keyPressed():
  53     """
  54     Constrain axis of rotation by holding down key 
  55     corresponding to axis
  56     """
  57     if (key == 'x'):  
  58         arcball.selectAxis(X)
  59     if (key == 'y'):  
  60         arcball.selectAxis(Y)
  61     if (key == 'z'):  
  62         arcball.selectAxis(Z)
  63 
  64 def keyReleased():
  65     """
  66     Release axis constraint
  67     """
  68     arcball.selectAxis(-1)
  69 
  70 def cube(sz):
  71     """
  72     Create and return the FBO cub
  73     """
  74     sz *= 0.5       
  75     cub = createShape(QUADS)
  76     cub.fill(200,  200,  200,  255)
  77     cub.ambient(50)
  78     cub.specular(30)
  79     cub.vertex(-sz, -sz, -sz)
  80     cub.vertex(+sz, -sz, -sz)
  81     cub.vertex(+sz, +sz, -sz)
  82     cub.vertex(-sz, +sz, -sz)
  83     cub.vertex(-sz, -sz, +sz)
  84     cub.vertex(+sz, -sz, +sz)
  85     cub.vertex(+sz, +sz, +sz)
  86     cub.vertex(-sz, +sz, +sz)
  87     cub.vertex(-sz, -sz, -sz)
  88     cub.vertex(-sz, -sz, +sz)
  89     cub.vertex(-sz, +sz, +sz)
  90     cub.vertex(-sz, +sz, -sz)
  91     cub.vertex(+sz, -sz, -sz)
  92     cub.vertex(+sz, -sz, +sz)
  93     cub.vertex(+sz, +sz, +sz)
  94     cub.vertex(+sz, +sz, -sz)
  95     cub.vertex(-sz, -sz, -sz)
  96     cub.vertex(+sz, -sz, -sz)
  97     cub.vertex(+sz, -sz, +sz)
  98     cub.vertex(-sz, -sz, +sz)
  99     cub.vertex(-sz, +sz, -sz)
 100     cub.vertex(+sz, +sz, -sz)
 101     cub.vertex(+sz, +sz, +sz)
 102     cub.vertex(-sz, +sz, +sz)
 103     cub.end()
 104     return cub

The Quaternion
   1 from math import acos, sqrt
   2 from processing.core import PConstants
   3 
   4 class Quaternion(object):
   5     """
   6     Helper class, originally written for use by ArcBall class
   7     """
   8  
   9     def __init__(self, w = 1.0,  x = 0,  y = 0,  z = 0):   
  10         """
  11         Important to initialize default with unit matrix
  12         """
  13         self.w, self.x, self.y, self.z = w,  x,  y,  z
  14     
  15     def reset(self):
  16         """
  17         Reset quaternion to unit matrix
  18         """
  19         self.w = 1.0
  20         self.x = 0.0
  21         self.y = 0.0
  22         self.z = 0.0
  23         
  24     def set(self,  w, v):
  25         """
  26         Set quaternion given w float and PVector
  27         """
  28         self.w = w
  29         self.x = v.x
  30         self.y = v.y
  31         self.z = v.z
  32         
  33     def copy(self,  q):
  34         """
  35         Copy quaternion q
  36         """
  37         self.w = q.w
  38         self.x = q.x
  39         self.y = q.y
  40         self.z = q.z  
  41         
  42     @classmethod  
  43     def mult(clas, q1, q2): 
  44         """
  45         class method returns a new instance of Quaternion as a product of 
  46         two input Quaternions
  47         """        
  48         x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
  49         y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z
  50         z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x
  51         w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
  52         return Quaternion(w,  x,  y,  z)
  53         
  54     def getValue(self):
  55         """
  56         Using processing epsilon
  57         """
  58         sa = sqrt(1.0 - self.w * self.w)
  59   
  60         if (sa < PConstants.EPSILON):
  61             sa = 1.0
  62         return [acos(self.w) * 2, self.x / sa, self.y / sa, self.z / sa]
  63  
  64 

The ArcBall class
   1 from processing.core import PVector
   2 from quaternion import Quaternion
   3 from math import sqrt
   4 
   5 class ArcBall(object):
   6     """
   7     Class contains ArcBall logic see test_arcball.py for usage
   8     """
   9     def __init__(self, cx, cy, radius):
  10         """
  11         Initialize instance of ArcBall with no constraint on axis of rotation
  12         """
  13         self.center_x = cx
  14         self.center_y = cy
  15         self.radius = radius
  16         self.v_down = PVector()
  17         self.v_drag = PVector()
  18         self.q_now = Quaternion()
  19         self.q_down = Quaternion()
  20         self.q_drag = Quaternion() 
  21         self.axis_set = [PVector(1.0, 0.0, 0.0), PVector(0.0, 1.0, 0.0), PVector(0.0, 0.0, 1.0)]
  22         self.axis = -1  
  23         
  24     def selectAxis(self, axis):
  25         """
  26         call this from sketch (typically in keyPressed() to constrain rotation to one axis)
  27         valid input 0, 1, 2 or -1
  28         """
  29         if ((axis == -1) or (axis == 0) or (axis == 1) or (axis == 2)):
  30           self.axis = axis
  31         
  32     def __mouse2sphere(self, x, y):
  33         """
  34         private map mouse to ArcBall (sphere)
  35         """
  36         v = PVector()
  37         v.x = (x - self.center_x) / self.radius
  38         v.y = (y - self.center_y) / self.radius
  39         mag = v.x * v.x + v.y * v.y
  40         if (mag > 1.0) :
  41             v.normalize()
  42         else:
  43             v.z = sqrt(1.0 - mag)
  44         if (self.axis != -1):
  45             v = self.__constrain(v, self.axis_set[self.axis])
  46         return  v  
  47     
  48     def mousePressed(self, x, y):
  49         """
  50         pass in mouse.x and mouse.y parameters from sketch
  51         """
  52         self.v_down = self.__mouse2sphere(x, y)
  53         self.q_down.copy(self.q_now)
  54         self.q_drag.reset()
  55 
  56     def mouseDragged(self, x, y):
  57         """
  58         pass in mouse.x and mouse.y parameters from sketch
  59         """
  60         self.v_drag = self.__mouse2sphere(x, y)
  61         self.q_drag.set(PVector.dot(self.v_down, self.v_drag), self.v_down.cross(self.v_drag))
  62         
  63     def __constrain(self, vector, axis):
  64         """
  65         private constrain (used to constrain axis)
  66         """
  67         vector.sub(axis.mult(axis, PVector.dot(axis, vector)))
  68         vector.normalize()
  69         return vector
  70         
  71     def update(self):
  72         """
  73         Call this function in the sketch draw loop to get rotation matrix as an array 
  74         """
  75         self.q_now = Quaternion.mult(self.q_drag, self.q_down)
  76         return self.__quat2matrix(self.q_now)
  77 
  78     def __quat2matrix(self,  q) :
  79         """
  80         private return matrix as array
  81         """
  82         rot = q.getValue()
  83         return rot

No comments:

Post a Comment

Followers

Blog Archive

About Me

My photo
Pembrokeshire, United Kingdom
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2