同じ実行画面をWebGLのネーティブコードとThree.jsのコードで比較してみます。
今回作成した結果は以下のとおりです。
赤、、
特に意味はありません。
Three.js
Vertexシェーダ
void main(void){
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
fragmentシェーダ
void main(void) {
gl_FragColor = vec4(1.0, .0, .0, 1.);
}
jsファイル
var canvasWidth, canvasHeight;
var renderer, scene, camera;
var geometry, shaderMaterial, mesh, uniforms;
function init(){
canvasWidth = 600;
canvasHeight = 400;
renderer = new THREE.WebGLRenderer({antialias : true});
renderer.setSize(canvasWidth, canvasHeight);
var wrapper = document.getElementById('three-js-wrapper');
wrapper.appendChild(renderer.domElement);
camera = new THREE.OrthographicCamera( canvasWidth/-2, canvasWidth/2, canvasHeight / 2, canvasHeight / - 2, 1, 1000 );
camera.position.z = 1;
scene = new THREE.Scene();
geometry = new THREE.PlaneGeometry( canvasWidth, canvasHeight );
uniforms = {
}
shaderMaterial = new THREE.ShaderMaterial({
uniforms : uniforms,
vertexShader : threeVertexShaderText,
fragmentShader : fragmentShaderText
});
mesh = new THREE.Mesh( geometry, shaderMaterial );
scene.add(mesh);
requestAnimationFrame(loop);
}
function loop(){
renderer.render(scene, camera);
requestAnimationFrame(loop);
}
init();
カメラはOrthographicCameraを使用しています。
geometryはPlaneGeometryを使用し、縦横の長さをウィンドウサイズと対応させています。
materialとしてshaderマテリアルを使用。
今後、uniformsの値をshaderに渡すために空のobjectを使用しています。
canvasのapiに比べたら、面倒に見えますが、
WebGLネーティブに比べるとthree.jsはやっぱり簡単ですねー
three.jsが広まるのも理解できます。。
WebGL
Vertexシェーダ
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}
fragmentシェーダ
void main(void) {
gl_FragColor = vec4(1.0, .0, .0, 1.);
}
var canvas, gl;
var shaderProgram;
var positionLocation;
var buffer;
var vertices;
var start = function(){
canvas = document.createElement('canvas');
canvas.style.display = "block";
canvas.width = 600;
canvas.height = 400;
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px'
var wrapper = document.getElementById('web-gl-wrapper');
wrapper.appendChild(canvas);
initGL(canvas);
initShader();
initBuffers();
requestAnimationFrame(drawScene);
}
function initGL(canvas){
try{
gl = canvas.getContext("webgl") || canvas.getContext('experimental-webgl');
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
}catch(e){}
}
function initShader(){
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderText);
gl.compileShader(fragmentShader)
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, glVertexShaderText);
gl.compileShader(vertexShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
console.log("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
positionLocation = gl.getAttribLocation(shaderProgram, 'a_position');
}
function initBuffers(){
buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
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
];
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
buffer.itemSize = 2;
buffer.numItem = 6;
}
function drawScene(){
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, buffer.itemSize, gl.FLOAT, false, 0, 0);
// draw
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
start();
bufferという変数が出てきます。
bufferとは、、、
webglで頂点を保存するためのメモリー領域らしいです(https://sites.google.com/site/webglbook/)。
作成したshaderを使えるようにするには、three.jsだと一行すんでましたが、
shaderMaterial = new THREE.ShaderMaterial({
uniforms : uniforms,
vertexShader : threeVertexShaderText,
fragmentShader : fragmentShaderText
});
webGLだと、、
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderText);
gl.compileShader(fragmentShader)
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, glVertexShaderText);
gl.compileShader(vertexShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
console.log("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
長いですね。
fragmentシェーダとvertexシェーダをそれぞれ作成し、シェーダテキストを登録、コンパイルします。
コンパイルしたものをシェーダープログラムにattachし、fragmentシェーダとvertexシェーダがGPUで実行できるようにします(gl.linkProgram(shaderProgram)
)。
https://msdn.microsoft.com/en-us/library/dn302428(v=vs.85).aspx
WebGLはGPUでレンダリングするための宗教的儀式に見えてきます。
GPUで動かすために色々な儀式(関数や変数)を決められた順番でやるもの。
順番や儀式を間違えなければ動くが、1つでも間違えるとエラーをだすものだと感じてます。
そんな形式的なものを打破し、WebGLをみんなものにするためにthree.jsがある、、
なんかキリスト教のカトリックとプロテスタントみたいな感じもします。
とりあえず、今日はこんなところで、、
参考
WebGL勉強するための定番ブログ
wgld.org
http://wgld.org/
The concepts of WebGL
https://hacks.mozilla.org/2013/04/the-concepts-of-webgl/
本格的にゼロから勉強したい時に読む本
WebGL Programming Guide
https://sites.google.com/site/webglbook/
WebGLについてしりたい
第1回目 WebGLの概念
http://qiita.com/como/items/8a66a6646d2ed64133a0
shaderについて勉強したい
WebGLでGLSL (Shader) を書く流れを(ざっくり)まとめた
http://qiita.com/katsew/items/0b338a508b59be410902#%E5%8F%82%E8%80%83