Lesson10 – ピクセルシェーダー

Lesson07Lesson08では頂点シェーダーを扱いましたが、ここではもう1つのシェーダーであるピクセルシェーダーを紹介したいと思います。

var gl;
var posVAttrib;
var colorVAttrib;

function start()
{
  var canvas = document.getElementById('canvas');

  initGL(canvas);
  if(gl){
    initShader();

    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);

    drawScene();
  }
}

function initGL(canvas){
  gl = null;

  try{
    gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
  }
  catch(e){
  }

  if(!gl){
    alert('Unable to Initialize WebGL.');
  }
}

function initShader()
{
  // Vertex shader
  var vshader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vshader, 'attribute vec3 pos; attribute vec4 color; varying vec4 vColor; void main(void){ gl_Position = vec4(pos, 1.0); vColor = color; }');
  gl.compileShader(vshader);
  if(!gl.getShaderParameter(vshader, gl.COMPILE_STATUS)){
    alert(gl.getShaderInfoLog(vshader));
    return;
  }

  // Fragment shader
  var fshader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fshader, 'precision mediump float; varying vec4 vColor; void main(void){ gl_FragColor = vColor; }');
  gl.compileShader(fshader);
  if(!gl.getShaderParameter(fshader, gl.COMPILE_STATUS)){
    alert(gl.getShaderInfoLog(fshader));
    return;
  }

  // Create shader program
  var program = gl.createProgram();
  gl.attachShader(program, fshader);
  gl.attachShader(program, vshader);
  gl.linkProgram(program);
  if(!gl.getProgramParameter(program, gl.LINK_STATUS)){
    alert(gl.getProgramInfoLog(program));
    return;
  }
  gl.useProgram(program);

  // attribute
  posVAttrib = gl.getAttribLocation(program, 'pos');
  gl.enableVertexAttribArray(posVAttrib);

  colorVAttrib = gl.getAttribLocation(program, 'color');
  gl.enableVertexAttribArray(colorVAttrib);
}

function drawScene(){
  var buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  var vertices = new Float32Array([0.0, 0.8, 0.0, -0.8, -0.8, 0.0, 0.8, -0.8, 0.0]);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  gl.vertexAttribPointer(posVAttrib, 3, gl.FLOAT, false, 0, 0);

  buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  var colors = new Float32Array([1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.1]);
  gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
  gl.vertexAttribPointer(colorVAttrib, 4, gl.FLOAT, false, 0, 0);

  gl.drawArrays(gl.TRIANGLES, 0, 3);
  gl.flush();
}

今回のサンプルは各頂点に色を割り当てて三角形を描くようにしています。少しややこしい部分もありますので、順に解説してみようと思います。

initShader

colorVAttrib = gl.getAttribLocation(program, 'color');
gl.enableVertexAttribArray(colorVAttrib);

drawScene

var colors = new Float32Array([1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.1]);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
gl.vertexAttribPointer(colorVAttrib, 4, gl.FLOAT, false, 0, 0);

initShaderdrawSceneで各頂点毎の色を頂点シェーダーに教えています。colorsが色データになります。色は4つの値で表現することはLesson09で紹介しましたが、ここでは赤色、緑色、青色を表していることになります。

色データの渡し方は頂点データの渡し方と同じです。説明が分かり難い場合は、Lesson07も参考にしてみてください。

次に、シェーダーの中身を解説したいと思いますが、そのままでは少し見づらいので、適当に改行を追加したコードを以下に再掲します。

頂点シェーダー

attribute vec3 pos;
attribute vec4 color;

varying vec4 vColor;

void main(void)
{
  gl_Position = vec4(pos, 1.0);
  vColor = color;
}

ピクセルシェーダー

precision mediump float;
varying vec4 vColor;

void main(void)
{
  gl_FragColor = vColor;
}

頂点シェーダーのcolorという変数で各頂点の色データが与えられます。しかし、実際に色付けするのはピクセルシェーダーになりますので、vColorという変数を介して色データをピクセルシェーダーに渡します。そして、ピクセルシェーダーでgl_FragColorにこのvColorの値を代入し、三角形を描きます。

これまで詳しく説明していませんでしたが、シェーダーの変数にattributevaryingなどが登場して混乱しているかもしれません。シェーダー関係の本に詳細が書かれていますので、気になる人は一度読んでみてください。

サンプルを確認する場合はこちらをクリックしてください。
赤色、緑色、青色の三角形が表示されます。

※頂点以外は線形補間された色で表示されます。

前回の記事
次回の記事
目次ページ

コメントを残す

メールアドレスが公開されることはありません。