Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0

Showing posts with label Vec3D. Show all posts
Showing posts with label Vec3D. Show all posts

Friday, 6 March 2015

Bezier patch sketch in JRubyArt

Occasionally I see people trawling over really old sketches in this blog, and I wonder what are they thinking? when program versions (ie newer ruby-processing versions) change or there are new opportunities such as JRubyArt, why not look at the "hot" stuff. Anyway I revised this sketch for JRubyArt (no need to import :vecmath it is built in)....
Sketch also makes use of AppRender to make for direct conversion from Vec3D to vertex/normal.
# bezier patch By Marius Watz:
# http://www.openprocessing.org/sketch/57709
# Normal calculation added by Andres Colubri
# Direct port of sample code by Paul Bourke.
# Original code: http://paulbourke.net/geometry/bezier/
#
# hit "spacebar" to generate a new shape and save current
#

NI = 4
NJ = 5
RESI = NI * 10
RESJ = NJ * 10

attr_accessor :outp, :inp, :normp, :auto_normals, :renderer

def setup
  sketch_title 'Bezier Patch'
  ArcBall.init(self)
  @auto_normals = false
  @renderer = AppRender.new(self)
  build
end

def draw
  background(255)
  smooth(8)
  lights
  no_stroke
  fill(192, 192, 192)
  define_lights
  lights
  (0...RESI - 1).each do |i|
    begin_shape(QUAD_STRIP)
    (0...RESJ).each do |j|
      normp[i][j].to_normal(renderer) unless auto_normals
      outp[i][j].to_vertex(renderer)
      outp[i + 1][j].to_vertex(renderer)
    end
    end_shape
  end
end

def settings
  size(1024, 768, P3D)
end

def define_lights
  ambient_light(60, 60, 60)
  point_light(30, 30, 30, 0, 0, 0)
  directional_light(40, 40, 50, 1, 0, 0)
  spot_light(30, 30, 30, 0, 40, 200, 0, -0.5, 0.5, PI / 2, 2)
end


def key_pressed
  return unless key == ' '
  save_frame('bez_patch.png')
  build
end

def build
  @outp = []
  @normp = []
  @inp = []
  uitang = Vec3D.new
  ujtang = Vec3D.new
  (0...NI).each do |i|
    row = []
    (0...NJ).each do |j|
      row << Vec3D.new(i, j, (rand * 6) - 3)
    end
    inp << row
  end
  (0...RESI).each do |i|
    mui = i.fdiv(RESI - 1)
    row = []
    row_n = []
    (0...RESJ).each do |j|
      muj = j.fdiv(RESJ - 1)
      vect = Vec3D.new
      uitang = Vec3D.new
      ujtang = Vec3D.new
      (0...NI).each do |ki|
        bi = bezier_blend(ki, mui, NI)
        dbi = d_bezier_blend(ki, mui, NI)
        (0...NJ).each do |kj|
          bj = bezier_blend(kj, muj, NJ)
          dbj = d_bezier_blend(kj, muj, NJ)
          vect.x += (inp[ki][kj].x * bi * bj)
          vect.y += (inp[ki][kj].y * bi * bj)
          vect.z += (inp[ki][kj].z * bi * bj)
          uitang.x += (inp[ki][kj].x * dbi * bj)
          uitang.y += (inp[ki][kj].y * dbi * bj)
          uitang.z += (inp[ki][kj].z * dbi * bj)
          ujtang.x += (inp[ki][kj].x * bi * dbj)
          ujtang.y += (inp[ki][kj].y * bi * dbj)
          ujtang.z += (inp[ki][kj].z * bi * dbj)
        end
      end
      vect += Vec3D.new(-NI / 2, -NJ / 2, 0)
      vect *= 100
      row << vect
      uitang.normalize!
      row_n << uitang.cross(ujtang.normalize)
    end
    @outp << row
    @normp << row_n
  end
end

def bezier_blend(k, mu,  n)
  blend = 1.0
  nn = n
  kn = k
  nkn = n - k
  while (nn >= 1)
    blend *= nn
    nn -= 1
    if kn > 1
      blend = blend.fdiv(kn)
      kn -= 1
    end
    if nkn > 1
      blend = blend.fdiv(nkn)
      nkn -= 1
    end
  end
  blend *= mu**k.to_f if k > 0
  return blend * (1 - mu)**(n - k).to_f if n - k > 0
  blend
end

def d_bezier_blend(k, mu,  n)
  dblendf = 1.0
  nn = n
  kn = k
  nkn = n - k
  while (nn >= 1)
    dblendf *= nn
    nn -= 1
    if kn > 1
      dblendf = dblendf.fdiv(kn)
      kn -= 1
    end
    if nkn > 1
      dblendf = dblendf.fdiv(nkn)
      nkn -= 1
    end
  end
  fk = 1
  dk = 0
  fnk = 1
  dnk = 0
  if k > 0
    fk = mu**k.to_f
    dk = k * mu**(k - 1).to_f
  end
  if n - k > 0
    fnk = (1 - mu)**(n - k).to_f
    dnk = (k - n) * (1 - mu)**(n - k - 1).to_f
  end
  dblendf * (dk * fnk + fk * dnk)
end

Tuesday, 23 December 2014

Lorenz Attractor Ruby-Processing

Here is a processing sketch that used a LinkedList (not needed in ruby version, an array is sufficient)
LENGTH = 10_000
SPEED = 10

load_library 'vecmath'

attr_accessor :particles, :a, :b, :c, :d

def setup
  size 512, 512, P3D
  ArcBall.init(self)
  frame_rate 30
  stroke color(0, 0, 0, 33)
  stroke_weight 2
  @a = 10
  @b = 28
  @c = 8 / 3
  @d = 0.75
  init_particles
end

def draw
  background(255)
  advance_particles(SPEED)
  draw_particles
end

def init_particles
  @particles = []
  LENGTH.times do
    add_particle(Vec3D.new 1.5, -1.5, 1.5) # need to start somewhere
  end
end

def add_particle(p)
  step = Vec3D.new(a * (p.y - p.x), p.x * (b - p.z) - p.y, p.x * p.y - c * p.z)
  step *= (d / step.mag)
  particles << p + step
end

def advance_particles(count)
  (1..count).each do
    particles.shift
    add_particle(particles.last)
  end
end

def draw_particles
  scale(8)
  particles.each_cons(2) do |a, b|
    stroke(color((b.x - a.x) * 255, (b.y - a.y) * 255, (b.z - a.z) * 255, 88))
    line(a.x, a.y, a.z - 30, b.x, b.y, b.z - 30)
  end
end

Monday, 6 October 2014

Vec3D to shape vertex in JRubyArt

Here is a shader sketch that will run with regular jruby and the JRubyArt gem, converted from ruby-processing. The original processing sketch by Andrés Colubri used PVector, the use Vec3D allows us to chain vector operations, and further (thanks to the ShapeRender interface) write them directly to the PShape verticies.

 
# Trefoil, by Andres Colubri
# A parametric surface is textured procedurally
# by drawing on an offscreen PGraphics surface.
#
# Features (Vec3D).to_normal(renderer) and (Vec3D).to_vertex_uv(renderer, u, v)
# see line 55 for inititialization of renderer where obj is an instance of PShape
# renderer = ShapeRender.new(obj)
require 'jruby_art'

class Trefoil < Processing::AppGL

  attr_reader :pg, :trefoil

  def setup
    size(1024, 768, P3D)
    texture_mode(NORMAL)
    no_stroke
    # Creating offscreen surface for 3D rendering.
    @pg = create_graphics(32, 512, P3D)
    pg.begin_draw
    pg.background(0, 0)
    pg.noStroke
    pg.fill(255, 0, 0, 200)
    pg.end_draw
    # Saving trefoil surface into a PShape3D object
    @trefoil = create_trefoil(350, 60, 15, pg)
  end

  def draw
    background(0)
    pg.begin_draw
    pg.ellipse(rand(0.0..pg.width), rand(0.0..pg.height), 4, 4)
    pg.end_draw
    ambient(250, 250, 250)
    pointLight(255, 255, 255, 0, 0, 200)
    push_matrix
    translate(width/2, height/2, -200)
    rotate_x(frame_count * PI / 500)
    rotate_y(frame_count * PI / 500)
    shape(trefoil)
    pop_matrix
 end

  # Code to draw a trefoil knot surface, with normals and texture 
  # coordinates. Makes of the Vec3D Render interface (uses ShapeRender here).
  # Adapted from the parametric equations example by Philip Rideout:
  # http://iphone-3d-programming.labs.oreilly.com/ch03.html

  # This function draws a trefoil knot surface as a triangle mesh derived
  # from its parametric equation.
  def create_trefoil(s, ny, nx, tex)
    obj = create_shape()
    obj.begin_shape(TRIANGLES)
    obj.texture(tex)
    renderer = ShapeRender.new(obj)
    (0 ... nx).each do |j|
      u0 = j.to_f / nx
      u1 = (j + 1).to_f / nx
      (0 ... ny).each do |i|
        v0 = i.to_f / ny
        v1 = (i + 1).to_f / ny
        p0 = eval_point(u0, v0)
        n0 = eval_normal(u0, v0)
        p1 = eval_point(u0, v1)
        n1 = eval_normal(u0, v1)
        p2 = eval_point(u1, v1)
        n2 = eval_normal(u1, v1)
        # Triangle p0-p1-p2      
        n0.to_normal(renderer)
        (p0 * s).to_vertex_uv(renderer, u0, v0)
        n1.to_normal(renderer)
        (p1 * s).to_vertex_uv(renderer, u0, v1)
        n2.to_normal(renderer)
        (p2 * s).to_vertex_uv(renderer, u1, v1)
        p1 = eval_point(u1, v0)
        n1 = eval_normal(u1, v0)
        # Triangle p0-p2-p1      
        n0.to_normal(renderer)
        (p0 * s).to_vertex_uv(renderer, u0, v0)
        n2.to_normal(renderer)
        (p2 * s).to_vertex_uv(renderer, u1, v1)
        n1.to_normal(renderer)
        (p1 * s).to_vertex_uv(renderer, u1, v0)
      end
    end
    obj.end_shape
    return obj
  end

  # Evaluates the surface normal corresponding to normalized 
  # parameters (u, v)
  def eval_normal(u, v)
    # Compute the tangents and their cross product.
    p = eval_point(u, v)
    tang_u = eval_point(u + 0.01, v)
    tang_v = eval_point(u, v + 0.01)
    tang_u -= p
    tang_v.cross(tang_u).normalize! # it is easy to chain Vec3D operations
  end

  # Evaluates the surface point corresponding to normalized 
  # parameters (u, v)
  def eval_point(u, v)
    a = 0.5
    b = 0.3
    c = 0.5
    d = 0.1
    s = TAU * u
    t = (TAU * (1 - v)) * 2
    sint = Math.sin(t)
    cost = Math.cos(t)
    sint15 = Math.sin(1.5 * t)
    cost15 = Math.cos(1.5 * t)
    r = a + b * cost15
    x = r * cost
    y = r * sint
    z = c * sint15
    dv = Vec3D.new(
      -1.5 * b * sint15 * cost - y,
      -1.5 * b * sint15 * sint + x,
      1.5 * c * cost15)
    q = dv.normalize     # regular normalize creates a new Vec3D for us
    qvn = Vec3D.new(q.y, -q.x, 0).normalize!  # chained Vec3D operations
    ww = q.cross(qvn)
    coss = Math.cos(s)
    sins = Math.sin(s)
    Vec3D.new(
      x + d * (qvn.x * coss + ww.x * sins),
      y + d * (qvn.y * coss + ww.y * sins),
      z + d * ww.z * sins)
  end
end

Trefoil.new(title: 'Trefoil', fullscreen: true, bgcolor: '#000000')





Saturday, 24 May 2014

Extending ruby-processing with built in jruby extensions

A jruby extension need not be a gem (and in some ways extension as gems can be limiting with ruby-processing, as they do not work too easily with jruby-complete) instead it can become a custom or built in library. In the development branch of ruby-processing (fastmath fork) I have created two built in libraries as jruby extensions:-
  1. vecmath, as direct replacement for PVector and incorporation arcball functionality (uses jafama under hood)
  2. fastmath, incorporating degree precision deg/cos lookup table and a wrapper for some jafama functions

For the vecmath I took the advantage of working with java to create arcball functionality using processing reflection calls. I also chose to allow simple Vec3D to vertex and Vec3D to normal (this has got to be most efficient way since it avoids unecessary java to ruby, ruby to java conversions something missing in vanilla processing). Here is a sketch (original by Andrés Colubri) that uses the FastMath sin and cos functions (from jafama) and Vec3D to vertex and Vec3D to normal conversions.
# Trefoil, by Andres Colubri
# A parametric surface is textured procedurally
# by drawing on an offscreen PGraphics surface.

load_libraries :vecmath, :fastmath

attr_reader :pg, :trefoil

def setup
  size(1024, 768, P3D)

  texture_mode(NORMAL)
  noStroke

  # Creating offscreen surface for 3D rendering.
  @pg = create_graphics(32, 512, P3D)
  pg.begin_draw
  pg.background(0, 0)
  pg.noStroke
  pg.fill(255, 0, 0, 200)
  pg.end_draw

  # Saving trefoil surface into a PShape3D object
  @trefoil = create_trefoil(350, 60, 15, pg)
end

def draw
  background(0)

  pg.begin_draw
  pg.ellipse(rand(0.0 .. pg.width), rand(0.0 .. pg.height), 4, 4)
  pg.end_draw

  ambient(250, 250, 250)
  pointLight(255, 255, 255, 0, 0, 200)

  push_matrix
  translate(width/2, height/2, -200)
  rotate_x(frame_count * PI / 500)
  rotate_y(frame_count * PI / 500)
  shape(trefoil)
  pop_matrix
end

# Code to draw a trefoil knot surface, with normals and texture 
# coordinates.
# Adapted from the parametric equations example by Philip Rideout:
# http://iphone-3d-programming.labs.oreilly.com/ch03.html

# This function draws a trefoil knot surface as a triangle mesh derived
# from its parametric equation.
def create_trefoil(s, ny, nx, tex)

  obj = create_shape()
  obj.begin_shape(TRIANGLES)
  obj.texture(tex)

  (0 ... nx).each do |j|
    u0 = j.to_f / nx
    u1 = (j + 1).to_f / nx
    (0 ... ny).each do |i|
      v0 = i.to_f / ny
      v1 = (i + 1).to_f / ny

      p0 = eval_point(u0, v0)
      n0 = eval_normal(u0, v0)

      p1 = eval_point(u0, v1)
      n1 = eval_normal(u0, v1)

      p2 = eval_point(u1, v1)
      n2 = eval_normal(u1, v1)

      # Triangle p0-p1-p2      
      n0.shape_normal(obj)
      pa = p0 * s
      pa.shape_vertex(obj, u0, v0)
      n1.shape_normal(obj)
      pb = p1 * s
      pb.shape_vertex(obj, u0, v1)
      n2.shape_normal(obj)
      pc = p2 * s
      pc.shape_vertex(obj, u1, v1)

      p1 = eval_point(u1, v0)
      n1 = eval_normal(u1, v0)

      # Triangle p0-p2-p1      
      n0.shape_normal(obj)
      pa.shape_vertex(obj, u0, v0)
      n2.shape_normal(obj)
      pc.shape_vertex(obj, u1, v1)
      n1.shape_normal(obj)
      pb = p1 * s
      pb.shape_vertex(obj, u1, v0)
    end
  end
  obj.end_shape
  return obj
end

# Evaluates the surface normal corresponding to normalized 
# parameters (u, v)
def eval_normal(u, v)
  # Compute the tangents and their cross product.
  p = eval_point(u, v)
  tangU = eval_point(u + 0.01, v)
  tangV = eval_point(u, v + 0.01)
  tangU -= p
  tangV -= p

  normUV = tangV.cross(tangU)
  normUV.normalize!
  return normUV
end

# Evaluates the surface point corresponding to normalized 
# parameters (u, v)
def eval_point(u, v)
  a = 0.5
  b = 0.3
  c = 0.5
  d = 0.1
  s = TWO_PI * u
  t = (TWO_PI * (1 - v)) * 2

  r = a + b * FastMath.cos(1.5 * t)
  x = r * FastMath.cos(t)
  y = r * FastMath.sin(t)
  z = c * FastMath.sin(1.5 * t)

  dv = Vec3D.new
  dv.x = -1.5 * b * FastMath.sin(1.5 * t) * FastMath.cos(t) - (a + b * FastMath.cos(1.5 * t)) * FastMath.sin(t)
  dv.y = -1.5 * b * FastMath.sin(1.5 * t) * FastMath.sin(t) + (a + b * FastMath.cos(1.5 * t)) * FastMath.cos(t)
  dv.z = 1.5 * c * FastMath.cos(1.5 * t)

  q = dv
  q.normalize!
  qvn = Vec3D.new(q.y, -q.x, 0)
  qvn.normalize!
  ww = q.cross(qvn)

  pt = Vec3D.new
  pt.x = x + d * (qvn.x * FastMath.cos(s) + ww.x * FastMath.sin(s))
  pt.y = y + d * (qvn.y * FastMath.cos(s) + ww.y * FastMath.sin(s))
  pt.z = z + d * ww.z * FastMath.sin(s)
  return pt
end



For the curious the current version of ruby-processings jruby extensions are available here.

Sunday, 12 January 2014

Frame of Reference Example Sketch (Original by Ira Greenberg)

Here's another processing sketch that I've translated to ruby-processing, where I replace PVector with Vec3D from the ruby processing vecmath library. It also makes use of the ArcBall functionality built into the vecamth library.
###############
# Frame of Reference example by Ira Greenberg
# https://github.com/irajgreenberg/ProcessingTips
# Translated to ruby-processing by Martin Prout January 2014
# Now use mouse drag for ArcBall manipulation, and  +/- keys for zoom
###############

load_library :vecmath
load_library :geometry

FACE_COUNT = 50

attr_reader :arcball, :c, :p, :zoom

def setup
  size(800, 800, P3D)
  @zoom = 1.0
  camera(0, 0, (height/2.0) / tan(PI*30.0 / 180.0), 0, 0, 0, 0, -1, 0) # point camera at origin
  # create an Arcball at centre that pretty much fills the screen
  @arcball = ArcBall.new(0, 0, min(width - 20, height - 20) / 2.0)
  @c = []
  @p = []
  FACE_COUNT.times do |i|

    # calc some random triangles in 3 space
    val = Vec3D.new(rand(-width/2 .. width/2), rand(-width/2 .. width/2), rand(-width/2 .. width/2))
    v0 = Vec3D.new(rand(-val.x .. -val.x + 100), rand(-val.y .. -val.y + 100), rand(-val.z .. -val.z + 100))
    v1 = Vec3D.new(rand(-val.x .. -val.x + 100), rand(-val.y .. -val.y + 100), rand(-val.z .. -val.z + 100))
    v2 = Vec3D.new(rand(-val.x .. -val.x + 100), rand(-val.y .. -val.y + 100), rand(-val.z .. -val.z + 100))
    p << Plane.new([v0, v1, v2])

    # build some cute little cylinders
    c << Cylinder.new(Vec3D.new(150, 5, 5), 12)

    # Using each Triangle normal (N), 
    # One of the Triangle's edges as a tangent (T)  
    # Calculate a bi-normal (B) using the cross-product between each N and T
    # Note caps represent constants in ruby so we used N = nn, T = tt and B = bb in the ruby code below

    #
    # A picture helps
    # nice, sweet orthogonal axes 

    # N   B
    # |  /
    # | /
    # |/____T

    #
    # N, T, B together give you a Frame of Reference (cute little local coordinate system), based on each triangle. 
    # You can then take the cylinder (or any vertices) and transform them using a 3 x 3 matrix to this coordinate system.
    # (In the matrix each column is based on N, T and B respectivley.) 
    # The transform will handle any rotations and scaling, but not the translation, 
    # but we can add another dimenson to the matrix to hold the translation values.  
    # Here's what all this confusing description looks like:

    #
    # Matrix :                               Vector :
    # |  N.x  T.x  B.x  translation.x  |      |  x  |
    # |  N.y  T.y  B.y  translation.y  |      |  y  |
    # |  N.z  T.z  B.z  translation.z  |      |  z  |
    # |  0    0    0    1              |      |  1  |

    # We add the extra row in the matrix and the 1 to each vector 
    # so the math works. We describe the Matrix as 4 rows by 4 columns
    # and the vector now as a Matrix with 4 rows and 1 column. 
    # When you multiply matrices the inner numbers MUST match, so: 
    # [4 x 4] [4 x 1] is OK, but [4 x 4] [1 x 4] is NOT COOL.

    # (Please note there is also row vector approach that you can use,
    # Google about; it simply puts the vector on left side of matrix and treats
    # it as a 1 row and 4 column matrix. However, you'll also need to shift
    # the translation terms to the bottom of the matrix for the math to grock.)

    # The Matrix multiplication looks like this (sorry it's a little tedious looking.)
    # n.x * x + t.x *y + B.x * z + translation.x * 1  =  new transformed x
    # n.y * x + t.y *y + B.y * z + translation.y * 1  =  new transformed y
    # n.z * x + t.z *y + B.z * z + translation.z * 1  =  new transformed z
    # 0 * x + 0 *y + 0 * z + 1 * 1   =   disregard this crap.
    #

    nn = p[i].n
    tt = Vec3D.new(p[i].vecs[1].x - p[i].vecs[0].x, p[i].vecs[1].y - p[i].vecs[0].y, p[i].vecs[1].z - p[i].vecs[0].z)
    nn.normalize!
    tt.normalize!
    bb = nn.cross(tt)
    bb.normalize! # not really needed

    # build matrix with frame and translation (to centroid of each triangle)
    m4 = Mat4.new(nn, tt, bb, p[i].c)

    # transform each cylinder to align with each triangle
    c[i].vecs = m4.mult(c[i].vecs)
  end
  fill(187)
  stroke(50, 20)
end

def draw
  background(0)
  lights
  # update the arcball rotation
  update
  FACE_COUNT.times do |i|
    p[i].display
    c[i].display
  end
end

def update
  theta, x, y, z = arcball.update
  rotate(theta, x, y, z)
end

def mouse_pressed
  arcball.mouse_pressed(mouse_x, mouse_y)
end

def mouse_dragged
  arcball.mouse_dragged(mouse_x, mouse_y)
end

def key_pressed
  case key
  when '+'
    @zoom -= 0.1  # closer is bigger
  when '-'
    @zoom += 0.1
  end
  camera(0, 0, (height * zoom / 2.0) / tan(PI*30.0 / 180.0), 0, 0, 0, 0, -1, 0)
end


Here is the Plane class
NORM_LEN = 225.0

class Plane
  include Processing::Proxy

  attr_reader :vecs, :c, :n


  def initialize(vecs)
    @vecs = vecs
    init
  end

  def init
    v1 = vecs[1].dup
    v2 = vecs[2].dup
    v1 -= vecs[0]
    v2 -= vecs[0]

    @c = Vec3D.new(
      (vecs[0].x+vecs[1].x+vecs[2].x) / 3,
      (vecs[0].y+vecs[1].y+vecs[2].y) / 3,
      (vecs[0].z+vecs[1].z+vecs[2].z) / 3
      )

    @n = v1.cross(v2)
    n.normalize!
  end

  def display
    begin_shape(TRIANGLES)
    vecs.each do |vec|
      vertex(vec.x, vec.y, vec.z)
    end
    end_shape

    #normal
    stroke(200, 160, 30)
    begin_shape(LINES)
    vertex(c.x, c.y, c.z)
    vertex(c.x + n.x * NORM_LEN, c.y + n.y * NORM_LEN, c.z + n.z * NORM_LEN)
    end_shape

    #binormal
    stroke(160, 200, 30)
    begin_shape(LINES)
    vertex(c.x, c.y, c.z)
    # tangent
    v = vecs[1].dup
    #v.set(vecs[1])
    v -= vecs[0]
    v.normalize!
    vertex(c.x + v.x * NORM_LEN, c.y + v.y * NORM_LEN, c.z + v.z * NORM_LEN)
    end_shape

    stroke(30, 200, 160)
    begin_shape(LINES)
    vertex(c.x, c.y, c.z)
    b = v.cross(n)
    vertex(c.x + b.x * NORM_LEN, c.y + b.y * NORM_LEN, c.z + b.z * NORM_LEN)
    end_shape
    stroke(0, 75)
  end
end



Here is the Mat4 class
# uber simple Homogeneous 4 x 4 matrix

class Mat4
  attr_reader :mat

  def initialize(axisX, axisY, axisZ, trans)
    @mat = [
    [axisX.x, axisY.x, axisZ.x, trans.x],
    [axisX.y, axisY.y, axisZ.y, trans.y],
    [axisX.z, axisY.z, axisZ.z, trans.z],
    [0, 0, 0,  1]
    ]
  end

  # The processing version changes the input 'array', here we return
  # a new array with transformed values (which we then assign to the input)
  # see line 91 Frame_of_Reference.rb

  def mult(array)
    temp = []
    array.each do |arr|
      xt = mat[0][0] * arr.x + mat[0][1] * arr.y + mat[0][2] * arr.z + mat[0][3] * 1
      yt = mat[1][0] * arr.x + mat[1][1] * arr.y + mat[1][2] * arr.z + mat[1][3] * 1
      zt = mat[2][0] * arr.x + mat[2][1] * arr.y + mat[2][2] * arr.z + mat[2][3] * 1
      temp << Vec3D.new(xt, yt, zt)
    end
    return temp
  end
end


Here is the Cylinder class
class Cylinder
  include Processing::Proxy
  attr_accessor :vecs
  attr_reader :detail, :dim



  def initialize(dim, detail)
    @dim = dim
    @detail = detail
    init
  end

  def init
    theta = 0.0
    #    created around x-axis
    #    y = Math.cos
    #    z = Math.sin
    veca = []
    vecb = []
    detail.times do
      veca << Vec3D.new(0, Math.cos(theta)*dim.y, Math.sin(theta)*dim.z)
      vecb << Vec3D.new(dim.x, Math.cos(theta)*dim.y, Math.sin(theta)*dim.z)
      theta += Math::PI * 2/detail
    end
    @vecs = veca.concat(vecb)
  end

  def display
    begin_shape(QUADS)
    detail.times do |i|
      if (i<detail-1)
        vertex(vecs[i].x, vecs[i].y, vecs[i].z)
        vertex(vecs[i+1].x, vecs[i+1].y, vecs[i+1].z)
        vertex(vecs[detail+i+1].x, vecs[detail+i+1].y, vecs[detail+i+1].z)
        vertex(vecs[detail+i].x, vecs[detail+i].y, vecs[detail+i].z)
      else
        vertex(vecs[i].x, vecs[i].y, vecs[i].z)
        vertex(vecs[0].x, vecs[0].y, vecs[0].z)
        vertex(vecs[detail].x, vecs[detail].y, vecs[detail].z)
        vertex(vecs[detail+i].x, vecs[detail+i].y, vecs[detail+i].z)
      end
    end
    end_shape
  end
end

Followers

About Me

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