Skip to content

Instantly share code, notes, and snippets.

@ympbyc
Last active January 17, 2019 13:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ympbyc/0e83949bf1c5efd6c005709b0cdea2b8 to your computer and use it in GitHub Desktop.
Save ympbyc/0e83949bf1c5efd6c005709b0cdea2b8 to your computer and use it in GitHub Desktop.
Easily composable signed distance functions for CEPL. Mostly untested.
(defpackage :distance-fns
(:use :cl :cepl :rtg-math :vari)
(:nicknames :df))
(in-package :df)
(defun-g rand ((co :vec2))
(fract (* (sin (dot co (v! 12.98 78.23))) 43758.54)))
;; Signed Distance functions
(defun-g sdf-sphere ((p :vec3) (r :float))
(- (length p) r))
(defun-g sdf-box ((p :vec3) (b :vec3))
(let ((d (- (abs p) b)))
(+ (min (max (x d) (max (y d) (z d))) 0.0)
(length (max d 0.0)))))
(defun-g sdf-torus ((p :vec3) (r :vec2))
(let ((q (v! (- (length (swizzle p :xz)) (x r))
(y p))))
(- (length q) (y r))))
(defun-g sdf-cylinder ((p :vec3) (c :vec3))
(- (length (- (swizzle p :xz) (swizzle c :xy)))
(z c)))
(defun-g sdf-cone ((p :vec3) (c :vec2))
(let ((q (length (swizzle p :xy))))
(dot c (v! q (z p)))))
(defun-g sdf-plane ((p :vec3) (n :vec4))
(+ (dot p (swizzle n :xyz))
(w n)))
(defun-g sdf-hex-prism ((p :vec3) (h :vec2))
(let ((q (abs p)))
(max (- (z q) (y h))
(- (max (+ (* (x q) 0.866025)
(* (y q) 0.5))
(y q))
(x h)))))
(defun-g sdf-ellipsoid ((p :vec3) (r :vec3))
(* (- (length (/ p r)) 1.0)
(min (min (x r) (y r)) (z r))))
(defun-g sdf-U ((d1 :float) (d2 :float))
(min d1 d2))
(defun-g sdf-S ((d1 :float) (d2 :float))
(max (- d1) d2))
(defun-g sdf-I ((d1 :float) (d2 :float))
(max d1 d2))
(defun-g sdf-rep ((p :vec3) (c :vec3))
(let ((q (v! (mod (x p) (x c))
(mod (y p) (y c))
(mod (z p) (z c)))))
(- q (* c 0.5))))
(defun-g sdf-tx ((p :vec3) (m :mat4))
(let ((v (* (inverse m) (v! (x p) (y p) (z p) 1.0))))
(swizzle v :xyz)))
(defun-g sdf-displace ((dist1 :float) (dist2 :float))
(+ dist1 dist2))
(defun-g sdf-smin ((a :float) (b :float) (k :float))
(let ((h (max (- k (abs (- a b))) 0.0)))
(- (min a b)
(/ (* h h 0.25) k))))
(defun-g sdf-blend ((d1 :float) (d2 :float))
(sdf-smin d1 d2 0.6))
(defun-g sdf-bend ((p :vec3) (k :float))
(let* ((c (cos (* k (y p))))
(s (sin (* k (y p))))
(m (m! c (- s) s c))
(q (v! (* m (swizzle p :xy)) (z p))))
q))
;;API
(defmacro sdf-api (name &rest params)
(let ((f-n (intern (concatenate 'string "SDF-" (symbol-name name)))))
`(defmacro-g ,(intern (concatenate 'string (symbol-name name)))
,params
(let ((p (gensym)))
`(lambda ((,p :vec3))
(,',f-n
,p
,,@params))))))
(defmacro sdf-api* (name)
(let ((f-n (intern (concatenate 'string "SDF-" (symbol-name name)))))
`(defmacro-g ,(intern (concatenate 'string (symbol-name name)))
(df1 df2)
(let ((p (gensym)))
`(lambda ((,p :vec3))
(,',f-n
(funcall ,df1 ,p)
(funcall ,df2 ,p)))))))
(defmacro sdf-api** (name param)
(let ((f-n (intern (concatenate 'string "SDF-" (symbol-name name)))))
`(defmacro-g ,(intern (concatenate 'string (symbol-name name)))
(,param df)
(let ((p (gensym)))
`(lambda ((,p :vec3))
(funcall ,df
(,',f-n ,p ,,param)))))))
(export (sdf-api sphere r))
(export (sdf-api box size))
(export (sdf-api torus r))
(export (sdf-api cylinder c))
(export (sdf-api cone c))
(export (sdf-api plane n))
(export (sdf-api hex-prism h))
(export (sdf-api ellipsoid r))
(export (sdf-api* U))
(export (sdf-api* S))
(export (sdf-api* I))
(export (sdf-api* displace))
(export (sdf-api* blend))
(export (sdf-api** rep v))
(export (sdf-api** tx v))
(export (sdf-api** bend k))
(defmacro-g move (v df)
(let* ((sym (gensym)))
`(lambda ((,sym :vec3))
(let* ((m (m! 1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
(x ,v) (y ,v) (z ,v) 1.0))
(p (* (inverse m) (v! (x ,sym) (y ,sym) (z ,sym) 1.0))))
(funcall ,df (swizzle p :xyz))))))
(defmacro-g rotate-x (tt df)
(let* ((sym (gensym)))
`(lambda ((,sym :vec3))
(let* ((m (m! 1.0 0.0 0.0 0.0
0.0 (cos ,tt) (- (sin ,tt)) 0.0
0.0 (sin ,tt) (cos ,tt) 0.0
0.0 0.0 0.0 1.0))
(p (* (inverse m) (v! (x ,sym) (y ,sym) (z ,sym) 1.0))))
(funcall ,df (swizzle p :xyz))))))
(defmacro-g rotate-y (tt df)
(let* ((sym (gensym)))
`(lambda ((,sym :vec3))
(let* ((m (m! (cos ,tt) 0.0 (sin ,tt) 0.0
0.0 1.0 0.0 0.0
(- (sin ,tt)) 0.0 (cos ,tt) 0.0
0.0 0.0 0.0 1.0))
(p (* (inverse m) (v! (x ,sym) (y ,sym) (z ,sym) 1.0))))
(funcall ,df (swizzle p :xyz))))))
(defmacro-g rotate-z (tt df)
(let* ((sym (gensym)))
`(lambda ((,sym :vec3))
(let* ((m (m! (cos ,tt) (- (sin ,tt)) 0.0 0.0
(sin ,tt) (cos ,tt) 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0))
(p (* (inverse m) (v! (x ,sym) (y ,sym) (z ,sym) 1.0))))
(funcall ,df (swizzle p :xyz))))))
(export 'move)
(export 'rotate-x)
(export 'rotate-y)
(export 'rotate-z)
;;just compose it like you would in Libfive Studio
(df:blend (df:move (V! 1 0 0) (df:sphere 1))
(df:box 1 (v! 2 2 2))
;;-> gives you back a signed distance function (lambda (:vec3) :float) you can use with raymarcher
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment