- vecmath, as direct replacement for PVector and incorporation arcball functionality (uses jafama under hood)
- 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.
No comments:
Post a Comment