-
Notifications
You must be signed in to change notification settings - Fork 0
/
glslsketch.js
154 lines (135 loc) · 4.42 KB
/
glslsketch.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
* A WebGL example of a dithered noise blob/sphere, using Regl.
* @author Matt DesLauriers (@mattdesl)
*/
// Import geometry & utilities
const createRegl = require('regl');
const createPrimitive = require('primitive-icosphere');
const createCamera = require('perspective-camera');
const glslify = require('glslify');
const hexRgb = require('hex-rgb');
// Utility to convert hex string to [ r, g, b] floats
const hexToRGB = hex => {
const rgba = hexRgb(hex, { format: 'array' });
return rgba.slice(0, 3).map(n => n / 255);
};
const settings = {
// Output size
dimensions: [ 256, 256 ],
// Setup render loop
animate: true,
duration: 7,
fps: 24,
// Ensure we set up a canvas with WebGL context, not 2D
context: 'webgl',
// We can pass down some properties to the WebGL context...
attributes: {
antialias: true // turn on MSAA
}
};
const sketch = ({ gl, canvasWidth, canvasHeight }) => {
// Background & foreground colors
const color = '#f2bac4';
const foregroundRGB = hexToRGB(color);
const backgroundRGBA = [ ...foregroundRGB, 1.0 ];
// Setup REGL with our canvas context
const regl = createRegl({ gl });
// Create a simple sphere mesh
const sphere = createPrimitive(1, { subdivisions: 5 });
// Create a perspective camera
const camera = createCamera({
fov: 45 * Math.PI / 180
});
// Place our camera
camera.translate([ 0, 0, 6 ]);
camera.lookAt([ 0, 0, 0 ]);
camera.update();
// Build a draw command for the mesh
const drawMesh = regl({
// Fragment & Vertex shaders
frag: glslify(`
precision highp float;
uniform vec3 color;
uniform float time;
uniform vec2 resolution;
varying vec3 vNormal;
varying vec3 vPosition;
varying vec2 screenUV;
#pragma glslify: dither = require('glsl-dither/8x8');
void main () {
// Spin light around a bit
float angle = sin(time * 0.25) * 2.0 + 3.14 * 0.5;
vec3 lightPosition = vec3(cos(angle), sin(time * 1.0), sin(angle));
vec3 L = normalize(lightPosition);
vec3 N = normalize(vNormal);
// Get diffuse contribution
float diffuse = max(0.0, dot(N, L));
diffuse = smoothstep(0.0, 1.25, diffuse);
diffuse = pow(diffuse, 0.25);
diffuse *= max(0.0, 1.0 - distance(vPosition, lightPosition) / 2.0) * 1.0;
diffuse += pow(vNormal.z, 0.95) * 0.05;
diffuse = clamp(diffuse, 0.0, 1.0);
float ditherSize = 256.0;
diffuse = dither(gl_FragCoord.xy / resolution.xy * ditherSize, diffuse);
gl_FragColor = vec4(color * diffuse, 1.0);
}
`),
vert: glslify(`
precision highp float;
attribute vec3 position;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform float time;
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 screenUV;
#pragma glslify: noise = require('glsl-noise/classic/4d');
void main () {
// Get initial normal
vNormal = normalize(position);
// Contribute noise
vec3 pos = position;
pos += vNormal * pow(noise(vec4(position.xyz * 1.0, time * 0.25)), 0.75) * 1.0;
pos += vNormal * pow(noise(vec4(position.xyz * 0.75, time * 0.25)), 0.75) * 0.5;
pos += vNormal * pow(noise(vec4(position.xyz * 40.0, time * 0.5)), 0.1) * 0.3;
pos *= 0.75;
// Update normal
vNormal = normalize(pos);
vPosition = pos;
// Final position
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos.xyz, 1.0);
screenUV = gl_Position.xy;
}
`),
uniforms: {
projectionMatrix: regl.prop('projectionMatrix'),
modelViewMatrix: regl.prop('modelViewMatrix'),
color: foregroundRGB,
resolution: [ canvasWidth, canvasHeight ],
time: regl.prop('time')
},
attributes: {
position: regl.buffer(sphere.positions),
normal: regl.buffer(sphere.normals)
},
elements: regl.elements(sphere.cells)
});
return ({ viewportWidth, viewportHeight, time, playhead }) => {
// On each tick, update regl timers and sizes
regl.poll();
// Clear backbuffer with black
regl.clear({
color: backgroundRGBA,
depth: 1,
stencil: 0
});
camera.viewport = [ 0, 0, viewportWidth, viewportHeight ];
camera.update();
drawMesh({
projectionMatrix: camera.projection,
modelViewMatrix: camera.view,
time
});
};
};
export default sketch;