      :radius [:float radius]
      :innerradius [:float inner-radius]
      :phimax [:float phi]})))
+
+(defn ply-mesh
+  [scene id & {:keys [mesh path tx material smooth]}]
+  (append
+   scene :geometry id
+   (merge
+    (when tx (transform-common scene tx))
+    {:__type :plymesh
+     :__material material
+     :__mesh mesh
+     :name [:string id]
+     :filename [:string (or path (str id ".ply"))]
+     :smooth [:bool smooth]})))
+
+(defn stl-mesh
+  [scene id & {:keys [mesh path tx material]}]
+  (append
+   scene :geometry id
+   (merge
+    (when tx (transform-common scene tx))
+    {:__type :stlmesh
+     :__material material
+     :__mesh mesh
+     :name [:string id]
+     :filename [:string (or path (str id ".stl"))]})))
 
 (defn lux-scene
   []

   "\n"))

(defmethod luxvalue :trimesh
  [_ id mesh]
  (let [verts (vec (keys (:vertices mesh)))
        vidx (zipmap verts (range))
        indices (mapcat (fn [[a b c]] [(vidx a) (vidx b) (vidx c)]) (:faces mesh))]
    (luxentity
     "Shape" "trianglemesh"
     {:indices [:int-vec (vec indices)]
      :P [:point-vec verts]
      :name [:string id]})))

(defmethod luxvalue :shape
  [_ id opts]
  (luxattrib
   id
   (str
    (when-let [tx (:__transform opts)] (luxtransform tx))
    (when-let [mat (:__material opts)] (material-ref mat))
    (luxentity "Shape" (:__type opts) opts))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; serialization

      (when tx (transform-common scene tx))
      (light-common scene opts)
      {:__type :area-light
       :__shape [(mesh-types mesh-type) {:__mesh mesh :__basename (str "light-" id)}]
       :nsamples [:int samples]}))))

(defn shape-disk
