WebGLネーティブとThree.jsで比較 - シェーダー実行 -


同じ実行画面をWebGLのネーティブコードとThree.jsのコードで比較してみます。

今回作成した結果は以下のとおりです。

![Screen Shot 2015-09-19 at 8.10.35 PM.png](https://qiita-image-store.s3.amazonaws.com/0/15925/8d1fbc21-9299-2dfc-9d29-9e1957b6aa8e.png "Screen Shot 2015-09-19 at 8.10.35 PM.png")

http://codepen.io/kenjiSpecial/pen/meEebx

赤、、

特に意味はありません。


##Three.js

Vertexシェーダ

```vertex.glsl
void main(void){
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
```

fragmentシェーダ

```fragment.glsl
void main(void) {
    gl_FragColor = vec4(1.0, .0, .0, 1.);
}
```

jsファイル

```javascript:main.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シェーダ

```vertex.glsl
attribute vec2 a_position;
void main() {
   gl_Position = vec4(a_position, 0, 1);
}
```

fragmentシェーダ

```fragment.glsl
void main(void) {
    gl_FragColor = vec4(1.0, .0, .0, 1.);
}
```


```javascript:main.js
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だと一行すんでましたが、

```javascript:
    shaderMaterial = new THREE.ShaderMaterial({
        uniforms       : uniforms,
        vertexShader   : threeVertexShaderText,
        fragmentShader : fragmentShaderText
    });
```


webGLだと、、


```javascript:
    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