LoginSignup
1
1

More than 5 years have passed since last update.

WebGLで2DシンプルなGLSLを書く

Posted at

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

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1