├── .gitignore ├── LICENSE ├── README.md ├── example ├── index.js ├── quad_frag.glsl ├── quad_vert.glsl ├── sphere_frag.glsl └── sphere_vert.glsl ├── images ├── f.png ├── g.png ├── h.png ├── j.png └── l.png ├── index.glsl └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | .idea/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This software is released under the MIT license: 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # glsl-cos-palette 2 | 3 | `cosPalette` is a simple shader function that is defined as 4 | 5 | ```glsl 6 | vec3 cosPalette( float t, vec3 a, vec3 b, vec3 c, vec3 d ){ 7 | return a + b*cos( 6.28318*(c*t+d) ); 8 | } 9 | ``` 10 | 11 | where `a,b,c,d` are RGB-colors. This function can be used to make very compact color palettes. 12 | A simple editor for making such palettes is provided [here](http://erkaman.github.io/glsl-cos-palette/). 13 | 14 | 15 | The function `cosPalette(t, a, b, c, d )`, which is the palette, will basically assign a color to every value `t`, which is in the range `[0,1]`. So if you set `t` to be the value of some noise function(say, Perlin noise) in range `[0,1]`, you can use this 16 | palette to make simple procedural textures. The palette will basically colorize the noise. In the fragment shader, we can easily procedurally generate a texture by doing something like 17 | 18 | ```glsl 19 | float t = noise(vPosition); 20 | vec3 tex = cosPalette(t, uAColor, uBColor, uCColor, uDColor ); 21 | ``` 22 | 23 | Credit goes to [Inigo Quilez](http://www.iquilezles.org/www/articles/palettes/palettes.htm) for coming up with this technique. 24 | 25 | If even more advanced palettes are desired, they can be created using [glsl-gradient-palette](https://github.com/Erkaman/glsl-gradient-palette) 26 | 27 | ## Examples 28 | 29 | Below are some examples of palettes 30 | 31 | `cosPalette(t,vec3(0.2,0.7,0.4),vec3(0.6,0.9,0.2),vec3(0.6,0.8,0.7),vec3(0.5,0.1,0.0))` 32 | 33 | 34 | 35 | 36 | 37 | `cosPalette(t,vec3(0.2,0.5,0.3),vec3(0.0,0.5,0.7),vec3(1.0,1.0,1.0),vec3(0.0,0.3,0.7))` 38 | 39 | 40 | 41 | 42 | `cosPalette(t,vec3(0.6,0.0,0.0),vec3(1.0,0.0,0.0),vec3(1.0,0.0,0.0),vec3(1.0,0.0,0.0))` 43 | 44 | 45 | 46 | 47 | `cosPalette(t,vec3(1.0,0.4,0.0),vec3(0.4,0.8,0.0),vec3(0.5,0.3,0.9),vec3(0.9,0.6,0.9))` 48 | 49 | 50 | 51 | 52 | `cosPalette(t,vec3(0.4,0.3,0.1),vec3(0.1,0.1,0.1),vec3(0.4,0.4,0.4),vec3(0.0,0.0,0.0))` 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | /* global requestAnimationFrame */ 2 | 3 | var mat4 = require('gl-mat4'); 4 | var vec3 = require('gl-vec3'); 5 | var Geometry = require('gl-geometry'); 6 | var glShader = require('gl-shader'); 7 | var glslify = require('glslify') 8 | var createOrbitCamera = require('orbit-camera'); 9 | var shell = require("gl-now")(); 10 | var createGui = require("pnp-gui"); 11 | var cameraPosFromViewMatrix = require('gl-camera-pos-from-view-matrix'); 12 | var randomArray = require('random-array'); 13 | var createSphere = require('primitive-icosphere'); 14 | var copyToClipboard = require('copy-to-clipboard'); 15 | 16 | var sphereShader, quadShader, quadGeo, sphereGeo; 17 | 18 | var camera = createOrbitCamera([0, -2.0, 0], [0, 0, 0], [0, 1, 0]); 19 | 20 | var mouseLeftDownPrev = false; 21 | 22 | var bg = [0.6, 0.7, 1.0]; // clear color. 23 | 24 | var aColor = [0.2, 0.7, 0.4]; 25 | var bColor = [0.6, 0.9, 0.2]; 26 | var cColor = [0.6, 0.8, 0.7]; 27 | var dColor = [0.5, 0.1, 0.0]; 28 | 29 | var noiseScale = {val: 1.0}; 30 | var seed = 100; 31 | 32 | // arguments are top-left and bottom-right corners 33 | function createQuad(tl, br) { 34 | var positions = []; 35 | var uvs = []; 36 | 37 | positions.push( [tl[0], tl[1] ] ); 38 | positions.push( [ br[0], tl[1] ] ); 39 | positions.push( [ tl[0] , br[1] ] ); 40 | positions.push([ br[0], br[1] ] ); 41 | 42 | uvs.push( [0,0 ] );// top-left 43 | uvs.push( [1,0 ] );// bottom-left 44 | uvs.push( [0,1 ] );// top-right 45 | uvs.push( [1,1 ] );// bottom-right 46 | 47 | var cells = []; 48 | cells.push( [2,1,0] ); 49 | 50 | cells.push( [1,2,3] ); 51 | 52 | return {positions: positions, cells:cells, uvs:uvs}; 53 | } 54 | 55 | shell.on("gl-init", function () { 56 | var gl = shell.gl 57 | 58 | gl.enable(gl.DEPTH_TEST); 59 | gl.enable(gl.CULL_FACE); 60 | gl.cullFace(gl.BACK) 61 | 62 | gui = new createGui(gl); 63 | gui.windowSizes = [300, 380]; 64 | 65 | var sphere = createSphere(1, { subdivisions: 2}); 66 | sphereGeo = Geometry(gl) 67 | .attr('aPosition', sphere.positions).faces(sphere.cells); 68 | 69 | var quad = createQuad( [400, 40], [880, 100] ); 70 | quadGeo = Geometry(gl). 71 | attr('aPosition', quad.positions, {size:2} ). 72 | attr('aUv', quad.uvs, {size:2} ).faces(quad.cells, {size:3}); 73 | 74 | sphereShader = glShader(gl, glslify("./sphere_vert.glsl"), glslify("./sphere_frag.glsl")); 75 | quadShader = glShader(gl, glslify("./quad_vert.glsl"), glslify("./quad_frag.glsl")); 76 | 77 | 78 | // fix intial camera view. 79 | camera.rotate([0,0], [0,0] ); 80 | }); 81 | 82 | 83 | function randomizeColor() { 84 | aColor = randomArray(0, 1).oned(3); 85 | bColor = randomArray(0, 1).oned(3); 86 | cColor = randomArray(0, 1).oned(3); 87 | dColor = randomArray(0, 1).oned(3); 88 | } 89 | 90 | function blackColor() { 91 | aColor = [0,0,0]; 92 | bColor =[0,0,0]; 93 | cColor = [0,0,0]; 94 | dColor = [0,0,0]; 95 | } 96 | 97 | function colorToStr(c) { 98 | return "vec3(" + [ c[0].toFixed(2),c[1].toFixed(2),c[2].toFixed(2) ].join() + ")"; 99 | } 100 | 101 | function paletteToStr() { 102 | return "cosPalette(t," + [colorToStr(aColor),colorToStr(bColor),colorToStr(cColor),colorToStr(dColor)].join()+ ")"; 103 | } 104 | 105 | function newSeed() { 106 | seed = randomArray(0.0, 100.0).oned(1)[0]; 107 | } 108 | 109 | shell.on("gl-render", function (t) { 110 | var gl = shell.gl 111 | var canvas = shell.canvas; 112 | 113 | gl.clearColor(bg[0], bg[1], bg[2], 1); 114 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 115 | gl.viewport(0, 0, canvas.width, canvas.height); 116 | 117 | var projection = mat4.create(); 118 | var scratchMat = mat4.create(); 119 | var view = camera.view(scratchMat); 120 | 121 | mat4.perspective(projection, Math.PI / 2, canvas.width / canvas.height, 0.1, 10000.0); 122 | 123 | /* 124 | Render Sphere 125 | */ 126 | 127 | sphereShader.bind(); 128 | 129 | sphereShader.uniforms.uView = view; 130 | sphereShader.uniforms.uProjection = projection; 131 | sphereShader.uniforms.uAColor = aColor; 132 | sphereShader.uniforms.uBColor = bColor; 133 | sphereShader.uniforms.uCColor = cColor; 134 | sphereShader.uniforms.uDColor = dColor; 135 | sphereShader.uniforms.uNoiseScale = noiseScale.val; 136 | sphereShader.uniforms.uSeed = seed; 137 | 138 | sphereGeo.bind(sphereShader); 139 | sphereGeo.draw(); 140 | 141 | /* 142 | Render Palette. 143 | */ 144 | 145 | quadShader.bind(); 146 | quadShader.uniforms.uAColor = aColor; 147 | quadShader.uniforms.uBColor = bColor; 148 | quadShader.uniforms.uCColor = cColor; 149 | quadShader.uniforms.uDColor = dColor; 150 | 151 | var projection = mat4.create() 152 | mat4.ortho(projection, 0, canvas.width, canvas.height, 0, -1.0, 1.0) 153 | quadGeo.bind(quadShader); 154 | quadShader.uniforms.uProj = projection; 155 | quadGeo.draw(); 156 | 157 | 158 | /* 159 | Render GUI. 160 | */ 161 | 162 | var pressed = shell.wasDown("mouse-left"); 163 | var io = { 164 | mouseLeftDownCur: pressed, 165 | mouseLeftDownPrev: mouseLeftDownPrev, 166 | 167 | mousePositionCur: shell.mouse, 168 | mousePositionPrev: shell.prevMouse 169 | }; 170 | mouseLeftDownPrev = pressed; 171 | 172 | gui.begin(io, "Window"); 173 | 174 | gui.textLine("a + b*cos(2pi*(c*t+d))"); 175 | 176 | gui.draggerRgb("a", aColor); 177 | gui.draggerRgb("b", bColor); 178 | gui.draggerRgb("c", cColor); 179 | gui.draggerRgb("d", dColor); 180 | 181 | if(gui.button("Randomize")) { 182 | randomizeColor(); 183 | } 184 | 185 | if(gui.button("To Black")) { 186 | blackColor(); 187 | } 188 | 189 | if(gui.button("Copy to Clipboard")) { 190 | copyToClipboard(paletteToStr() ); 191 | } 192 | 193 | 194 | gui.separator(); 195 | 196 | gui.textLine("Noise Settings"); 197 | 198 | 199 | gui.sliderFloat("Scale", noiseScale, 0.1, 10.0); 200 | 201 | if(gui.button("New Seed")) { 202 | newSeed(); 203 | } 204 | 205 | gui.end(gl, canvas.width, canvas.height); 206 | }); 207 | 208 | shell.on("tick", function () { 209 | 210 | // if interacting with the GUI, do not let the mouse control the camera. 211 | if (gui.hasMouseFocus()) 212 | return; 213 | 214 | if (shell.wasDown("mouse-left")) { 215 | var speed = 1.3; 216 | camera.rotate([(shell.mouseX / shell.width - 0.5) * speed, (shell.mouseY / shell.height - 0.5) * speed], 217 | [(shell.prevMouseX / shell.width - 0.5) * speed, (shell.prevMouseY / shell.height - 0.5) * speed]) 218 | } 219 | if (shell.scroll[1]) { 220 | camera.zoom(shell.scroll[1] * 0.01); 221 | } 222 | }); 223 | -------------------------------------------------------------------------------- /example/quad_frag.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | varying vec2 vUv; 4 | 5 | uniform vec3 uAColor; 6 | uniform vec3 uBColor; 7 | uniform vec3 uCColor; 8 | uniform vec3 uDColor; 9 | 10 | #pragma glslify: cosPalette = require(../index.glsl) 11 | 12 | void main() { 13 | gl_FragColor = vec4(cosPalette(vUv.x, uAColor, uBColor, uCColor, uDColor ), 1.0 ); 14 | 15 | } -------------------------------------------------------------------------------- /example/quad_vert.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | attribute vec2 aPosition; 4 | attribute vec2 aUv; 5 | 6 | varying vec2 vUv; 7 | 8 | uniform mat4 uProj; 9 | 10 | 11 | void main() { 12 | gl_Position = uProj * vec4(aPosition, 0.0, 1.0); 13 | vUv = aUv; 14 | } -------------------------------------------------------------------------------- /example/sphere_frag.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | varying vec3 vPosition; 4 | 5 | uniform vec3 uAColor; 6 | uniform vec3 uBColor; 7 | uniform vec3 uCColor; 8 | uniform vec3 uDColor; 9 | uniform float uNoiseScale; 10 | uniform float uSeed; 11 | 12 | #pragma glslify: snoise3 = require(glsl-noise/simplex/3d) 13 | #pragma glslify: cosPalette = require(../index.glsl) 14 | 15 | float noise(vec3 s) { 16 | return snoise3(s) * 0.5 + 0.5; // scale to range [0,1] 17 | } 18 | 19 | float fbm( vec3 p) { 20 | float f = 0.0; 21 | f += 0.5000*noise( p ); p = p*2.02; 22 | f += 0.2500*noise( p ); p = p*2.03; 23 | f += 0.1250*noise( p ); p = p*2.01; 24 | f += 0.0625*noise( p ); 25 | return f/0.9375; 26 | } 27 | 28 | void main() { 29 | float t = fbm(uNoiseScale*(vPosition + uSeed ) ); 30 | 31 | vec3 tex = cosPalette(t, uAColor, uBColor, uCColor, uDColor ); 32 | 33 | gl_FragColor = vec4(tex, 1.0); 34 | } 35 | -------------------------------------------------------------------------------- /example/sphere_vert.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | attribute vec3 aPosition; 4 | 5 | varying vec3 vPosition; 6 | 7 | uniform mat4 uProjection; 8 | uniform mat4 uView; 9 | 10 | void main() { 11 | vPosition = aPosition; 12 | gl_Position = uProjection * uView * vec4(aPosition, 1.0); 13 | } -------------------------------------------------------------------------------- /images/f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Erkaman/glsl-cos-palette/2183c2352891f08afe6b7f27e29119a6e9ca78ec/images/f.png -------------------------------------------------------------------------------- /images/g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Erkaman/glsl-cos-palette/2183c2352891f08afe6b7f27e29119a6e9ca78ec/images/g.png -------------------------------------------------------------------------------- /images/h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Erkaman/glsl-cos-palette/2183c2352891f08afe6b7f27e29119a6e9ca78ec/images/h.png -------------------------------------------------------------------------------- /images/j.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Erkaman/glsl-cos-palette/2183c2352891f08afe6b7f27e29119a6e9ca78ec/images/j.png -------------------------------------------------------------------------------- /images/l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Erkaman/glsl-cos-palette/2183c2352891f08afe6b7f27e29119a6e9ca78ec/images/l.png -------------------------------------------------------------------------------- /index.glsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | vec3 cosPalette( float t, vec3 a, vec3 b, vec3 c, vec3 d ){ 4 | return a + b*cos( 6.28318*(c*t+d) ); 5 | } 6 | 7 | #pragma glslify: export(cosPalette) 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glsl-cos-palette", 3 | "version": "1.0.0", 4 | "description": "glsl function for making cosine palettes", 5 | "scripts": { 6 | "start": "budo --verbose example/index.js -t glslify --live --open", 7 | "test": "standard" 8 | }, 9 | "keywords": [ 10 | "stackgl", 11 | "glsl", 12 | "gl", 13 | "webgl", 14 | "procedual", 15 | "palette", 16 | "cos", 17 | "cosine", 18 | "palette", 19 | "texture", 20 | "noise" 21 | ], 22 | "author": "Eric Arnebäck (https://github.com/Erkaman)", 23 | "license": "MIT", 24 | "devDependencies": { 25 | "copy-to-clipboard": "^2.0.0", 26 | "gl-camera-pos-from-view-matrix": "^1.0.1", 27 | "gl-geometry": "^3.1.0", 28 | "gl-mat4": "^1.1.4", 29 | "gl-now": "^1.4.0", 30 | "gl-shader": "^4.2.0", 31 | "gl-vec3": "^1.0.3", 32 | "glslify": "^5.0.2", 33 | "orbit-camera": "^1.0.0", 34 | "pnp-gui": "0.0.3", 35 | "primitive-icosphere": "^1.0.2", 36 | "random-array": "0.0.2", 37 | "glsl-noise": "0.0.0" 38 | }, 39 | "dependencies": { 40 | }, 41 | "directories": { 42 | "example": "example" 43 | }, 44 | "browserify": { 45 | "transform": [ 46 | "glslify" 47 | ] 48 | }, 49 | "repository": { 50 | "type": "git", 51 | "url": "https://github.com/Erkaman/glsl-cos-palette.git" 52 | }, 53 | "homepage": "https://github.com/Erkaman/glsl-cos-palette#readme" 54 | } 55 | --------------------------------------------------------------------------------