# bezier bez_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 # load_library :vecmath NI=4 NJ=5 RESI=NI*10 RESJ=NJ*10 attr_accessor :outp, :inp, :normp, :auto_normals, :arcball, :bez_patch def setup size(1024, 768, P3D) @arcball = ArcBall.new(width/2.0, height/2.0, min(width - 20, height - 20) * 0.5) @auto_normals = false build_geometry @bez_patch = build_shape end def draw background(255) translate(width/2,height/2) smooth(8) lights define_lights #scale(0.9) update shape(bez_patch) end ####### # use bez patch geometry to # create a vbo object (PShape) ####### def build_shape no_stroke bez = create_shape(QUAD_STRIP) bez.fill(192, 192, 192) bez.ambient(20, 20, 20) (0 ... RESI - 1).each do |i| (0 ... RESJ).each do |j| if (!auto_normals) bez.normal(*normp[i][j]) end bez.vertex(*outp[i][j]) bez.vertex(*outp[i+1][j]) end end bez.end # end has unfortunate ruby highlighting in jedit, not in vim though return bez end ########## # build geometry # for bez patch ########## def build_geometry @outp = [] @normp = [] @inp = [] uitang = PVector.new ujtang = PVector.new (0 ... NI).each do |i| row = Array.new (0 ... NJ).each do |j| row << PVector.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 = PVector.new uitang.set(0, 0, 0) ujtang.set(0, 0, 0) (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.add(PVector.new(-NI/2,-NJ/2,0)) vect.mult(100) row << vect.array() uitang.normalize ujtang.normalize row_n << uitang.cross(ujtang).array() 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 *= pow(mu, k.to_f) if (k > 0) blend *= pow(1-mu, (n - k).to_f) if (n - k > 0) return(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 = pow(mu, k.to_f) dk = k * pow(mu, (k - 1).to_f) end if (n - k > 0) fnk = pow(1 - mu, (n - k).to_f) dnk = (k - n)*pow(1 - mu, (n - k - 1).to_f) end dblendf *= (dk * fnk + fk * dnk) return(dblendf) end ###################### # ArcBall control # and lighting + re-run ###################### 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 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 case(key) when ' ' save_frame("bezPatch.png") build_geometry @bez_patch = build_shape when 'x' arcball.select_axis(X) when 'y' arcball.select_axis(Y) when 'z' arcball.select_axis(Z) end end def key_released arcball.select_axis(-1) endUpdated 20 February 2014 (arcball library is now in vecmath).
Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
Friday, 28 December 2012
Bezier Patch as a VBO (PShape)
Hardly needs introduction here is an alternative version of the bezier patch sketch, features ArcBall (arcball library is built in to my fork of ruby-processing, which is required to run a sketch with processing-2.0 functionality such as PShape) to rotate the patch and uses PShape object to store the geometry as a vbo.
Labels:
bezier patch,
Marius Watz,
Paul Burke,
ruby-processing,
vbo
Thursday, 27 December 2012
Bezier Patch in ruby-processing
This is getting to be a habit? Another sketch by Marius Watz translated to ruby-processing. The main reason is that I've been working on updating ruby-processing to processing-2.0, and in the course of that I'm including some sketches included with the processing-2.0 distribution and this is just another. Both these sketches benefit from taking a different approach building arrays in ruby cf java. This one has benefited from bit more tuning, as there no real need for an arrays of PVector once the math has been done. Further it is so easy to just splat array to the vertex coordinates, don't you just love ruby.
# 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 def setup size(1024, 768, P3D) @auto_normals = false build end def draw background(255) translate(width/2,height/2) smooth(8) lights #scale(0.9) rotate_y(map(mouse_x, 0, width, -PI, PI)) rotate_x(map(mouse_y, 0, height, -PI, PI)) no_stroke fill(192, 192, 192) ambient_light(100, 100, 100) ambient(40) specular(30) (0 ... RESI - 1).each do |i| beginShape(QUAD_STRIP) (0 ... RESJ).each do |j| if (!auto_normals) normal(*normp[i][j]) end vertex(*outp[i][j]) vertex(*outp[i+1][j]) end endShape end end def keyPressed if (key == ' ') save_frame("bezPatch.png") build end end def build @outp = [] @normp = [] @inp = [] uitang = PVector.new ujtang = PVector.new (0 ... NI).each do |i| row = Array.new (0 ... NJ).each do |j| row << PVector.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 = PVector.new uitang.set(0, 0, 0) ujtang.set(0, 0, 0) (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.add(PVector.new(-NI/2,-NJ/2,0)) vect.mult(100) row << vect.array() uitang.normalize ujtang.normalize row_n << uitang.cross(ujtang).array() 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 *= pow(mu, k.to_f) if (k > 0) blend *= pow(1-mu, (n - k).to_f) if (n - k > 0) return(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 = pow(mu, k.to_f) dk = k * pow(mu, (k - 1).to_f) end if (n - k > 0) fnk = pow(1 - mu, (n - k).to_f) dnk = (k - n)*pow(1 - mu, (n - k - 1).to_f) end dblendf *= (dk * fnk + fk * dnk) return(dblendf) end
Labels:
bezier,
ruby-processing
Monday, 24 December 2012
Rotating Arcs Sketch in Ruby Processing
Here is vanilla sketch that wasn't easy to translate to ruby, the more hacks there are, the harder it is to translate. However conversely it should make me a bit bit more sensitive to the same issue in reverse. The original sketch featured sincos look up tables which are a dubious benefit in java, especially when not optimised. It also featured a nasty ++ increment hack. The original sketch had quite lot of casting to int, I found there no casting required in ruby-processing, just a nifty built in deg to radian conversion using a patched Numeric class.
# # Geometry # by Marius Watz. # load_library 'pdf' include_package 'processing.pdf' attr_reader :num, :pt, :style, :dosave def setup size(1024, 768, P3D) background(255) @dosave = false @num = 150 @pt = [] @style = [] # Set up arc shapes index = 0 (0 ... num).each do |i| pt.push(rand(TWO_PI)) # Random X axis rotation pt.push(rand(TWO_PI)) # Random Y axis rotation pt.push(rand(60 .. 80)) # Short to quarter-circle arcs if (rand(100)>90) pt[pt.length - 1] = rand(8 .. 27) * 10 end pt.push(rand(2 .. 50) * 5) # Radius. Space them out nicely pt.push(rand(4 .. 32)) # Width of band if (rand(100) > 90) pt[pt.length - 1] = rand(40 .. 60) # Width of band end pt.push(rand(0.005 .. 0.0334))# Speed of rotation # get colors prob = rand(100) if (prob < 30) style[i*2] = color_blended(rand, 255,0,100, 255,0,0, 210) elsif(prob < 70) style[i*2] = color_blended(rand, 0,153,255, 170,225,255, 210) elsif(prob<90) style[i*2] = color_blended(rand, 200,255,0, 150,255,0, 210) else style[i*2] = color(255,255,255, 220) end if (prob < 50) style[i*2] = color_blended(rand, 200,255,0, 50,120,0, 210) elsif(prob < 90) style[i*2] = color_blended(rand, 255,100,0, 255,255,0, 210) else style[i*2] = color(255, 255, 255, 220) style[i*2+1] = rand(100) % 3 end end end def draw if(dosave) # set up PGraphicsPDF for use with beginRaw pdf = begin_raw(PDF, "pdf_complex_out.pdf") # set default Illustrator stroke styles and paint background rect. pdf.stroke_join(MITER) pdf.stroke_cap(SQUARE) pdf.fill(0) pdf.no_stroke pdf.rect(0,0, width,height) end background(0) index = 0 translate(width/2, height/2, 0) rotate_x(PI/6) rotate_y(PI/6) (0 ... num).each do |i| push_matrix rotate_x(pt[index]) rotate_y(pt[index + 1]) index += 2 if (style[i*2+1] == 0) stroke(style[i*2]) no_fill stroke_weight(1) arc_line(0,0, pt[index],pt[index + 1],pt[index + 2]) index += 3 elsif (style[i*2+1] == 1) fill(style[i*2]) no_stroke arc_line_bars(0,0, pt[index],pt[index + 1],pt[index + 2]) index += 3 else fill(style[i*2]) no_stroke arc(0,0, pt[index],pt[index + 1],pt[index + 2]) index += 3 end # increase rotation pt[index-5] += pt[index] / 10 pt[index-4] += pt[index] / 20 index += 1 pop_matrix end if (dosave) end_raw @dosave=false end end # Get blend of two colors def color_blended(fract, r, g, b, r2, g2, b2, a) r2 = (r2 - r) g2 = (g2 - g) b2 = (b2 - b) return color(r + r2 * fract, g + g2 * fract, b + b2 * fract, a) end # Draw arc line def arc_line(x, y, deg, rad, w) a=(deg < 360)? deg : 0 numlines = w/2 (0 ... numlines).each do begin_shape (0 ... a).each do |i| vertex(cos(i.radians)*rad+x,sin(i.radians)*rad+y) end end_shape rad += 2 end end # Draw arc line with bars def arc_line_bars(x, y, deg, rad, w) a=(deg < 360)? deg / 4 : 0 begin_shape(QUADS) (0 ... a).step(4) do |i| vertex(cos(i.radians)*(rad)+x,sin(i.radians)*(rad)+y) vertex(cos(i.radians)*(rad+w)+x,sin(i.radians)*(rad+w)+y) vertex(cos((i + 2).radians)*(rad+w)+x,sin((i + 2).radians)*(rad+w)+y) vertex(cos((i + 2).radians)*(rad)+x,sin((i + 2).radians)*(rad)+y) end end_shape end # Draw solid arc def arc(x,y,deg,rad,w) a = (deg < 360)? deg : 0 begin_shape(QUAD_STRIP) (0 ... a).each do |i| vertex(cos(i.radians)*(rad)+x,sin(i.radians)*(rad)+y) vertex(cos(i.radians)*(rad+w)+x,sin(i.radians)*(rad+w)+y) end end_shape end def mouse_pressed @dosave = true end
# # Geometry # by Marius Watz. # load_library 'pdf' include_package 'processing.pdf' attr_reader :num, :pt, :style, :dosave def setup size(1024, 768, P3D) background(255) @dosave = false @num = 150 @pt = [] @style = [] # Set up arc shapes index = 0 (0 ... num).each do |i| pt.push(rand(TWO_PI)) # Random X axis rotation pt.push(rand(TWO_PI)) # Random Y axis rotation pt.push(rand(60 .. 80)) # Short to quarter-circle arcs if (rand(100)>90) pt[pt.length - 1] = rand(8 .. 27) * 10 end pt.push(rand(2 .. 50) * 5) # Radius. Space them out nicely pt.push(rand(4 .. 32)) # Width of band if (rand(100) > 90) pt[pt.length - 1] = rand(40 .. 60) # Width of band end pt.push(radians(rand(5 .. 30)) / 5 )# Speed of rotation # get colors prob = rand(100) if (prob < 30) style[i*2] = color_blended(rand, 255,0,100, 255,0,0, 210) elsif(prob < 70) style[i*2] = color_blended(rand, 0,153,255, 170,225,255, 210) elsif(prob<90) style[i*2] = color_blended(rand, 200,255,0, 150,255,0, 210) else style[i*2] = color(255,255,255, 220) end if (prob < 50) style[i*2] = color_blended(rand, 200,255,0, 50,120,0, 210) elsif(prob < 90) style[i*2] = color_blended(rand, 255,100,0, 255,255,0, 210) else style[i*2] = color(255, 255, 255, 220) style[i*2+1] = rand(100).to_i % 3 end end end def draw if(dosave) # set up PGraphicsPDF for use with beginRaw pdf = begin_raw(PDF, "pdf_complex_out.pdf") # set default Illustrator stroke styles and paint background rect. pdf.stroke_join(MITER) pdf.stroke_cap(SQUARE) pdf.fill(0) pdf.no_stroke pdf.rect(0,0, width,height) end background(0) index = 0 translate(width/2, height/2, 0) rotate_x(PI/6) rotate_y(PI/6) (0 ... num).each do |i| push_matrix rotate_x(pt[index]) rotate_y(pt[index + 1]) index += 2 if (style[i*2+1] == 0) stroke(style[i*2]) no_fill stroke_weight(1) arc_line(0,0, pt[index],pt[index + 1],pt[index + 2]) index += 3 elsif (style[i*2+1] == 1) fill(style[i*2]) no_stroke arc_line_bars(0,0, pt[index],pt[index + 1],pt[index + 2]) index += 3 else fill(style[i*2]) no_stroke arc(0,0, pt[index],pt[index + 1],pt[index + 2]) index += 3 end # increase rotation pt[index-5] += pt[index] / 10 pt[index-4] += pt[index] / 20 index += 1 pop_matrix end if (dosave) end_raw @dosave=false end end # Get blend of two colors def color_blended(fract, r, g, b, r2, g2, b2, a) r2 = (r2 - r) g2 = (g2 - g) b2 = (b2 - b) return color(r + r2 * fract, g + g2 * fract, b + b2 * fract, a) end # Draw arc line def arc_line(x, y, deg, rad, w) a=(deg < 360)? deg : 0 numlines = w/2 (0 ... numlines).each do begin_shape (0 ... a).each do |i| vertex(cos(radians(i))*rad+x,sin(radians(i))*rad+y) end end_shape rad += 2 end end # Draw arc line with bars def arc_line_bars(x, y, deg, rad, w) a=(deg < 360)? deg / 4 : 0 begin_shape(QUADS) (0 ... a).step(4) do |i| vertex(cos(radians(i))*(rad)+x,sin(radians(i))*(rad)+y) vertex(cos(radians(i))*(rad+w)+x,sin(radians(i))*(rad+w)+y) vertex(cos(radians(i + 2))*(rad+w)+x,sin(radians(i + 2))*(rad+w)+y) vertex(cos(radians(i + 2))*(rad)+x,sin(radians(i + 2))*(rad)+y) end end_shape end # Draw solid arc def arc(x,y,deg,rad,w) a = (deg < 360)? deg : 0 begin_shape(QUAD_STRIP) (0 ... a).each do |i| vertex(cos(radians(i))*(rad)+x,sin(radians(i))*(rad)+y) vertex(cos(radians(i))*(rad+w)+x,sin(radians(i))*(rad+w)+y) end end_shape end def mouse_pressed @dosave = true end
Labels:
complex 3D,
Marius Watz,
rotating arcs,
ruby processing
Friday, 21 December 2012
Context free sketch in regular ruby processing
Sometimes it is not necessary to use the ruby-cf3 library. I was contemplating adding parametrized shape to cf3ruby, so I thought I would try a simple context free art sketch to experiment with. Turn out this pretty easy to implement in regular ruby-processing (now using ruby-1.9 syntax for random range):-
# Grapher is based on a context free art design # by ColorMeImpressed (takes a bit of time to run) # http://www.contextfreeart.org/gallery/view.php?id=2844 # CMIN = -2.0 # Important to specify float else get random int from range? CMAX = 2.0 FUZZ = 0.04 SZ = 5 def setup size 600, 600 no_stroke color_mode(HSB, 1.0) background(0) frame_rate(4000) end def draw translate(width/2, height/2) dot(rand(-PI .. PI), rand(-PI .. PI), rand(CMIN .. CMAX)) unless frame_count > 200000 end def dot(px, py, c) func = sin(px) + sin(py) + c # change function to change the graph eg. #func = sin(px) + tan(py) + c #func = cos(px) + sin(py) + c if abs(func) <= FUZZ fill(((CMIN - c) / (CMIN - CMAX)), 1, 1) ellipse px * width / TWO_PI, py * height / TWO_PI, SZ, SZ else dot(rand(-PI .. PI), rand(-PI .. PI), rand(CMIN .. CMAX)) end end
Labels:
context free art,
equations,
graph,
ruby-processing
Wednesday, 19 December 2012
Exporting cf3ruby directly to 'large' pdf
With the processing pdf export library it is easy to export processing sketches to pdf. This is also true for ruby-processing sketches, including those using the cf3ruby library see example below:-
# levy.rb ruby-processing NB: :alpha is now implemented ruby-processing require 'cf3', 'pdf' include_package 'processing.pdf' def setup_the_levy @levy = ContextFree.define do shape :start do levy brightness: 0.9 end shape :levy do square alpha: 0.1 split do levy size: 1/Math.sqrt(2), rotation: -45, x: 0.5, brightness: 0.9 rewind levy size: 1/Math.sqrt(2), rotation: 45, x: 0.5, brightness: 0.9 end end end end def setup size 2000, 2000, PDF, "levy.pdf" setup_the_levy smooth draw_it end def draw exit end def draw_it background 255 @levy.render :start, size: 250, stop_size: 2, start_x: width/4, start_y: height/2 end
Labels:
cf3,
context free DSL,
pdf,
ruby processing
Tuesday, 18 December 2012
Context Free Tree in cf3ruby
################################################################# # A non deterministic sketch run it until you get a result you like # uncomment "srand 5" to get a more deterministic result. It looked # pretty good on my linux box (however I'm not sure how universal the # random seeding is in jruby) ################################################################# require 'cf3' def setup_the_tree @tree = ContextFree.define do shape :trunk, 20 do # rule has a probability weighting of 20 circle size: 0.25, brightness: 0.5 # giving an actual probability = 0.952381 scraggle y: -0.1 # the minus is require by the upside down coordinate system end shape :trunk, 1 do # rule has a probability weighting of 1 branch size: 0.7 # giving an actual probability = 0.047619 end shape :trunk, 0.02 do # empty rule top stop early end shape :branch do split do # split is like a branch, rewind returns original context trunk rotation: 10 rewind trunk rotation: -10 end end shape :scraggle do # without an explicit weighting trunk rotation: 5 # probability of each scraggle rule end # is 0.5 shape :scraggle do trunk rotation: -5 end end end def setup size 600, 600 srand 5 smooth setup_the_tree background 255 # NB color mode here is "RGB 255", within context free definition draw_it # the color mode is "HSB 1.0", supports :hue, :saturation, :brightness save_frame "/home/tux/tree4.png" end def draw_it @tree.render :trunk, start_x: width/2, start_y: height * 0.9, stop_size: height/150, size: height/15 end
Labels:
context free DSL,
ruby-cf3,
ruby-processing,
tree
New context_free.rb (cf3ruby)
Here is my "y" window sketch using my modified ruby-processing library (features CF3 syntax, ie shape replaces rule, also ruby 1.9 hash syntax).
# y.rb ruby-processing require 'cf3' Y_TOP = -1 / Math.sqrt(3) Y_BOT = Math.sqrt(3) / 6 def setup_the_triangle @triangle = ContextFree.define do ######## shape :start do unit brightness: 1.0 end shape :unit do triangle size: 1.0 split do unit size: 0.5, x: 0, y: Y_TOP/2, brightness: 0.8 rewind unit size: 0.5, x: -0.25, y: -Y_TOP/4, brightness: 0.8 rewind unit size: 0.5, x: 0.25, y: -Y_TOP/4, brightness: 0.8 end end ######## end end def setup size 1024, 1024 setup_the_triangle no_stroke color_mode RGB, 1 smooth draw_it save_frame("y.png") end def draw # Do nothing. end def draw_it background 225, 225, 0 @triangle.render :start, size: height, stop_size: 0.5, start_x: width/2, start_y: height * 0.6 end
Labels:
cf3,
context free DSL,
ruby-1.9,
ruby-processing
Subscribe to:
Posts (Atom)
Followers
About Me
- monkstone
- I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2



