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)を試しました。

