webgl torus lighting h_doxas Follow 2012-03-25 05:14:08 License: MIT License Fork0 Fav0 View445 Play Stop Reload Fullscreen Smart Phone Readme JavaScript 307 lines HTML 28 lines CSS 3 lines webgl torus lighting minMatrix.js onload = function(){ // canvasエレメントを取得 var c = document.getElementById('canvas'); c.width = 300; c.height = 300; // webglコンテキストを取得 var gl = c.getContext('webgl') || c.getContext('experimental-webgl'); // 頂点シェーダとフラグメントシェーダの生成 var v_shader = create_shader('vs'); var f_shader = create_shader('fs'); // プログラムオブジェクトの生成とリンク var prg = create_program(v_shader, f_shader); // attributeLocationを配列に取得 var attLocation = new Array(); attLocation[0] = gl.getAttribLocation(prg, 'position'); attLocation[1] = gl.getAttribLocation(prg, 'normal'); attLocation[2] = gl.getAttribLocation(prg, 'color'); // attributeの要素数を配列に格納 var attStride = new Array(); attStride[0] = 3; attStride[1] = 3; attStride[2] = 4; // トーラスの頂点データを生成 var torusData = torus(32, 32, 0.25, 0.5); var position = torusData[0]; var normal = torusData[1]; var color = torusData[2]; var index = torusData[3]; // VBOの生成 var pos_vbo = create_vbo(position); var nor_vbo = create_vbo(normal); var col_vbo = create_vbo(color); // VBO を登録する set_attribute([pos_vbo, nor_vbo, col_vbo], attLocation, attStride); // IBOの生成 var ibo = create_ibo(index); // IBOをバインドして登録する gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); // uniformLocationの取得 var uniLocation = new Array(); uniLocation[0] = gl.getUniformLocation(prg, 'mvpMatrix'); uniLocation[1] = gl.getUniformLocation(prg, 'invMatrix'); uniLocation[2] = gl.getUniformLocation(prg, 'lightDirection'); // minMatrix.js を用いた行列関連処理 // matIVオブジェクトを生成 var m = new matIV(); // 各種行列の生成と初期化 var mMatrix = m.identity(m.create()); var vMatrix = m.identity(m.create()); var pMatrix = m.identity(m.create()); var tmpMatrix = m.identity(m.create()); var mvpMatrix = m.identity(m.create()); var invMatrix = m.identity(m.create()); // ビュー×プロジェクション座標変換行列 m.lookAt([0.0, 0.0, 5.0], [0, 0, 0], [0, 1, 0], vMatrix); m.perspective(45, c.width / c.height, 0.1, 100, pMatrix); m.multiply(pMatrix, vMatrix, tmpMatrix); // 平行光源の向き var lightDirection = [-1, 1, 1]; // カウンタの宣言 var count = 0; // カリングと深度テストを有効にする gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); gl.enable(gl.CULL_FACE); // 恒常ループ (function(){ // canvasを初期化 gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clearDepth(100); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // カウンタをインクリメントする count++; // カウンタを元にラジアンを算出 var rad = (count % 360) * Math.PI / 180; // モデル座標変換行列の生成 m.identity(mMatrix); m.rotate(mMatrix, rad, [0, 1, 1], mMatrix); m.multiply(tmpMatrix, mMatrix, mvpMatrix); // モデル座標変換行列から逆行列を生成 m.inverse(mMatrix, invMatrix); // uniform変数の登録 gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix); gl.uniformMatrix4fv(uniLocation[1], false, invMatrix); gl.uniform3fv(uniLocation[2], lightDirection); // モデルの描画 gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0); // コンテキストの再描画 gl.flush(); // ループのために再帰呼び出し setTimeout(arguments.callee, 1000 / 30); })(); // シェーダを生成する関数 function create_shader(id){ // シェーダを格納する変数 var shader; // HTMLからscriptタグへの参照を取得 var scriptElement = document.getElementById(id); // scriptタグが存在しない場合は抜ける if(!scriptElement){return;} // scriptタグのtype属性をチェック switch(scriptElement.type){ // 頂点シェーダの場合 case 'x-shader/x-vertex': shader = gl.createShader(gl.VERTEX_SHADER); break; // フラグメントシェーダの場合 case 'x-shader/x-fragment': shader = gl.createShader(gl.FRAGMENT_SHADER); break; default : return; } // 生成されたシェーダにソースを割り当てる gl.shaderSource(shader, scriptElement.text); // シェーダをコンパイルする gl.compileShader(shader); // シェーダが正しくコンパイルされたかチェック if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){ // 成功していたらシェーダを返して終了 return shader; }else{ // 失敗していたらエラーログをアラートする alert(gl.getShaderInfoLog(shader)); } } // プログラムオブジェクトを生成しシェーダをリンクする関数 function create_program(vs, fs){ // プログラムオブジェクトの生成 var program = gl.createProgram(); // プログラムオブジェクトにシェーダを割り当てる gl.attachShader(program, vs); gl.attachShader(program, fs); // シェーダをリンク gl.linkProgram(program); // シェーダのリンクが正しく行なわれたかチェック if(gl.getProgramParameter(program, gl.LINK_STATUS)){ // 成功していたらプログラムオブジェクトを有効にする gl.useProgram(program); // プログラムオブジェクトを返して終了 return program; }else{ // 失敗していたらエラーログをアラートする alert(gl.getProgramInfoLog(program)); } } // VBOを生成する関数 function create_vbo(data){ // バッファオブジェクトの生成 var vbo = gl.createBuffer(); // バッファをバインドする gl.bindBuffer(gl.ARRAY_BUFFER, vbo); // バッファにデータをセット gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW); // バッファのバインドを無効化 gl.bindBuffer(gl.ARRAY_BUFFER, null); // 生成した VBO を返して終了 return vbo; } // VBOをバインドし登録する関数 function set_attribute(vbo, attL, attS){ // 引数として受け取った配列を処理する for(var i in vbo){ // バッファをバインドする gl.bindBuffer(gl.ARRAY_BUFFER, vbo[i]); // attributeLocationを有効にする gl.enableVertexAttribArray(attL[i]); // attributeLocationを通知し登録する gl.vertexAttribPointer(attL[i], attS[i], gl.FLOAT, false, 0, 0); } } // IBOを生成する関数 function create_ibo(data){ // バッファオブジェクトの生成 var ibo = gl.createBuffer(); // バッファをバインドする gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); // バッファにデータをセット gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(data), gl.STATIC_DRAW); // バッファのバインドを無効化 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); // 生成したIBOを返して終了 return ibo; } // トーラスを生成する関数 function torus(row, column, irad, orad){ var pos = new Array(), nor = new Array(), col = new Array(), idx = new Array(); for(var i = 0; i <= row; i++){ var r = Math.PI * 2 / row * i; var rr = Math.cos(r) * irad + orad; var ry = Math.sin(r) * irad; for(var ii = 0; ii <= column; ii++){ var tr = Math.PI * 2 / column * ii; var rx = rr * Math.cos(tr); var rz = rr * Math.sin(tr); pos.push(rx, ry, rz); var tn = vectorNormalize(rx, ry, rz); nor.push(tn[0], tn[1], tn[2]); var tc = hsva(360 / column * ii, 1, 1, 1); col.push(tc[0], tc[1], tc[2], tc[3]); } } for(i = 0; i < row; i++){ for(ii = 0; ii < column; ii++){ r = (row + 1) * ii + i; idx.push(r, r + row + 2, r + 1); idx.push(r, r + row + 1, r + row + 2); } } return [pos, nor, col, idx]; } // HSVカラー取得用関数 function hsva(h, s, v, a){ if(s > 1 || v > 1 || a > 1){return;} var th = h % 360; var i = Math.floor(th / 60); var f = th / 60 - i; var m = v * (1 - s); var n = v * (1 - s * f); var k = v * (1 - s * (1 - f)); var color = new Array(); if(!s > 0 && !s < 0){ color.push(v, v, v, a); } else { var r = new Array(v, n, m, m, k, v); var g = new Array(k, v, v, n, m, m); var b = new Array(m, m, k, v, v, n); color.push(r[i], g[i], b[i], a); } return color; } // ベクトルを正規化する関数 function vectorNormalize(){ if(arguments.length < 1){return;} var vectorLength = 0; for(var i = 0; i < arguments.length; i++){ vectorLength += arguments[i] * arguments[i]; } vectorLength = 1 / Math.sqrt(vectorLength); var normal = new Array(); for(i = 0; i < arguments.length; i++){ normal.push(arguments[i] * vectorLength); } return normal; } }; <script id="vs" type="x-shader/x-vertex"> attribute vec3 position; attribute vec3 normal; attribute vec4 color; uniform mat4 mvpMatrix; uniform mat4 invMatrix; uniform vec3 lightDirection; varying vec4 vColor; void main(void){ vec3 invLight = normalize(invMatrix * vec4(lightDirection, 0.0)).xyz; float diffuse = clamp(dot(normal, invLight), 0.1, 1.0); vColor = color * vec4(vec3(diffuse), 1.0); gl_Position = mvpMatrix * vec4(position, 1.0); } </script> <script id="fs" type="x-shader/x-fragment"> precision mediump float; varying vec4 vColor; void main(void){ gl_FragColor = vColor; } </script> <canvas id="canvas"></canvas> webgl torus lighting body{ margin: 5px; } onload = function(){ // canvasエレメントを取得 var c = document.getElementById('canvas'); c.width = 300; c.height = 300; // webglコンテキストを取得 var gl = c.getContext('webgl') || c.getContext('experimental-webgl'); // 頂点シェーダとフラグメントシェーダの生成 var v_shader = create_shader('vs'); var f_shader = create_shader('fs'); // プログラムオブジェクトの生成とリンク var prg = create_program(v_shader, f_shader); // attributeLocationを配列に取得 var attLocation = new Array(); attLocation[0] = gl.getAttribLocation(prg, 'position'); attLocation[1] = gl.getAttribLocation(prg, 'normal'); attLocation[2] = gl.getAttribLocation(prg, 'color'); // attributeの要素数を配列に格納 var attStride = new Array(); attStride[0] = 3; attStride[1] = 3; attStride[2] = 4; // トーラスの頂点データを生成 var torusData = torus(32, 32, 0.25, 0.5); var position = torusData[0]; var normal = torusData[1]; var color = torusData[2]; var index = torusData[3]; // VBOの生成 var pos_vbo = create_vbo(position); var nor_vbo = create_vbo(normal); var col_vbo = create_vbo(color); // VBO を登録する set_attribute([pos_vbo, nor_vbo, col_vbo], attLocation, attStride); // IBOの生成 var ibo = create_ibo(index); // IBOをバインドして登録する gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); // uniformLocationの取得 var uniLocation = new Array(); uniLocation[0] = gl.getUniformLocation(prg, 'mvpMatrix'); uniLocation[1] = gl.getUniformLocation(prg, 'invMatrix'); uniLocation[2] = gl.getUniformLocation(prg, 'lightDirection'); // minMatrix.js を用いた行列関連処理 // matIVオブジェクトを生成 var m = new matIV(); // 各種行列の生成と初期化 var mMatrix = m.identity(m.create()); var vMatrix = m.identity(m.create()); var pMatrix = m.identity(m.create()); var tmpMatrix = m.identity(m.create()); var mvpMatrix = m.identity(m.create()); var invMatrix = m.identity(m.create()); // ビュー×プロジェクション座標変換行列 m.lookAt([0.0, 0.0, 5.0], [0, 0, 0], [0, 1, 0], vMatrix); m.perspective(45, c.width / c.height, 0.1, 100, pMatrix); m.multiply(pMatrix, vMatrix, tmpMatrix); // 平行光源の向き var lightDirection = [-1, 1, 1]; // カウンタの宣言 var count = 0; // カリングと深度テストを有効にする gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); gl.enable(gl.CULL_FACE); // 恒常ループ (function(){ // canvasを初期化 gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clearDepth(100); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // カウンタをインクリメントする count++; // カウンタを元にラジアンを算出 var rad = (count % 360) * Math.PI / 180; // モデル座標変換行列の生成 m.identity(mMatrix); m.rotate(mMatrix, rad, [0, 1, 1], mMatrix); m.multiply(tmpMatrix, mMatrix, mvpMatrix); // モデル座標変換行列から逆行列を生成 m.inverse(mMatrix, invMatrix); // uniform変数の登録 gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix); gl.uniformMatrix4fv(uniLocation[1], false, invMatrix); gl.uniform3fv(uniLocation[2], lightDirection); // モデルの描画 gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0); // コンテキストの再描画 gl.flush(); // ループのために再帰呼び出し setTimeout(arguments.callee, 1000 / 30); })(); // シェーダを生成する関数 function create_shader(id){ // シェーダを格納する変数 var shader; // HTMLからscriptタグへの参照を取得 var scriptElement = document.getElementById(id); // scriptタグが存在しない場合は抜ける if(!scriptElement){return;} // scriptタグのtype属性をチェック switch(scriptElement.type){ // 頂点シェーダの場合 case 'x-shader/x-vertex': shader = gl.createShader(gl.VERTEX_SHADER); break; // フラグメントシェーダの場合 case 'x-shader/x-fragment': shader = gl.createShader(gl.FRAGMENT_SHADER); break; default : return; } // 生成されたシェーダにソースを割り当てる gl.shaderSource(shader, scriptElement.text); // シェーダをコンパイルする gl.compileShader(shader); // シェーダが正しくコンパイルされたかチェック if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){ // 成功していたらシェーダを返して終了 return shader; }else{ // 失敗していたらエラーログをアラートする alert(gl.getShaderInfoLog(shader)); } } // プログラムオブジェクトを生成しシェーダをリンクする関数 function create_program(vs, fs){ // プログラムオブジェクトの生成 var program = gl.createProgram(); // プログラムオブジェクトにシェーダを割り当てる gl.attachShader(program, vs); gl.attachShader(program, fs); // シェーダをリンク gl.linkProgram(program); // シェーダのリンクが正しく行なわれたかチェック if(gl.getProgramParameter(program, gl.LINK_STATUS)){ // 成功していたらプログラムオブジェクトを有効にする gl.useProgram(program); // プログラムオブジェクトを返して終了 return program; }else{ // 失敗していたらエラーログをアラートする alert(gl.getProgramInfoLog(program)); } } // VBOを生成する関数 function create_vbo(data){ // バッファオブジェクトの生成 var vbo = gl.createBuffer(); // バッファをバインドする gl.bindBuffer(gl.ARRAY_BUFFER, vbo); // バッファにデータをセット gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW); // バッファのバインドを無効化 gl.bindBuffer(gl.ARRAY_BUFFER, null); // 生成した VBO を返して終了 return vbo; } // VBOをバインドし登録する関数 function set_attribute(vbo, attL, attS){ // 引数として受け取った配列を処理する for(var i in vbo){ // バッファをバインドする gl.bindBuffer(gl.ARRAY_BUFFER, vbo[i]); // attributeLocationを有効にする gl.enableVertexAttribArray(attL[i]); // attributeLocationを通知し登録する gl.vertexAttribPointer(attL[i], attS[i], gl.FLOAT, false, 0, 0); } } // IBOを生成する関数 function create_ibo(data){ // バッファオブジェクトの生成 var ibo = gl.createBuffer(); // バッファをバインドする gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); // バッファにデータをセット gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(data), gl.STATIC_DRAW); // バッファのバインドを無効化 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); // 生成したIBOを返して終了 return ibo; } // トーラスを生成する関数 function torus(row, column, irad, orad){ var pos = new Array(), nor = new Array(), col = new Array(), idx = new Array(); for(var i = 0; i <= row; i++){ var r = Math.PI * 2 / row * i; var rr = Math.cos(r) * irad + orad; var ry = Math.sin(r) * irad; for(var ii = 0; ii <= column; ii++){ var tr = Math.PI * 2 / column * ii; var rx = rr * Math.cos(tr); var rz = rr * Math.sin(tr); pos.push(rx, ry, rz); var tn = vectorNormalize(rx, ry, rz); nor.push(tn[0], tn[1], tn[2]); var tc = hsva(360 / column * ii, 1, 1, 1); col.push(tc[0], tc[1], tc[2], tc[3]); } } for(i = 0; i < row; i++){ for(ii = 0; ii < column; ii++){ r = (row + 1) * ii + i; idx.push(r, r + row + 2, r + 1); idx.push(r, r + row + 1, r + row + 2); } } return [pos, nor, col, idx]; } // HSVカラー取得用関数 function hsva(h, s, v, a){ if(s > 1 || v > 1 || a > 1){return;} var th = h % 360; var i = Math.floor(th / 60); var f = th / 60 - i; var m = v * (1 - s); var n = v * (1 - s * f); var k = v * (1 - s * (1 - f)); var color = new Array(); if(!s > 0 && !s < 0){ color.push(v, v, v, a); } else { var r = new Array(v, n, m, m, k, v); var g = new Array(k, v, v, n, m, m); var b = new Array(m, m, k, v, v, n); color.push(r[i], g[i], b[i], a); } return color; } // ベクトルを正規化する関数 function vectorNormalize(){ if(arguments.length < 1){return;} var vectorLength = 0; for(var i = 0; i < arguments.length; i++){ vectorLength += arguments[i] * arguments[i]; } vectorLength = 1 / Math.sqrt(vectorLength); var normal = new Array(); for(i = 0; i < arguments.length; i++){ normal.push(arguments[i] * vectorLength); } return normal; } }; <script id="vs" type="x-shader/x-vertex"> attribute vec3 position; attribute vec3 normal; attribute vec4 color; uniform mat4 mvpMatrix; uniform mat4 invMatrix; uniform vec3 lightDirection; varying vec4 vColor; void main(void){ vec3 invLight = normalize(invMatrix * vec4(lightDirection, 0.0)).xyz; float diffuse = clamp(dot(normal, invLight), 0.1, 1.0); vColor = color * vec4(vec3(diffuse), 1.0); gl_Position = mvpMatrix * vec4(position, 1.0); } </script> <script id="fs" type="x-shader/x-fragment"> precision mediump float; varying vec4 vColor; void main(void){ gl_FragColor = vColor; } </script> <canvas id="canvas"></canvas> body{ margin: 5px; } use an iframe compat browser, deer Play on jsdo.it games Author Share ブログに埋め込む QR Tag Download Complete! Description What kind of game? Control Device Smartphone Controllerjsdo.it WebSocket Controller» Mouse Keyboard Touch Device Fullscreen Activated Inactivated jsdo.it games から削除する Submit Author h_doxas URLhttp://wgld.org ソースが汚いのが難点 Tweet Default Panel Auto play Screenshot Readme JavaScript HTML CSS Size Width: px Height: px code <script type="text/javascript" src="http://jsdo.it/blogparts/jFG0/js"></script> library&test test webgl Tweet Twitter Discussion Questions on this code? Tags library&test test webgl