Canvasで網目模様を描く方法を教えてください。その5の派生
地球のテクスチャーマッピング。
基本的なところを勉強中。
マウスで操作できるのだが、イベントハンドラあたりを書き直した。
こちらは問題ないのだが、その5に適用すると球体の反対側を表にしたとき動作が逆になる。
あぁ〜時間がほしい。また忙しくなる。
参照元
http://jsdo.it/totetero/without_polygon
しかし、マッピングする方法が目指しているものと違う。
逆行列だ!?う〜〜〜ん、悩む
http://d.hatena.ne.jp/gyuque/20090211
<!DOCTYPE html> <meta charset="UTF-8"> <title>3D</title> <style> canvas { background : #aaa; } </style> <body> <img style="display:none;" src="data:image/gif;base64, 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"> <canvas id='world' width="600" height="400"></canvas> <script> function load (){ var canvas = document.getElementById("world"); var context = canvas.getContext("2d"); var canvasdat = context.createImageData(canvas.width, canvas.height); var imgdat = null; var rotq = []; // メインループ var renderScene = function(){ rotq = ctrl.rotq; for(var i = 0; i < canvasdat.height; i++){ for(var j = 0; j < canvasdat.width; j++){ var index = i * canvasdat.width + j; var x = (j - canvasdat.width * 0.5) / 150; var y = (i - canvasdat.height * 0.5) / 150; var r = x * x + y * y; if(r <= 1){ // 描画対象点の球上座標を得る var z = Math.sqrt(1 - r); // 球上座標にクォータニオン回転を適用する var ix = rotq[3] * x + rotq[1] * z - rotq[2] * y; var iy = rotq[3] * y + rotq[2] * x - rotq[0] * z; var iz = rotq[3] * z + rotq[0] * y - rotq[1] * x; var iw = -rotq[0] * x - rotq[1] * y - rotq[2] * z; x = ix * rotq[3] - iw * rotq[0] - iy * rotq[2] + iz * rotq[1]; y = iy * rotq[3] - iw * rotq[1] - iz * rotq[0] + ix * rotq[2]; z = iz * rotq[3] - iw * rotq[2] - ix * rotq[1] + iy * rotq[0]; // 球上座標をテクスチャ座標に変換する var u = Math.atan2(z, x) / (2 * Math.PI) + 0.5; var v = Math.acos(y) / Math.PI; u = Math.floor((1 - u) * imgdat.height); v = Math.floor((1 - v) * imgdat.width); var index2 = v * imgdat.width + u; canvasdat.data[index * 4 + 0] = imgdat.data[index2 * 4 + 0]; canvasdat.data[index * 4 + 1] = imgdat.data[index2 * 4 + 1]; canvasdat.data[index * 4 + 2] = imgdat.data[index2 * 4 + 2]; canvasdat.data[index * 4 + 3] = 255; }else{ canvasdat.data[index * 4 + 0] = 0; canvasdat.data[index * 4 + 1] = 0; canvasdat.data[index * 4 + 2] = 0; canvasdat.data[index * 4 + 3] = 255; } } } context.putImageData(canvasdat, 0, 0); setTimeout(renderScene, 40); } // 画像の読み込み var img = new Image(); img.onload = function(){ var imgcanvas = document.createElement('canvas'); imgcanvas.setAttribute('width', 360); imgcanvas.setAttribute('height', 360); var imgcontext = imgcanvas.getContext('2d'); imgcontext.drawImage(img, 0, 0, imgcanvas.width, imgcanvas.height); imgdat = imgcontext.getImageData(0, 0, imgcanvas.width, imgcanvas.height); // 処理開始 renderScene(); } img.src = document.querySelector ('img').src; } //マウスのドラッグで、3Dオブジェクトを回転させる (function () { function CanvasController (canvas) { this.canvas = canvas; this.mouseX = 0; this.mouseY = 0; this.touchF = false; this.rotq = [0, 0, 0, 1]; this.gain = 100; // mouse移動の感度 } function handleEvent (event) { var e, x, y, dx, dy, a; switch (event.type) { case 'mousedown' : case 'touchstart' : this.touchF = true; break; case 'mouseup' : case 'touchend' : this.touchF = false; break; case 'mousemove' : case 'touchmove' : e = event.target.getBoundingClientRect (); x = event.clientX - e.left; y = event.clientY - e.top; if (this.touchF){ // クオータニオンによる回転 dx = -(x - this.mouseX) / this.gain; dy = (y - this.mouseY) / this.gain; a = Math.sqrt (dx * dx + dy * dy); if(a != 0){ var ar = a * 0.5; var as = Math.sin(ar) / a; var qax = this.rotq[0], qay = this.rotq[1], qaz = this.rotq[2], qaw = this.rotq[3]; var qbx = dy * as; var qby = dx * as; var qbw = Math.cos(ar); this.rotq = [ qax * qbw + qaw * qbx - qaz * qby, qay * qbw + qaw * qby + qaz * qbx, qaz * qbw + qax * qby - qay * qbx, qaw * qbw - qax * qbx - qay * qby ]; } } this.mouseX = x; this.mouseY = y; break; default : break; } } function create (canvas) { var obj; if (1 > arguments.length) throw new Error ('引数がない'); if ('CANVAS' !== canvas.tagName) throw new Error ('Canvas 要素ではない'); obj = new CanvasController (canvas); canvas.addEventListener ('mousedown', obj, false); canvas.addEventListener ('touchstart', obj, false); canvas.addEventListener ('mouseup', obj, false); canvas.addEventListener ('touchend', obj, false); canvas.addEventListener ('mousemove', obj, false); canvas.addEventListener ('touchmove', obj, false); canvas = null; return obj; } //__ CanvasController.prototype.handleEvent = handleEvent; //__ CanvasController.create = create; this.CanvasController = CanvasController; }) (); var ctrl = CanvasController.create (document.querySelector ('canvas')); addEventListener ('load', load, false); </script>