LoginSignup
26
21

More than 5 years have passed since last update.

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

Posted at

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

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

Screen Shot 2015-09-19 at 8.10.35 PM.png

赤、、

特に意味はありません。

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ファイル

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.);
}
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だと一行すんでましたが、

    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

26
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
21