Wireframe Extrusion

webgl3dwireframe

The humble cone contains the answers to fundamental questions about the universe. But not _this_ one, its just pixels on the screen. What is mildly interesting about this cone is the way it is generated - a 2D polyline forms the bottom side and hypotenuse of a right-handed triangle in the X-Y plane. This flat shape is then "extruded" into three dimensions by rotating around the Y axis to generate the cone. Another shape which is generated by rotation and scaling extrusions in multiple dimensions can be seen here: https://github.com/rm-hull/wireframes/blob/master/doc/gallery/weird-swirly-thing.stl

18 Feb 2015 by rm-hull
rm-hull/178513f8d2b6ecf501e4
wireframe-extrusion.cljs
(ns enchilada.wireframe-extrusion
  (:require
    [enchilada :refer [canvas ctx value-of canvas-size]]
    [wireframes.renderer.canvas :refer [draw-solid ->canvas]]
    [wireframes.renderer.color :refer [wireframe solid]]
    [wireframes.transform :refer [point combine rotate scale translate degrees->radians]]
    [wireframes.shapes.primitives :refer [extrude make-line make-point transform-shape center-at-origin]]
    [jayq.core :refer [show]]
    [inkspot.color :refer [coerce]]
    [monet.canvas :refer [get-context fill-rect fill-style]]
    [big-bang.core :refer [big-bang]]))

(def root2 (Math/sqrt 2))
(def Π Math/PI)
(def sin Math/sin)
(def cos Math/cos)

(def intervals->radians
 (let [atan8 (* (Math/atan 1.0) 8.0)]
   (fn [num-intervals] (/ atan8 (double num-intervals)))))

(defn polyline-2d [& points]
  (apply make-line (map (fn [[x y]] (make-point x y 0)) points)))

(defn make-cone [n]
  (extrude
    (polyline-2d
      [0.0 0.0]
      [1.0 0.0]
      [2.0 0.0]
      [3.0 0.0]
      [4.0 0.0]
      [5.0 0.0]
      [4.5 1.0]
      [4.0 2.0]
      [3.5 3.0]
      [3.0 4.0]
      [2.5 5.0]
      [2.0 6.0]
      [1.5 7.0]
      [1.0 8.0]
      [0.5 9.0]
      [0.0 10])
    (rotate :y (intervals->radians n))
    n))

(def rect
  (let [[width height] (canvas-size)]
    {:x 0 :y 0 :w  width :h height}))

(def dimensions
  (mapv rect [:w :h]))

(defn inflate [shape multiplier]
  ((transform-shape (scale multiplier)) shape))

(def divisions
  (js/parseInt (value-of :divisions 40)))

(def alpha
  (js/parseFloat (value-of :alpha 1)))

(def shape
  (->
    (make-cone divisions)
    (center-at-origin)
    (inflate (js/parseFloat (value-of :scale 0.25)))))

(def style
  (keyword (value-of :style :transparent)))

(def color
  (coerce (value-of :color :white)))

(def color-fn
  (condp = style
    :transparent (wireframe color style)
    :translucent (wireframe color style)
    :opaque (wireframe color style)
    :shaded (solid color)))

(defn render-shape
  "Draws the shape at the given state of the world (the x,y,z rotation angles)"
  [[x y z]]
  (-> ctx
    (fill-style "rgba(255,255,255,0.75")
    (fill-rect rect))
  ((->canvas ctx)
    (partial draw-solid
      {:style style
       :focal-length 3
       :color-fn color-fn
       :shape shape
       :transform (combine
                    (rotate :x (degrees->radians x))
                    (rotate :y (degrees->radians y))
                    (rotate :z (degrees->radians z))
                    (translate 0 0 10))})
    dimensions))

(defn update-state
  "Increment/decrement the rotation angles around the x,y and z axes"
  [event [x y z]]
  [(+ x 0.3) (- y 0.7) (+ z 0.5)])

(->
  ctx
  (fill-style :white)
  (fill-rect rect))

(show canvas)

(big-bang
  :initial-state [0 0 0]
  :on-tick update-state
  :to-draw render-shape)