<canvas id='bird-canvas'></canvas>
<!-- ------------------------------------------------------------------------------------------------------- -->
<!-- BIRD -->
<!-- ------------------------------------------------------------------------------------------------------- -->
<script id='bird-vertex-shader' type='x-shader/x-vertex'>
precision mediump float;
#define SPEED 3.0
uniform float u_canvas_height;
uniform float u_canvas_width;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform float u_time;
attribute vec2 a_position;
varying vec2 v_position;
void main() {
vec4 new_position = u_projection_matrix * u_view_matrix * u_model_matrix * vec4(a_position, 0.0, 1.0);
float deltaY = (abs(new_position.x) + 0.3) * sin(abs(new_position.x * 2.0) + u_time * SPEED) / 3.0
+ (sin(abs(a_position.x) * 100.0 + u_time) + sin(a_position.y * 100.0 + u_time)) / 70.0;
new_position.y += deltaY;
new_position.x = new_position.x * u_canvas_height / u_canvas_width;
new_position.x /= (1.0 + 0.9 * new_position.w);
new_position.y /= (1.0 + 0.9 * new_position.w);
v_position = a_position;
gl_Position = new_position;
}
</script>
<script id='bird-fragment-shader' type='x-shader/x-fragment'>
precision mediump float;
uniform float u_canvas_height;
uniform float u_canvas_width;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform float u_time;
varying vec2 v_position;
void main() {
float color = v_position.y;
if (color > 1.0) {
color = 1.0;
} else if (color < 0.0) {
color = 0.0;
}
gl_FragColor = vec4(1.0 - color, 1.0 - color, 1.0 - color, 1.0);
}
</script>
<!-- ------------------------------------------------------------------------------------------------------- -->
<!-- DOTS -->
<!-- ------------------------------------------------------------------------------------------------------- -->
<script id='bird-dots-vertex-shader' type='x-shader/x-vertex'>
precision mediump float;
#define SPEED 3.0
uniform float u_canvas_height;
uniform float u_canvas_width;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform float u_time;
attribute vec2 a_position;
varying vec2 v_position;
void main() {
vec4 new_position = u_projection_matrix * u_view_matrix * u_model_matrix * vec4(a_position, 0.0, 1.0);
float time = u_time;
float deltaY = (abs(new_position.x) + 0.3) * sin(abs(new_position.x * 2.0) + time * SPEED) / 3.0
+ (sin(abs(a_position.x) * 100.0 + time) + sin(a_position.y * 100.0 + time)) / 70.0;
new_position.y += deltaY;
new_position.x = new_position.x * u_canvas_height / u_canvas_width;
new_position.x /= (1.0 + 0.9 * new_position.w);
new_position.y /= (1.0 + 0.9 * new_position.w);
v_position = a_position;
gl_Position = new_position;
gl_PointSize = 1.0;
}
</script>
<script id='bird-dots-fragment-shader' type='x-shader/x-fragment'>
precision mediump float;
uniform float u_canvas_height;
uniform float u_canvas_width;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform float u_time;
varying vec2 v_position;
void main() {
float color = v_position.y;
if (color > 1.0) {
color = 1.0;
} else if (color < 0.0) {
color = 0.0;
}
gl_FragColor = vec4(color, color, color, 1.0);
}
</script>
<!-- ------------------------------------------------------------------------------------------------------- -->
<!-- TRACK DOTS -->
<!-- ------------------------------------------------------------------------------------------------------- -->
<script id='bird-trackdots-vertex-shader' type='x-shader/x-vertex'>
precision mediump float;
#define SPEED 3.0
#define TIME_DELTA -0.2
uniform float u_canvas_height;
uniform float u_canvas_width;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform float u_time;
attribute vec2 a_position;
varying vec2 v_position;
void main() {
vec4 new_position = u_projection_matrix * u_view_matrix * u_model_matrix * vec4(a_position, 0.0, 1.0);
float time = u_time + TIME_DELTA;
float deltaY = (abs(new_position.x) + 0.3) * sin(abs(new_position.x * 2.0) + time * SPEED) / 3.0
+ (sin(abs(a_position.x) * 100.0 + time) + sin(a_position.y * 100.0 + time)) / 70.0;
new_position.y += deltaY;
new_position.x = new_position.x * u_canvas_height / u_canvas_width;
new_position.x /= (1.0 + 0.9 * new_position.w);
new_position.y /= (1.0 + 0.9 * new_position.w);
v_position = a_position;
gl_Position = new_position;
gl_PointSize = 2.0;
}
</script>
<script id='bird-trackdots-fragment-shader' type='x-shader/x-fragment'>
precision mediump float;
#define SPEED 3.0
#define PI 3.1415926
uniform float u_canvas_height;
uniform float u_canvas_width;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform float u_time;
varying vec2 v_position;
void main() {
float color = 0.3 * abs(abs(v_position.x) - 4.0) * (1.0 - v_position.y) * (1.0 - sin(PI / 2.0 + u_time * SPEED * 2.0)) * sin(PI + u_time * SPEED);
if (color > 0.2) {
color = 0.2;
} else if (color < 0.0) {
color = 0.0;
}
gl_FragColor = vec4(color * 0.3, color, color * 0.7, 1.0);
}
</script>
<!-- ------------------------------------------------------------------------------------------------------- -->
<!-- TRACK DOTS 2 -->
<!-- ------------------------------------------------------------------------------------------------------- -->
<script id='bird-trackdots2-vertex-shader' type='x-shader/x-vertex'>
precision mediump float;
#define SPEED 3.0
#define TIME_DELTA -0.2
uniform float u_canvas_height;
uniform float u_canvas_width;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform float u_time;
attribute vec2 a_position;
varying vec2 v_position;
void main() {
vec4 new_position = u_projection_matrix * u_view_matrix * u_model_matrix * vec4(a_position, 0.0, 1.0);
float time = u_time + TIME_DELTA;
float deltaY = (abs(new_position.x) + 0.3) * sin(abs(new_position.x * 2.0) + time * SPEED) / 3.0
+ (sin(abs(a_position.x) * 100.0 + time) + sin(a_position.y * 100.0 + time)) / 70.0;
new_position.y += deltaY;
new_position.x = new_position.x * u_canvas_height / u_canvas_width;
new_position.x /= (1.0 + 0.9 * new_position.w);
new_position.y /= (1.0 + 0.9 * new_position.w);
v_position = a_position;
gl_Position = new_position;
gl_PointSize = 1.0;
}
</script>
<script id='bird-trackdots2-fragment-shader' type='x-shader/x-fragment'>
precision mediump float;
#define SPEED 3.0
#define PI 3.1415926
uniform float u_canvas_height;
uniform float u_canvas_width;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform float u_time;
varying vec2 v_position;
void main() {
float color = 0.3 * abs(abs(v_position.x) - 4.0) * v_position.y * (1.0 - sin(PI / 2.0 + u_time * SPEED * 2.0)) * sin(u_time * SPEED);
if (color > 0.2) {
color = 0.2;
} else if (color < 0.0) {
color = 0.0;
}
gl_FragColor = vec4(color * 0.5, color, color * 0.7, 1.0);
}
</script>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
overflow: hidden;
}
View Compiled
class Bird {
constructor(options) {
this.canvas = options.canvas;
this.gl = this.canvas.getContext('webgl');
this.gl.clearColor(0.0, 0.0, 0.0, 1.0);
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
this.shaders = {
bird: {
vertex: this.compileShader(this.gl.VERTEX_SHADER, options.shaders.bird.vertex),
fragment: this.compileShader(this.gl.FRAGMENT_SHADER, options.shaders.bird.fragment)
},
dots: {
vertex: this.compileShader(this.gl.VERTEX_SHADER, options.shaders.dots.vertex),
fragment: this.compileShader(this.gl.FRAGMENT_SHADER, options.shaders.dots.fragment)
},
trackdots: {
vertex: this.compileShader(this.gl.VERTEX_SHADER, options.shaders.trackdots.vertex),
fragment: this.compileShader(this.gl.FRAGMENT_SHADER, options.shaders.trackdots.fragment)
},
trackdots2: {
vertex: this.compileShader(this.gl.VERTEX_SHADER, options.shaders.trackdots2.vertex),
fragment: this.compileShader(this.gl.FRAGMENT_SHADER, options.shaders.trackdots2.fragment)
},
};
this.cameraOptions = {
zoom: 0.3,
angleY: Math.PI * 0.4,
angleX: 0.0
};
this.programs = {
bird: null,
dots: null
};
this.calculateMatrices();
this.createBirdGeometry();
this.createPrograms();
this.updateCanvasUniforms();
this.updateMatrixUniforms();
this.initEventListeners();
this.updateCanvasSize();
requestAnimationFrame(this.animate.bind(this));
}
calculateMatrices() {
const x = -4;
const y = -0.5;
this.modelMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, 0, 1
];
const z = this.cameraOptions.zoom;
const a = this.cameraOptions.angleY;
const b = this.cameraOptions.angleX;
this.viewMatrix = [
z * Math.cos(b), 0, z * -Math.sin(b), 0,
z * -Math.sin(a) * Math.sin(b), z * Math.cos(a), z * -Math.sin(a) * Math.cos(b), 0,
z * Math.cos(a) * Math.sin(b), z * Math.sin(a), z * Math.cos(a) * Math.cos(b), 0,
0, 0, 0, 1
];
const s = 1 / (Math.tan(90 * Math.PI / 360));
const n = -1;
const f = 10.0;
this.projectionMatrix = [
s, 0, 0, 0,
0, s, 0, 0,
0, 0, -(f)/(f-n), -1,
0, 0, -f*n/(f-n), 1
];
}
createBirdGeometry() {
const points = [];
const stepX = 0.4;
const stepY = 0.2;
for (let x = 0; x <= 8; x += stepX) {
for (let y = 0; y <= 1; y += stepY) {
if (y === 0) {
points.push(x);
points.push(y);
points.push(x + stepX);
points.push(y);
}
points.push(x + stepX);
points.push(y);
points.push(x + stepX);
points.push(y + stepY);
points.push(x + stepX);
points.push(y + stepY);
points.push(x);
points.push(y + stepY);
points.push(x);
points.push(y + stepY);
points.push(x);
points.push(y);
points.push(x);
points.push(y);
points.push(x + stepX);
points.push(y + stepY);
}
}
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.gl.createBuffer());
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
new Float32Array(points),
this.gl.STATIC_DRAW
);
}
compileShader(type, source) {
const shader = this.gl.createShader(type);
this.gl.shaderSource(shader, source);
this.gl.compileShader(shader);
console.log(this.gl.getShaderInfoLog(shader));
return shader;
}
createPrograms() {
this.createProgramByName('bird');
this.createProgramByName('dots');
this.createProgramByName('trackdots');
this.createProgramByName('trackdots2');
}
createProgramByName(name) {
this.programs[name] = this.gl.createProgram();
this.gl.attachShader(this.programs[name], this.shaders[name].vertex);
this.gl.attachShader(this.programs[name], this.shaders[name].fragment);
this.gl.linkProgram(this.programs[name]);
const vertexPositionAttribute = this.gl.getAttribLocation(this.programs[name], 'a_position');
this.gl.enableVertexAttribArray(vertexPositionAttribute);
this.gl.vertexAttribPointer(vertexPositionAttribute, 2, this.gl.FLOAT, false, 0, 0);
}
updateMatrixUniforms() {
this.updateMatrixUniformsForProgram(this.programs.bird);
this.updateMatrixUniformsForProgram(this.programs.dots);
this.updateMatrixUniformsForProgram(this.programs.trackdots);
this.updateMatrixUniformsForProgram(this.programs.trackdots2);
}
updateMatrixUniformsForProgram(program) {
this.gl.useProgram(program);
this.gl.uniformMatrix4fv(this.gl.getUniformLocation(program, 'u_model_matrix'), false, this.modelMatrix);
this.gl.uniformMatrix4fv(this.gl.getUniformLocation(program, 'u_view_matrix'), false, this.viewMatrix);
this.gl.uniformMatrix4fv(this.gl.getUniformLocation(program, 'u_projection_matrix'), false, this.projectionMatrix);
}
updateCanvasUniforms() {
this.updateCanvasUniformsForProgram(this.programs.bird);
this.updateCanvasUniformsForProgram(this.programs.dots);
this.updateCanvasUniformsForProgram(this.programs.trackdots);
this.updateCanvasUniformsForProgram(this.programs.trackdots2);
}
updateCanvasUniformsForProgram(program) {
this.gl.useProgram(program);
this.gl.uniform1f(this.gl.getUniformLocation(program, 'u_canvas_height'), this.canvas.height);
this.gl.uniform1f(this.gl.getUniformLocation(program, 'u_canvas_width'), this.canvas.width);
}
updateTimeUniform(timeStamp) {
this.updateTimeUniformForProgram(this.programs.bird, timeStamp);
this.updateTimeUniformForProgram(this.programs.dots, timeStamp);
this.updateTimeUniformForProgram(this.programs.trackdots, timeStamp);
this.updateTimeUniformForProgram(this.programs.trackdots2, timeStamp);
}
updateTimeUniformForProgram(program, timeStamp) {
this.gl.useProgram(program);
this.gl.uniform1f(this.gl.getUniformLocation(program, 'u_time'), timeStamp / 1000.0);
}
updateCanvasSize() {
this.canvas.height = Math.ceil(window.innerHeight);
this.canvas.width = Math.ceil(window.innerWidth);
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
this.updateCanvasUniforms();
}
updateCameraAngles(mouseX, mouseY) {
const modX = (mouseX - window.innerWidth / 2) / window.innerWidth;
const modY = (mouseY - window.innerHeight / 2) / window.innerHeight;
this.cameraOptions.angleY = Math.PI * 0.4 + modY / 4;
this.cameraOptions.angleX = modX;
this.calculateMatrices();
this.updateMatrixUniforms();
}
initEventListeners() {
window.addEventListener('resize', this.updateCanvasSize.bind(this));
document.body.addEventListener('mousemove', (e) => {
this.updateCameraAngles(e.clientX, e.clientY);
});
}
animate(timeStamp) {
this.gl.clearColor(0.0, 0.0, 0.05, 1.0);
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
this.updateTimeUniform(timeStamp);
this.gl.useProgram(this.programs.trackdots);
this.gl.drawArrays(this.gl.POINTS, 0, 1000);
this.gl.useProgram(this.programs.bird);
this.gl.drawArrays(this.gl.LINES, 0, 1000);
this.gl.useProgram(this.programs.dots);
this.gl.drawArrays(this.gl.POINTS, 0, 1000);
this.gl.useProgram(this.programs.trackdots2);
this.gl.drawArrays(this.gl.POINTS, 0, 1000);
requestAnimationFrame(this.animate.bind(this));
}
}
const myBird = new Bird({
canvas: document.getElementById('bird-canvas'),
shaders: {
bird: {
vertex: document.getElementById('bird-vertex-shader').textContent,
fragment: document.getElementById('bird-fragment-shader').textContent
},
dots: {
vertex: document.getElementById('bird-dots-vertex-shader').textContent,
fragment: document.getElementById('bird-dots-fragment-shader').textContent
},
trackdots: {
vertex: document.getElementById('bird-trackdots-vertex-shader').textContent,
fragment: document.getElementById('bird-trackdots-fragment-shader').textContent
},
trackdots2: {
vertex: document.getElementById('bird-trackdots2-vertex-shader').textContent,
fragment: document.getElementById('bird-trackdots2-fragment-shader').textContent
},
}
});
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.