SkillAgentSearch skills...

Shadergraph

WebGL/GLSL shader library & dependency framework for ClojureScript

Install / Use

/learn @thi-ng/Shadergraph
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

#+SETUPFILE: src/setup.org #+TITLE: thi.ng/shadergraph

  • Contents :toc_3_gh:
  • [[#about-the-project][About the project]]
    • [[#overview][Overview]]
    • [[#leiningen-coordinates][Leiningen coordinates]]
      • [[#latest-stable][Latest stable]]
      • [[#latest-snapshot][Latest snapshot]]
    • [[#status][Status]]
    • [[#usage-example][Usage example]]
    • [[#module-namespaces][Module namespaces]]
    • [[#tests][Tests]]
    • [[#building--testing-this-project][Building & testing this project]]
  • [[#project-definition][Project definition]]
    • [[#building--testing-this-project][Building & testing this project]]
      • [[#testing][Testing]]
      • [[#working-with-the-repl][Working with the REPL]]
    • [[#injected-properties][Injected properties]]
    • [[#dependencies][Dependencies]]
      • [[#runtime][Runtime]]
      • [[#development][Development]]
    • [[#leiningen-project-file][Leiningen project file]]
    • [[#clojurescript-html-harness][ClojureScript HTML harness]]
    • [[#accessing-library-version-during-runtime][Accessing library version during runtime]]
      • [[#version-namespace][Version namespace]]
    • [[#release-history][Release history]]
    • [[#contributors][Contributors]]
  • About the project ** Overview

This project provides a function-oriented approach to composing complex shaders. The library contains:

  • Dozens of pure GLSL functions, generally useful and often used in GLSL shaders for both OpenGL & WebGL projects (both Clojure & Clojurescript).
  • Automatic Clojure metadata generation for GLSL functions (incl. arg lists) to help with documentation in the REPL or for custom tool development.
  • A generic transitive dependency graph resolution mechanism for any shader functions defined (not just in this library).
  • An optional basic shader minifier (without name mangling)
  • GLSL source code can be specified as strings or read from files/resources

Several shader functions have been gathered from literature and other projects and been partially refactored as pure functions.

** Leiningen coordinates

#+BEGIN_SRC [thi.ng/shadergraph "0.3.1"] #+END_SRC

** Status

STABLE

** Usage example

The brief example below defines a shader pair with standard [[https://en.wikipedia.org/wiki/Lambertian_reflectance][Lambert lighting]]. The =defglsl= macro is used to define a GLSL sourcecode snippet with (optional) dependencies. It also minifies the original sources at compile time (all snippets provided by this library are minified this way).

#+BEGIN_SRC clojure (ns example (:require [thi.ng.glsl.core :as glsl :include-macros true] [thi.ng.glsl.vertex] [thi.ng.glsl.lighting]))

(glsl/defglsl my-vertex-shader [thi.ng.glsl.vertex/mvp thi.ng.glsl.vertex/surface-normal] "void main() { vNormal = surfaceNormal(normal, normalMat); gl_Position = mvp(position, model, view, proj); }")

(glsl/defglsl my-fragment-shader [thi.ng.glsl.lighting/lambert] "void main() { float lam = lambert(normalize(vNormal), normalize(lightDir)); gl_FragColor = vec4(ambientCol + diffuseCol * lightCol * lam, 1.0); }") #+END_SRC

Apart from the =defglsl= macro, the =assemble= function is the other main tool in this library. It takes a map of GLSL dependencies and sourcecode and returns a transformed/expanded source with all transitive deps injected in the correct order. The =my-vertex-shader= spec above in assembled form will expand to:

#+BEGIN_SRC clojure (glsl/assemble my-vertex-shader) ;; "vec3 surfaceNormal(vec3 normal,mat4 normalMat){return normalize((normalMatvec4(normal,.0)).xyz);}vec4 mvp(vec3 pos,mat4 model,mat4 view,mat4 proj){return projviewmodelvec4(pos,1.);}void main(){vNormal=surfaceNormal(normal,normalMat);gl_Position=mvp(position,model,view,proj);}" #+END_SRC

Using another library like, e.g. [[https://github.com/thi-ng/geom/][thi.ng/geom]] 's GL module, these shader sources can then be combined into a fully defined shader like this (the =make-shader-from-spec= function used below generates all attribute, varying & uniform definitions and setters automatically and returns a compiled shader program):

#+BEGIN_SRC clojure (require '[thi.ng.geom.gl.shaders :as shaders])

(def shader (shaders/make-shader-from-spec my-gl-context {:vs (glsl/assemble my-vertex-shader) :fs (glsl/assemble my-fragment-shader) :uniforms {:model :mat4 :view :mat4 :proj :mat4 :normalMat :mat4 :ambientCol :vec3 :diffuseCol :vec3 :lightCol :vec3 :lightDir :vec3} :attribs {:position :vec3 :normal :vec3} :varying {:vNormal :vec3}})) #+END_SRC

** Module namespaces

  • [[src/core.org][thi.ng.glsl.core]]
  • [[src/buffers.org][thi.ng.glsl.buffers]]
  • [[src/color.org][thi.ng.glsl.color]]
  • [[src/distancefields.org][thi.ng.glsl.distancefields]]
  • [[src/fog.org][thi.ng.glsl.fog]]
  • [[src/grid.org][thi.ng.glsl.grid]]
  • [[src/lighting.org][thi.ng.glsl.lighting]]
  • [[src/matrix.org][thi.ng.glsl.matrix]]
  • [[src/noise.org][thi.ng.glsl.noise]]
  • [[src/vertex.org][thi.ng.glsl.vertex]]

** Tests

  • [[test/core.org]] ** Building & testing this project
  • Project definition ** Building & testing this project

This project is written in a literate programming format and requires [[https://www.gnu.org/software/emacs/][Emacs]] & [[http://orgmode.org][Org-mode]] to generate usable source code. Assuming both tools are installed, the easiest way to generate a working project is via command line (make sure =emacs= is on your path or else edit its path in =tangle.sh=):

#+BEGIN_SRC bash git clone https://github.com/thi-ng/shadergraph.git cd shadergraph

tangle selected files

./tangle.sh README.org src/.org test/.org

...or individual file

./tangle.sh src/core.org #+END_SRC

Tangling is the process of extracting & combining source blocks from =.org= files into an actual working project/source tree.

Once tangling is complete, you can =cd= into the generated project directory (=babel= in this case) and then use =lein= as usual.

*** Testing

The =project.clj= file define an alias to trigger a complete build & tests for both CLJ & CLJS versions.

#+BEGIN_SRC bash cd babel lein cleantest # some tests currently fail due to still missing protocol impls #+END_SRC

To only build the Clojurescript version simply run =lein cljsbuild test= from the same directory. A small HTML harness for the resulting JS file is also located in that folder (=babel/index.html=), allowing for further experimentation in the browser.

*** Working with the REPL

Editing code blocks / files in Org-mode, then re-loading & testing changes is quite trivial. Simply launch a REPL (via lein or Emacs) as usual. Everytime you've made changes to an =.org= file, re-tangle it from Emacs or =tangle.sh=, then reload the namespace in the REPL via =(require 'thi.ng.glsl... :reload)= or similar.

** Injected properties :noexport:

#+BEGIN_SRC clojure :exports none :noweb-ref version 0.3.1 #+END_SRC

#+BEGIN_SRC clojure :exports none :noweb-ref project-url https://github.com/thi-ng/shadergraph #+END_SRC

#+BEGIN_SRC clojure :exports none :noweb-ref project-name thi.ng/shadergraph #+END_SRC

#+BEGIN_SRC clojure :exports none :noweb yes :noweb-ref cljs-artefact-path target/shadergraph-<<version>>.js #+END_SRC

** Dependencies *** Runtime **** [[https://github.com/clojure/clojure][Clojure]] #+BEGIN_SRC clojure :noweb-ref dep-clj [org.clojure/clojure "1.11.1"] #+END_SRC

**** [[https://github.com/clojure/clojurescript][ClojureScript]] #+BEGIN_SRC clojure :noweb-ref dep-cljs [org.clojure/clojurescript "1.11.4"] #+END_SRC

**** [[https://github.com/kibu-australia/dependency][Dependency graph]] #+BEGIN_SRC clojure :noweb-ref dep-dep [com.postspectacular/dependency "0.1.2"] #+END_SRC

*** Development **** [[https://github.com/cemerick/clojurescript.test][clojurescript.test]] #+BEGIN_SRC clojure :noweb-ref dep-cljs-test [com.cemerick/clojurescript.test "0.3.3"] #+END_SRC

**** [[https://github.com/emezeske/lein-cljsbuild][Cljsbuild]] #+BEGIN_SRC clojure :noweb-ref dep-cljsbuild [lein-cljsbuild "1.1.8"] #+END_SRC

** Leiningen project file :noexport:

#+BEGIN_SRC clojure :tangle babel/project.clj :noweb yes :mkdirp yes :padline no (defproject <<project-name>> "<<version>>" :description "WebGL/GLSL shader library & dependency graph for ClojureScript" :url "<<project-url>>" :license {:name "Apache Software License" :url "http://www.apache.org/licenses/LICENSE-2.0" :distribution :repo} :scm {:name "git" :url "<<project-url>>"}

:min-lein-version "2.4.0"

:dependencies [<<dep-clj>>
               <<dep-cljs>>
               <<dep-dep>>]

:profiles {:dev {:plugins [<<dep-cljsbuild>>
                           <<dep-cljs-test>>]
                 :aliases {"cleantest" ["do" "clean," "cljsbuild" "test"]}}}

:cljsbuild {:builds [{:source-paths ["src" "test"]
                      :id "simple"
                      :compiler {:output-to "<<cljs-artefact-path>>"
                                 :optimizations :whitespace
                                 :pretty-print true}}
                     {:source-paths ["src" "test"]
                      :id "prod"
                      :compiler {:output-to "<<cljs-artefact-path>>"
                                 :optimizations :advanced
                                 :pretty-print false}}]
            :test-commands {"unit-tests" ["phantomjs" :runner "<<cljs-artefact-path>>"]}}

:pom-addition [:developers [
View on GitHub
GitHub Stars63
CategoryDevelopment
Updated2mo ago
Forks4

Languages

Shell

Security Score

80/100

Audited on Jan 4, 2026

No findings