Twitter
2021年03月13日 - Three.js・WebVR

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

  • このエントリーをはてなブックマークに追加

関連記事

前の記事へ

GPGPUでパーティクル

次の記事へ

GLSLでジュリア集合