このブログの最初の記事が2011/12/30の「3Dを基礎から勉強する」の記事でした。3Dを理解する前に2Dを理解しないとねってことで月日が経ってしまったわけですが、2Dの理解も深まったので、ようやく3Dの勉強に本格的に入ることにしました。
再度、「てっく煮ブログ」の下記の記事を参考にFlash版をJavascriptに移植してみました。
AS3.0 で 3D プログラミングを1から勉強する (2) - 行列の導入
AS3.0 で 3D プログラミングを1から勉強する (3) - 透視投影
以前の記事である「行列による2Dアフィン変換を理解してみる」にて行列の有効性の理解した、今度は3D版の行列である。
3Dの行列は下記の通り、2Dの場合は3x3行列でしたが3Dの場合は4x4行列となります。
回転行列 X軸周りの回転 Y軸周りの回転 Z軸周りの回転 | 1 0 0 0 | | cos 0 sin 0 | | cos -sin 0 0 | | 0 cos -sin 0 | | 0 1 0 0 | | sin cos 0 0 | | 0 sin cos 0 | | -sin 0 cos 0 | | 0 0 1 0 | | 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 | 拡大縮小行列 平行移動行列 | sx 0 0 0 | | 1 0 0 tx | | 0 sy 0 0 | | 0 1 0 ty | | 0 0 sx 0 | | 0 0 1 tz | | 0 0 0 1 | | 0 0 0 1 |
参考:回転行列、拡大縮小行列、平行移動行列(三次元座標の場合)
http://imagingsolution.net/math/rotation-scaling-translation-3d-matrix/
行列による3Dアフィン変換のソースリスト
var Matrix3D = (function () { // | m00 m01 m02 tx | // | m10 m11 m12 ty | // | m20 m21 m22 tz | function Matrix3D() { this.m00 = this.m11 = this.m22 = 1; this.m10 = this.m20 = this.m01 = this.m21 = this.m02 = this.m12 = this.tx = this.ty = this.tz = 0; } Matrix3D.prototype.set = function (mx) { this.m00 = mx.m00; this.m01 = mx.m01; this.m02 = mx.m02; this.tx = mx.tx; this.m10 = mx.m10; this.m11 = mx.m11; this.m12 = mx.m12; this.ty = mx.ty; this.m20 = mx.m20; this.m21 = mx.m21; this.m22 = mx.m22; this.tz = mx.tz; return this; }; Matrix3D.prototype.multi = function (mx) { var wx, wy, wz; wx = this.m00; wy = this.m01; wz = this.m02; this.m00 = wx * mx.m00 + wy * mx.m10 + wz * mx.m20; this.m01 = wx * mx.m01 + wy * mx.m11 + wz * mx.m21; this.m02 = wx * mx.m02 + wy * mx.m12 + wz * mx.m22; this.tx = wx * mx.tx + wy * mx.ty + wz * mx.ty + this.tx; wx = this.m10; wy = this.m11; wz = this.m12; this.m10 = wx * mx.m00 + wy * mx.m10 + wz * mx.m20; this.m11 = wx * mx.m01 + wy * mx.m11 + wz * mx.m21; this.m12 = wx * mx.m02 + wy * mx.m12 + wz * mx.m22; this.ty = wx * mx.tx + wy * mx.ty + wz * mx.tz + this.ty; wx = this.m20; wy = this.m21; wz = this.m22; this.m20 = wx * mx.m00 + wy * mx.m10 + wz * mx.m20; this.m21 = wx * mx.m01 + wy * mx.m11 + wz * mx.m21; this.m22 = wx * mx.m02 + wy * mx.m12 + wz * mx.m22; this.tz = wx * mx.tx + wy * mx.ty + wz * mx.tz + this.tz; return this; }; Matrix3D.prototype.rotateX = function (rad) { var mx = new Matrix3D(); mx.m11 = Math.cos(rad); mx.m12 = -Math.sin(rad); mx.m21 = Math.sin(rad); mx.m22 = Math.cos(rad); return this.multi(mx); }; Matrix3D.prototype.rotateY = function (rad) { var mx = new Matrix3D(); mx.m00 = Math.cos(rad); mx.m02 = Math.sin(rad); mx.m20 = -Math.sin(rad); mx.m22 = Math.cos(rad); return this.multi(mx); }; Matrix3D.prototype.rotateZ = function (rad) { var mx = new Matrix3D(); mx.m00 = Math.cos(rad); mx.m01 = -Math.sin(rad); mx.m10 = Math.sin(rad); mx.m11 = Math.cos(rad); return this.multi(mx); }; Matrix3D.prototype.scale = function (sx, sy, sz) { var mx = new Matrix3D(); mx.m00 = sx; mx.m11 = sy; mx.m22 = sz; return this.multi(mx); }; Matrix3D.prototype.translate = function (tx, ty, tz) { this.tx = tx; this.ty = ty; this.tz = tz; }; Matrix3D.prototype.transformPoint = function (p) { return new Point3D(this.m00 * p.x + this.m01 * p.y + this.m02 * p.z + this.tx, this.m10 * p.x + this.m11 * p.y + this.m12 * p.z + this.ty, this.m20 * p.x + this.m21 * p.y + this.m22 * p.z + this.tz); }; return Matrix3D; })();
今回、行列をクラス化した際に4x4行列ではなく4x3行列にしています。
これは先程の各行列を見ると最下行がどれも|0 0 0 1|と固定となっており、0に対して値を掛け算しても値は0になるため、無駄な計算を少し省いた感じです。
今回はここまでとして、次はもう少し中身を追っていきます。