|
| 1 | +# ===== Default : Default |
| 2 | +GEM_HOME = '/home/tux/.gem/ruby/2.6.0' |
| 3 | +require 'vecmath' |
| 4 | + |
| 5 | +color_mode(RGB, 1) |
| 6 | + |
| 7 | +def draw |
| 8 | + background(0) |
| 9 | + @renderer ||= GfxRender.new(graphics) |
| 10 | + # Move the origin so that the scene is centered on the screen. |
| 11 | + translate(width / 2, height / 2, 0.0) |
| 12 | + # Set up the lighting. |
| 13 | + setup_lights |
| 14 | + # Rotate the local coordinate system. |
| 15 | + smooth_rotation(5.0, 6.7, 7.3) |
| 16 | + # Draw the inner object. |
| 17 | + no_stroke |
| 18 | + fill(smooth_colour(10.0, 12.0, 7.0)) |
| 19 | + draw_icosahedron(5, 60.0, false) |
| 20 | + # Rotate the local coordinate system again. |
| 21 | + smooth_rotation(4.5, 3.7, 7.3) |
| 22 | + # Draw the outer object. |
| 23 | + stroke(0.2) |
| 24 | + fill(smooth_colour(6.0, 9.2, 0.7)) |
| 25 | + draw_icosahedron(5, 200.0, true) |
| 26 | +end |
| 27 | + |
| 28 | +def setup_lights |
| 29 | + ambient_light(0.025, 0.025, 0.025) |
| 30 | + directional_light(0.2, 0.2, 0.2, -1, -1, -1) |
| 31 | + spot_light(1.0, 1.0, 1.0, -200, 0, 300, 1, 0, -1, PI / 4, 20) |
| 32 | +end |
| 33 | + |
| 34 | +# Generate a vector whose components change smoothly over time in the range |
| 35 | +# (0..1). Each component uses a Math.sin function to map the current time in |
| 36 | +# milliseconds in the range (0..1).A 'speed' factor is specified for each |
| 37 | +# component. |
| 38 | +def smooth_vector(s1, s2, s3) |
| 39 | + mills = millis * 0.00003 ## Lazydogs factor |
| 40 | + # mills = millis * 0.0000001 ## worked for me a bit slower!! |
| 41 | + x = 0.5 * sin(mills * s1) + 0.5 |
| 42 | + y = 0.5 * sin(mills * s2) + 0.5 |
| 43 | + z = 0.5 * sin(mills * s3) + 0.5 |
| 44 | + Vec3D.new(x, y, z) |
| 45 | +end |
| 46 | + |
| 47 | +# Generate a colour which smoothly changes over time. |
| 48 | +# The speed of each component is controlled by the parameters s1, s2 and s3. |
| 49 | +def smooth_colour(s1, s2, s3) |
| 50 | + v = smooth_vector(s1, s2, s3) |
| 51 | + color(v.x, v.y, v.z) |
| 52 | +end |
| 53 | + |
| 54 | +# Rotate the current coordinate system. |
| 55 | +# Uses smooth_vector to smoothly animate the rotation. |
| 56 | +def smooth_rotation(s1, s2, s3) |
| 57 | + r1 = smooth_vector(s1, s2, s3) |
| 58 | + rotate_x(2.0 * Math::PI * r1.x) |
| 59 | + rotate_y(2.0 * Math::PI * r1.y) |
| 60 | + rotate_x(2.0 * Math::PI * r1.z) |
| 61 | +end |
| 62 | + |
| 63 | +# Draw an icosahedron defined by a radius r and recursive depth d. |
| 64 | +# Geometry data will be saved into dst. If spherical is true then the |
| 65 | +# icosahedron is projected onto the sphere with radius r. |
| 66 | +def draw_icosahedron(depth, r, spherical) |
| 67 | + # Calculate the vertex data for an icosahedron inscribed by a sphere radius |
| 68 | + # 'r'. Use 4 Golden Ratio rectangles as the basis. |
| 69 | + gr = (1.0 + Math.sqrt(5.0)) / 2.0 |
| 70 | + h = r / Math.sqrt(1.0 + gr * gr) |
| 71 | + v = [ |
| 72 | + Vec3D.new(0, -h, h * gr), |
| 73 | + Vec3D.new(0, -h, -h * gr), |
| 74 | + Vec3D.new(0, h, -h * gr), |
| 75 | + Vec3D.new(0, h, h * gr), |
| 76 | + Vec3D.new(h, -h * gr, 0), |
| 77 | + Vec3D.new(h, h * gr, 0), |
| 78 | + Vec3D.new(-h, h * gr, 0), |
| 79 | + Vec3D.new(-h, -h * gr, 0), |
| 80 | + Vec3D.new(-h * gr, 0, h), |
| 81 | + Vec3D.new(-h * gr, 0, -h), |
| 82 | + Vec3D.new(h * gr, 0, -h), |
| 83 | + Vec3D.new(h * gr, 0, h) |
| 84 | + ] |
| 85 | + # Draw the 20 triangular faces of the icosahedron. |
| 86 | + r = 0.0 unless spherical |
| 87 | + begin_shape(TRIANGLES) |
| 88 | + draw_triangle(depth, r, v[0], v[7], v[4]) |
| 89 | + draw_triangle(depth, r, v[0], v[4], v[11]) |
| 90 | + draw_triangle(depth, r, v[0], v[11], v[3]) |
| 91 | + draw_triangle(depth, r, v[0], v[3], v[8]) |
| 92 | + draw_triangle(depth, r, v[0], v[8], v[7]) |
| 93 | + draw_triangle(depth, r, v[1], v[4], v[7]) |
| 94 | + draw_triangle(depth, r, v[1], v[10], v[4]) |
| 95 | + draw_triangle(depth, r, v[10], v[11], v[4]) |
| 96 | + draw_triangle(depth, r, v[11], v[5], v[10]) |
| 97 | + draw_triangle(depth, r, v[5], v[3], v[11]) |
| 98 | + draw_triangle(depth, r, v[3], v[6], v[5]) |
| 99 | + draw_triangle(depth, r, v[6], v[8], v[3]) |
| 100 | + draw_triangle(depth, r, v[8], v[9], v[6]) |
| 101 | + draw_triangle(depth, r, v[9], v[7], v[8]) |
| 102 | + draw_triangle(depth, r, v[7], v[1], v[9]) |
| 103 | + draw_triangle(depth, r, v[2], v[1], v[9]) |
| 104 | + draw_triangle(depth, r, v[2], v[10], v[1]) |
| 105 | + draw_triangle(depth, r, v[2], v[5], v[10]) |
| 106 | + draw_triangle(depth, r, v[2], v[6], v[5]) |
| 107 | + draw_triangle(depth, r, v[2], v[9], v[6]) |
| 108 | + end_shape |
| 109 | +end |
| 110 | + |
| 111 | +## |
| 112 | +# Draw a triangle either immediately or subdivide it first. |
| 113 | +# If depth is 1 then draw the triangle otherwise subdivide first. |
| 114 | +# |
| 115 | +def draw_triangle(depth, r, p1, p2, p3) |
| 116 | + if depth == 1 |
| 117 | + p1.to_vertex(@renderer) |
| 118 | + p2.to_vertex(@renderer) |
| 119 | + p3.to_vertex(@renderer) |
| 120 | + else |
| 121 | + # Calculate the mid points of this triangle. |
| 122 | + v1 = (p1 + p2) * 0.5 |
| 123 | + v2 = (p2 + p3) * 0.5 |
| 124 | + v3 = (p3 + p1) * 0.5 |
| 125 | + unless r == 0.0 |
| 126 | + # Project the vertices out onto the sphere with radius r. |
| 127 | + v1.normalize! |
| 128 | + v1 *= r |
| 129 | + v2.normalize! |
| 130 | + v2 *= r |
| 131 | + v3.normalize! |
| 132 | + v3 *= r |
| 133 | + end |
| 134 | + ## Generate the next level of detail |
| 135 | + depth -= 1 |
| 136 | + draw_triangle(depth, r, p1, v1, v3) |
| 137 | + draw_triangle(depth, r, v1, p2, v2) |
| 138 | + draw_triangle(depth, r, v2, p3, v3) |
| 139 | + # Uncomment out the next line to include the central part of the triangle. |
| 140 | + # draw_triangle(depth, r, v1, v2, v3) |
| 141 | + end |
| 142 | +end |
0 commit comments