From b6cf243ecbebe95c1508d98a925d73b1c42b00e5 Mon Sep 17 00:00:00 2001 From: ojack Date: Sat, 2 Dec 2023 14:51:44 -0500 Subject: [PATCH] added custom glsl stuff --- .../learning/extending-hydra/custom-glsl.md | 0 content/docs/learning/extending-hydra/glsl.md | 142 +++++++++++++++--- 2 files changed, 121 insertions(+), 21 deletions(-) delete mode 100644 content/docs/learning/extending-hydra/custom-glsl.md diff --git a/content/docs/learning/extending-hydra/custom-glsl.md b/content/docs/learning/extending-hydra/custom-glsl.md deleted file mode 100644 index e69de29..0000000 diff --git a/content/docs/learning/extending-hydra/glsl.md b/content/docs/learning/extending-hydra/glsl.md index 988efaa..e85cf62 100644 --- a/content/docs/learning/extending-hydra/glsl.md +++ b/content/docs/learning/extending-hydra/glsl.md @@ -8,38 +8,138 @@ title: Custom GLSL ## Using custom GLSL functions -Hydra is built using GLSL (a language for generating a program, or shader, that runs directly on the graphics card using WebGl). Each javascript function in hydra corresponds directly to a snippet of shader code. Hydra has a unique way of adding custom source and transform functions which we will explain here. +Hydra is built using GLSL (a language for generating a program, or shader, that runs directly on the graphics card using WebGl). Each javascript function in hydra corresponds directly to a snippet of shader code. There are four possible types in hydra: src, coord (geometry), combine (blend), combineCoord (modulate). Each string of functions is composited based on its type into a single string of fragment shader code. -### setFunction + You can see the glsl for each existing hydra function in [glsl-functions.js](https://github.com/hydra-synth/hydra-synth/blob/main/src/glsl/glsl-functions.js) of the hydra source code. -The Hydra API includes a function called `setFunction` which receives a specific type of JavaScript object. This object will have the properties `name`, `type`, `inputs` and `glsl`. + You can see the fragment shader code generated by a chain of functions in hydra, by replacing the `.out()` in a function chain with `.glsl()`, and then logging the results. + + For example, `console.log(osc().glsl()[0])` will show the fragment shader generates by `osc()` in the browser console. + + +## setFunction + +The hydra-synth API includes a function called `setFunction` which lets you dynamically add a function with custom GLSL and custom name, and use it elsewhere in the code. * `name` is a String with the name for the function -* `type` is one of the available types of functions ('src', 'color', 'coord', 'combine', 'combineCoord') -* `inputs` is an Array of objects each with it's own `name`, `type` and `default` properties. They represent the arguments of the GLSL function. +* `type` is one of the available types of functions ('src', 'color', 'coord', 'combine', 'combineCoord', esplained below) +* `inputs` is an Array of objects each with it's own `name`, `type` and `default` properties. These become the arguments of the generated GLSL function. * `glsl` is a String with the glsl code. -#### Example - +### Example +For example, the following code: ```javascript setFunction({ - name: 'myOsc', - type: 'src', - inputs: [ - { name: 'freq', type: 'float', default: 20 } - ], - glsl: ` - return vec4(sin((_st.x+time)*freq*vec3(0.1)),1.0); - ` + name: 'gradient2', + type: 'src', + inputs: [ + { + type: 'float', + name: 'speed', + default: 0, + } + ], + glsl: +` return vec4(sin(time*speed), _st, 1.0);` }) ``` +will generate the glsl function: + +```C +vec4 gradient2(vec2 _st, float speed){ + return vec4(sin(time*speed), _st, 1.0);; +} +``` -### Types of GLSL functions and their arguments +that is then usable in hydra using `gradient2().out()` -#### src +full example: +```hydra +setFunction({ + name: 'gradient2', + type: 'src', + inputs: [ + { + type: 'float', + name: 'speed', + default: 0, + } + ], + glsl: +` return vec4(sin(time*speed), _st, 1.0);` +}) +// +gradient2(1).out() +``` + +## Types of GLSL functions and their arguments +Types and default arguments for hydra functions. +The value in the 'type' field lets the parser know which type of function will be returned as well as default arguments. + + +```javascript +const types = { + 'src': { + returnType: 'vec4', + args: ['vec2 _st'] + }, + 'coord': { // geometry + returnType: 'vec2', + args: ['vec2 _st'] + }, + 'color': { + returnType: 'vec4', + args: ['vec4 _c0'] + }, + 'combine': { // blending + returnType: 'vec4', + args: ['vec4 _c0', 'vec4 _c1'] + }, + 'combineCoord': { // modulation + returnType: 'vec2', + args: ['vec2 _st', 'vec4 _c0'] + } +} + +``` + +### src A function with a specified type of `src` is one that generates visuals by its own. Just like `osc` or `noise`. They all have a `vec2` argument called `_st` for the coordinate. And you can add any custom inputs as shown above. You must return a `vec4`. -#### color +```hydra +setFunction({ + name: 'myOsc', + type: 'src', + inputs: [ + { + type: 'float', + name: 'frequency', + default: 60, + }, +{ + type: 'float', + name: 'sync', + default: 0.1, + }, +{ + type: 'float', + name: 'offset', + default: 0, + } + ], + glsl: +` vec2 st = _st; + float r = sin((st.x-offset/frequency+time*sync)*frequency)*0.5 + 0.5; + float g = sin((-st.x+time*sync*2.)*frequency)*0.5 + 0.5; + float b = sin((st.x+offset/frequency+time*sync)*frequency)*0.5 + 0.5; + return vec4(r, g, b, 1.0);` +}) + +myOsc(10).out() +``` + + +### color A `color` function receives a `vec4` called `_c0` that represents the color being affected by the transform. As any function you may add any extra inputs. You must return another `vec4`. @@ -56,7 +156,7 @@ osc(60,.1,5).switchColors() .out() ``` -#### coord +### coord A `coord` function receives a `vec2` called `_st` that represents the coordinate plane. You must return another `vec2`. @@ -76,7 +176,7 @@ osc(60,.1,5).tan(2) .out() ``` -#### combine +### combine The functions of type `combine` receive 2 `vec4` arguments, `_c0` and `_c1`. The first one represents the texture being affected and the latter represents the texture being blended into the former. For example, when you use `osc().mult(noise())`, inside the definition of the function, `_c0` represents the `osc()` and `_c1` represents the `noise()` colors. You can think combine functions as blending modes. And as custom function you may add extra inputs as needed. You must return a `vec4`. @@ -96,7 +196,7 @@ osc().negate(noise().brightness(.5)) .out() ``` -#### combineCoord +### combineCoord `combineCoord` functions change the position of colors in the texture being affected given the colors of another texture. Think about the many modulate functions for example, since they are precisely this type. They receive a `vec2 _st` and a `vec4 _c0`. You must return a `vec2`.