前回までのLessonではシェーダーの中身をできるだけ見ないようにしてきましたが、いよいよその中身を見る時がやってきました。
まずは、前回のサンプルで用いた頂点シェーダー関係の部分を抜き出してみます。
// Vertex shader
var vshader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vshader, 'attribute vec3 pos; void main(void){ gl_Position = vec4(pos, 1.0); }');
gl.compileShader(vshader);
if(!gl.getShaderParameter(vshader, gl.COMPILE_STATUS)){
alert(gl.getShaderInfoLog(vshader));
return;
}
シェーダーはコンパイル&リンクして使うということは以前説明しましたが、今回の注目はそのソースコードの中身です。shaderSource
に渡している文字列がそれになります。
ただ、このままでは少し見づらいと思いますので適当に改行したソースコードを次に再掲します。
attribute vec3 pos;
void main(void)
{
gl_Position = vec4(pos, 1.0);
}
頂点シェーダーは頂点毎に計算されます。
何となく想像できるかもしれませんがpos
という変数で頂点座標が与えられています。関係している部分はinitShader
とdrawScene
です。
initShader
// attribute
var posVAttrib = gl.getAttribLocation(program, 'pos');
gl.enableVertexAttribArray(posVAttrib);
drawScene
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(posVAttrib, 3, gl.FLOAT, false, 0, 0);
initShader
では頂点シェーダーのpos
とJavaScriptのposVAttrib
の関係を設定しています。そして、drawScene
で頂点座標をposVAttrib
に渡しています。
こう書くと何か分かったような、分からないような気分になってきます。そこで、1つサンプルとして前回紹介した平行移動のサンプルを頂点シェーダーのソースコードを修正して実現してみたいと思います。
平行移動の場合、結局のところ0.5足せば良いのですから、次のように書き変えれば実現できそうな気がします。
attribute vec3 pos;
void main(void)
{
gl_Position = vec4(0.5, 0.5, 0.5, 0) + vec4(pos, 1.0);
}
不要かもしれませんが、念のために全ソースコードを掲載しておきます。これを修正して、x軸方向にのみ平行移動した図やy軸方向にのみ平行移動した図を描く練習をしてみるのも面白いと思います。
var gl;
var posVAttrib;
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; void main(void){ gl_Position = vec4(0.5, 0.5, 0.5, 0) + vec4(pos, 1.0); }');
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, 'void main(void){ gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); }');
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);
}
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);
gl.drawArrays(gl.TRIANGLES, 0, 3);
gl.flush();
}
更に、もう1つサンプルを追加したいと思います。上のようにvec4
で足しても今回の平行移動は実現できますが、後々のことを考えて、Lesson05で紹介した平行移動行列を使ってみようと思います。
頂点シェーダーの部分のみ抜き出てみますと、次のようにできます。(見やすいように改行していますが、実際に試す場合は改行を削除してください。)
attribute vec3 pos;
void main(void)
{
mat4 m = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, 0.5,0.5,0.5,1);
gl_Position = m * vec4(pos, 1.0);
}