2021年03月13日 - WebVR・Three.js
WebGLでシェーダ(GLSL)入門
「Three.jsでシェーダ(GLSL)入門」で、Three.jsでシェーダを使用する方法を調べましたが、「GLSL だけでレンダリングする-wgld.org」を参考に、WebGLでシェーダを使用する方法を調べてみました。
WebGLでシェーダ(GLSL)入門
GLSL(OpenGL Shading Language)はC言語の構文をベースとしたシェーダ言語です。WebGLでシェーダを使用する場合はGLSLを使います。
GLSLには、バーテックスシェーダとフラグメントシェーダがあります。バーテックスシェーダは、オブジェクトの位置や回転など頂点データをスクリーン上のどこに配置するかを計算し、フラグメントシェーダは、スクリーン上の各ピクセルの描画色を計算します。
● script.jsの読み込み
いろいろとGLSLを試せるように、GLSLとWebGLで四角形ポリゴンをレンダリングするファイルを分けました。GLSLはscript.jsからインポートするので、script.jsをtype="module"をつけて読み込みます。
<script src="js/script.js" type="module"></script>
● glsl.js
//バーテックスシェーダ const vertexShader =` attribute vec3 position; void main(void){ gl_Position = vec4(position,1.0); } `; //フラグメントシェーダ const fragmentShader =` precision mediump float; //経過時間 uniform float time; //マウス座標 uniform vec2 mouse; //スクリーンサイズ uniform vec2 resolution; void main(void){ //フラグメント座標の正規化 vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x,resolution.y); vec2 color = (p.xy + vec2(1.0)) * 0.5; gl_FragColor = vec4(color,0.5,1.0); } `; export { vertexShader, fragmentShader };
● script.js
//=============================================================== // Import //=============================================================== import { vertexShader, fragmentShader } from './glsl.js'; //=============================================================== // Init & Redering //=============================================================== window.addEventListener('load',function(){ init(); rendering(); }); let canvas,gl; let prg,uniLocation; let mx,my; let startTime,time; function init(){ //canvasの設定 canvas = document.getElementById('webgl-canvas'); canvas.width = 700; canvas.height = 700; //WebGLコンテキストの取得 gl = canvas.getContext('webgl'); //シェーダの生成 const vShader = createShader(gl.VERTEX_SHADER,vertexShader); const fShader = createShader(gl.FRAGMENT_SHADER,fragmentShader); //プログラムオブジェクトの生成とリンク prg = createProgram(vShader,fShader); uniLocation = []; uniLocation[0] = gl.getUniformLocation(prg,'time'); uniLocation[1] = gl.getUniformLocation(prg,'mouse'); uniLocation[2] = gl.getUniformLocation(prg,'resolution'); //頂点座標の設定 const position = [ -1.0,1.0,0.0, 1.0,1.0,0.0, -1.0,-1.0,0.0, 1.0,-1.0,0.0 ]; //インデックスの設定 const index = [ 0,2,1, 1,2,3 ]; //四角形ポリゴンを生成 const vPosition = createVbo(position); const vIndex = createIbo(index); const vAttLocation = gl.getAttribLocation(prg,'position'); gl.bindBuffer(gl.ARRAY_BUFFER,vPosition); gl.enableVertexAttribArray(vAttLocation); gl.vertexAttribPointer(vAttLocation,3,gl.FLOAT,false,0,0); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,vIndex); startTime = new Date().getTime(); mx = 0.5; my = 0.5; //画面の初期化 gl.clearColor(0.0,0.0,0.0,1.0); window.addEventListener('mousemove',mouseMove); } function rendering(){ //経過時間 time = (new Date().getTime() - startTime) * 0.001; //カラーバッファをクリア gl.clear(gl.COLOR_BUFFER_BIT); //uniform変数の送信 gl.uniform1f(uniLocation[0],time); gl.uniform2fv(uniLocation[1],[mx,my]); gl.uniform2fv(uniLocation[2],[canvas.width,canvas.height]); //描画 gl.drawElements(gl.TRIANGLES,6,gl.UNSIGNED_SHORT,0); gl.flush(); requestAnimationFrame(rendering); } //=============================================================== // Controll //=============================================================== function mouseMove(event){ mx = event.offsetX / canvas.width; my = event.offsetY / canvas.height; } //=============================================================== // Function //=============================================================== //シェーダを生成 function createShader(shaderType,shaderText){ const shader = gl.createShader(shaderType); gl.shaderSource(shader,shaderText); gl.compileShader(shader); return shader; } //プログラムオブジェクトを生成しシェーダをリンク function createProgram(vs,fs){ const program = gl.createProgram(); gl.attachShader(program, vs); gl.attachShader(program, fs); gl.linkProgram(program); gl.useProgram(program); return program; } //VBOを生成 function createVbo(data){ const 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; } //IBOを生成 function createIbo(data){ const ibo = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,ibo); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,new Int16Array(data),gl.STATIC_DRAW); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,null); return ibo; }
完成したデモになります。WebGLでシェーダ(GLSL)を試してみました。