シェーダーとしてまずLambertを勉強した。ライトの向いてる方向と法線の内積求めて、diffuseと色をかけるだけでできてしまうらしい。参考ページを見て作ってた。フラグメントシェーダーをまず載せて、その後に全体のプログラムを載せる。その前にプログラムのスクリーンショット。右の方からライトを当てている
Fragmentシェーダー、法線とライトの方向の内積をとって、diffuseをかけている。今回は物体の色は無視している
precision mediump float; //法線ベクトル varying vec3 N; //ライトの向いている方向 vec3 light_dir = vec3(-1.0, 0.0, 0.0); //lightのdiffuse vec4 light_diffuse = vec4(0.8, 0.8, 0.8, 1.0); void main(){ //法線ベクトルとライトの方向の内積をdiffuseにかけたものを色とする gl_FragColor = vec4(light_diffuse.rgb * dot(N, light_dir), 1.0); }
プログラム全体
<html><head> <meta http-equiv="content-type" content="text/html; charset=Shift_JIS"> <title></title> <script type="text/javascript" src="./js/glMatrix-0.js"></script> <script type="text/javascript" src="./js/gun3.js"></script> <script type="text/javascript" src="./js/object3d.js"></script> <script> window.onload = function(){ //HTML5のキャンバス取得 var canvas = document.getElementById("canvas"); //WebGLのハンドル(?)取得 var gl = canvas.getContext("experimental-webgl"); //Vertexシェーダー取得 var vertexShader = createShader(gl, "2d-vertex-shader", gl.VERTEX_SHADER); //Fragmentシェーダー取得 var fragmentShader = createShader(gl, "2d-fragment-shader", gl.FRAGMENT_SHADER); //シェーダーをリンクする program = createProgram(gl, vertexShader, fragmentShader); var mvMatrix = mat4.create(); var pMatrix = mat4.create(); //シェーダーにデータを渡すためのハンドル(?)取得 var pMatrixLocation = gl.getUniformLocation(program, "u_PMatrix"); var mvMatrixLocation = gl.getUniformLocation(program, "u_MVMatrix"); var nMatrixLocation = gl.getUniformLocation(program, "u_NormalMatrix"); var positionLocation = gl.getAttribLocation(program, "a_position"); var normalLocation = gl.getAttribLocation(program, "a_normal"); //銃のモデルから表示オブジェクトを作る var object = new Object3D(gl); object.initBuffer(gun3.vertices, gun3.faces, gun3.normals); object.setHandle(positionLocation, normalLocation); var rotate = 135; gl.enable(gl.DEPTH_TEST); setInterval(function(){ mat4.perspective(45, 450.0 / 450.0, 1.0, 10.0, pMatrix); mat4.identity(mvMatrix); //銃の表示位置を指定 mat4.translate(mvMatrix, [0.0, -0.5, -5.0]); //銃を回転させる mat4.rotate(mvMatrix, rotate * 3.1415 / 180.0, [0, 1, 0]); //シェーダーにデータを渡す gl.uniformMatrix4fv(pMatrixLocation, false, pMatrix); gl.uniformMatrix4fv(mvMatrixLocation, false, mvMatrix); var normalMatrix = mat3.create(); mat4.toInverseMat3(mvMatrix, normalMatrix); mat3.transpose(normalMatrix); gl.uniformMatrix3fv(nMatrixLocation, false, normalMatrix); gl.clearColor(0.7, 0.7, 0.7, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); object.draw(); }, 16); } function createShader(gl, shaderId, type) { var shader = gl.createShader(type); var source = document.getElementById(shaderId).innerHTML; gl.shaderSource(shader, source); gl.compileShader(shader); return shader; } function createProgram(gl, vertexShader, fragmentShader){ var program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { alert(gl.getShaderInfoLog(vertexShader)); alert(gl.getShaderInfoLog(fragmentShader)); } gl.useProgram(program); return program; } </script> <script id="2d-vertex-shader" type="x-shader/x-vertex"> attribute vec3 a_position; attribute vec3 a_normal; varying vec3 N; uniform mat4 u_MVMatrix; uniform mat4 u_PMatrix; uniform mat3 u_NormalMatrix; void main(){ N = normalize(u_NormalMatrix * a_normal); gl_Position = u_PMatrix * u_MVMatrix * vec4(a_position, 1.0); } </script> <script id="2d-fragment-shader" type="x-shader/x-fragment"> precision mediump float; varying vec3 N; vec3 light_dir = vec3(1.0, 0.0, 0.0); vec4 light_diffuse = vec4(0.8, 0.8, 0.8, 1.0); void main(){ //法線ベクトルとライトの方向の内積をdiffuseにかけたものを色とする gl_FragColor = vec4(light_diffuse.rgb * dot(N, light_dir), 1.0); } </script> </head> <body> <canvas id="canvas" width="450" height="450"></canvas> </body></html>
この中で使っているObject3D
var Object3D = function(gl){ var vertexBuffer = null; var indexBuffer = null; var normalBUffer = null; var positionHandle = null; var normalHandle = null; var length = 0; this.initBuffer = function(vertices, indices, normals){ initVertexBuffer(vertices); initIndexBuffer(indices); initNormalBuffer(normals); length = indices.length; } this.setHandle = function(pHandle, nHandle){ positionHandle = pHandle; normalHandle = nHandle; } this.draw = function(){ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.enableVertexAttribArray(positionHandle); gl.vertexAttribPointer(positionHandle, 3, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); gl.enableVertexAttribArray(normalHandle); gl.vertexAttribPointer(normalHandle, 3, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); gl.drawElements(gl.TRIANGLES, length, gl.UNSIGNED_SHORT, 0); } function initVertexBuffer(vertices){ vertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); } function initIndexBuffer(indices){ indexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); } function initNormalBuffer(normals){ normalBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW); } }
glMatrixはこちらから
gun3.jsは
gun3.js