Demo: https://codepen.io/mo4_9/pen/eGywGp
GLSLを書くときは、2DならWebGL、3DならThree.jsで書くのがよさげ。
今回は2D表現なのでWebGLで書いてみた。
index.html
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision mediump float;
uniform float u_time;
void main(void) {
gl_FragColor = vec4(abs(sin(u_time)), abs(cos(u_time)), 0., 1.);
}
</script>
script.js
let canvas,
gl,
positionLocation,
timeLocation,
vbo;
start();
function start() {
canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
const wrapper = document.querySelector('.wrapper');
wrapper.appendChild(canvas);
gl = canvas.getContext("webgl") || canvas.getContext('experimental-webgl');
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
initShader();
initVbo();
requestAnimationFrame(tick);
}
function initShader() {
const vs = create_shader("vertexShader");
const fs = create_shader("fragmentShader");
const program = create_program(vs,fs);
positionLocation = gl.getAttribLocation(program, 'a_position');
timeLocation = gl.getUniformLocation(program, 'u_time');
}
function initVbo() {
const vertices = [
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0
];
vbo = create_vbo(vertices);
vbo.itemSize = 2;
}
function tick(time){
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, vbo.itemSize, gl.FLOAT, false, 0, 0);
gl.uniform1f(timeLocation, time/1000);
// draw
gl.drawArrays(gl.TRIANGLES, 0, 6);
requestAnimationFrame(tick);
}
// wgld.org
function create_shader(id) {
let shader;
let scriptElement = document.getElementById(id);
if(!scriptElement) return;
switch(scriptElement.type){
case 'x-shader/x-vertex':
shader = gl.createShader(gl.VERTEX_SHADER);
break;
case 'x-shader/x-fragment':
shader = gl.createShader(gl.FRAGMENT_SHADER);
break;
default:
return;
}
console.log(scriptElement.text)
gl.shaderSource(shader, scriptElement.text);
gl.compileShader(shader);
if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
return shader;
}else{
alert(gl.getShaderInfoLog(shader));
}
}
function create_program(vs, fs){
let program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if(gl.getProgramParameter(program, gl.LINK_STATUS)){
gl.useProgram(program);
return program;
} else {
alert(gl.getProgramInfoLog(program));
}
}
function create_vbo(data){
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
// gl.bindBuffer(gl.ARRAY_BUFFER, null);
return vbo;
}
参考
https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API
https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext
http://wbgl.org/
https://codepen.io/kenjiSpecial/pen/meEebx?editors=1010
https://stackoverflow.com/questions/45131804/how-to-set-a-time-uniform-in-webgl