Lesson07とLesson08では頂点シェーダーを扱いましたが、ここではもう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);
initShader
とdrawScene
で各頂点毎の色を頂点シェーダーに教えています。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
の値を代入し、三角形を描きます。
これまで詳しく説明していませんでしたが、シェーダーの変数にattribute
やvarying
などが登場して混乱しているかもしれません。シェーダー関係の本に詳細が書かれていますので、気になる人は一度読んでみてください。
※頂点以外は線形補間された色で表示されます。