Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/kfish/glsl-pasta
Combine GLSL shaders for use with Elm WebGL
https://github.com/kfish/glsl-pasta
elm glsl webgl
Last synced: 25 days ago
JSON representation
Combine GLSL shaders for use with Elm WebGL
- Host: GitHub
- URL: https://github.com/kfish/glsl-pasta
- Owner: kfish
- Created: 2017-07-22T04:53:30.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2017-07-24T22:44:44.000Z (over 7 years ago)
- Last Synced: 2024-10-15T15:12:09.039Z (2 months ago)
- Topics: elm, glsl, webgl
- Language: Elm
- Size: 76.2 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# glsl-pasta
This is a crude way of combining GLSL shaders for use with Elm
[webgl](http://package.elm-lang.org/packages/elm-community/elm-webgl/latest/WebGL).GLSLPasta allows you to extract common functionality from shaders into reusable Components,
then combine these to generate specific shaders.This package also includes a library of common routines for generating lighting shaders,
with or without normal and diffuse texture maps.Some terminology, then a quick example.
## Components
GLSLPasta components contain blocks of code which get pasted together to form a shader. These include:
* Globals: declarations of attributes, uniforms, varyings and const values
* Functions: the text of entire functions
* Splices: snippets of code that get spliced into main()Each component additionally specifies:
* Dependencies: a list of other Components which GLSLPasta will automatically include
* Provides: a list of Features, given as arbitrary Strings, which this component provides
* Requirements: a list of Features which this component needsYou combine a list of components together with a call to `GLSLPasta.combine`, which will automatically
pull in dependencies and will check that requirements are satisfied:```elm
combine : List Component -> String
```the output of which you can pass to `WebGL.unsafeShader`.
## Examples
Various lighting components are provided in the module `GLSLPasta.Lighting`. Some preliminary imports:
```elm
import GLSLPasta
import GLSLPasta.Lighting exposing (..)
import WebGL
```## Vertex Shader Example
You could construct a shader that interpolates between vertex normals using:
```elm
interpolateNormals =
GLSLPasta.combine [ vertex_gl_Position, vertexNoTangent ]
|> WebGL.unsafeShader
```or you could construct a similar shader that uses a texture to provide normals:
```elm
textureNormals =
GLSLPasta.combine [ vertex_gl_Position, vertex_vTexCoord, vertexNoTangent ]
|> WebGL.unsafeShader
```Alternatively you could construct a vertex shader that generates normals via a
Tangent, Bitangent, Normal (TBN) matrix:```elm
textureNormals =
GLSLPasta.combine [ vertex_gl_Position, vertex_vTexCoord, vertexTBN ]
|> WebGL.unsafeShader
```## Fragment Shader Examples
`GLSL.Lighting` provides components which implement variations of the Phong shading model, such as
`fragment_lambert`, `fragment_diffuse` and `fragment_specular`.You may have alternative ways of providing input to these. For example, `fragment_lambert` requires
a `pixelNormal`. If we are using any of the vertex shaders above, we could calculate these via
interpolation between vertices:```elm
[ fragment_interpolatedNormal, fragment_lambert ]
```However if we additionally have a normal texture map available, and we use one of the above shaders that
generates `vTexCoord`, we can modify this to:```elm
[ fragment_textureNormal, fragment_lambert ]
```which will include the extra globals:
```elm
, globals =
[ Uniform "sampler2D" "textureNorm"
, Varying "vec2" "vTexCoord"
]
```Similarly for diffuse maps, we could specify
```elm
[ fragment_textureDiffuse, fragment_diffuse ]
```for objects with diffuse maps, or
```elm
[ fragment_constantDiffuse, fragment_diffuse ]```
to generate a simple shader with constant `diffuseColor`.
## Error handling
Note that `fragment_diffuse` simply requires that some earlier Component has generated `diffuseColor`. What if
this requirement is not met?```elm
> import GLSLPasta exposing (..)
> import GLSLPasta.Lighting exposing (..)
> combine [ fragment_diffuse ]
Missing requirement diffuseColor, needed by lighting.fragment_diffuse: "<>"
""
: String
````GLSLPasta.combine` will log errors to the Javascript console, and return an empty String.
## Putting it all together
A complete Phong lighting shader generates `gl_FragColor` with `fragment_phong`, which requires
that earlier components have generated "ambient", "diffuse", "specular" and "attenuation".A complete shader that supports normal and diffuse maps looks like:
```elm
normalDiffuseTextures =
GLSLPasta.combine
[ fragment_textureNormal
, fragment_lambert
, fragment_textureDiffuse
, fragment_diffuse
, fragment_ambient_03
, fragment_specular
, fragment_attenuation
, fragment_phong
]
|> WebGL.unsafeShader
```whereas a simpler shader that interpolates normals and uses a constant diffuseColor looks like:
```elm
simplePhong =
GLSLPasta.combine
[ fragment_interpolatedNormal
, fragment_lambert
, fragment_constantDiffuse
, fragment_diffuse
, fragment_ambient_02
, fragment_specular
, fragment_attenuation
, fragment_phong
]
|> WebGL.unsafeShader
```## Implementation
You define a part of a shader with type `Component`:
```elm
type alias Component =
{ id : ComponentId -- used in error messages
, dependencies : Dependencies
, provides : List Feature
, requires : List Feature
, globals : List Global
, functions : List Function
, splices : List Splice
}
```Most of these fields are `String`s, apart from dependencies (which wraps a list of other `Component`s) and
`Global`s, which are:```elm
type Global
= Attribute Type Name
| Uniform Type Name
| Varying Type Name
| Const Type Name Value
```where, again, `Type`, `Name` and `Value` are just `String`s.
## How it works
Once all dependencies and requirements are resolved, GLSLPasta simply generates code for the globals
and fills in the functions and main() splices according to a template.
The default template is:```elm
defaultTemplate : String
defaultTemplate =
"""
precision mediump float__PASTA_GLOBALS__
__PASTA_FUNCTIONS__
void main()
{
__PASTA_SPLICES__
}"""
```Here, `__PASTA_GLOBALS__` is replaced with a all the globals from all the Components (with duplicates removed),
`__PASTA_FUNCTIONS__` is replaced with all the functions from all the Components,
and `__PASTA_SPLICES__` is replaced with all the splices from all the Components, in the order the list of Components.Note that the functions and splices are replaced as arbitrary strings, and glsl-pasta makes no
attempt to parse or sanity-check these.## Credits
The code in GLSLPasta.Lighting is extracted from @Zinggi's example code in
[elm-object-loader](https://github.com/Zinggi/elm-obj-loader/tree/master/examples).