HTML5のCanvasでつくるダイナミックな表現―CreateJSを使う

第21回 水平に回す立方体の面を塗る

この記事を読むのに必要な時間:およそ 3.5 分

立方体の表向きの面のみを塗る

まずは,第20回につくったサンプルコード1および2の立方体の4面を塗ろう。まだ,面の裏表は考えない。面のクラス(Face)には,つぎのように塗り色のプロパティ(color)を加える。また,塗り色はランダムに決めたいので,ランダムな整数を返す関数がほしい。そこで,クラスのように扱える名前空間のオブジェクト(MathUtils)を定めて,その静的メソッド(getRandomInt())として加えた。引数の最大値と最小値(minとmax)の順序は,逆でも値が求まるように条件判定の処理を入れている。

// Face
// function Face(pos0, pos1, pos2, pos3) {
function Face(pos0, pos1, pos2, pos3, color) {
  this.length = 4;
  this.color = color;
  this[0] = pos0;
  this[1] = pos1;
  this[2] = pos2;
  this[3] = pos3;
}

// MathUtils
var MathUtils = {};
MathUtils.getRandomInt = function(min, max) {
  if (min > max) {
    var temp = min;
    min = max;
    max = temp;
  }
  var randomNumber = Math.random() * (max - min) + min;
  return Math.floor(randomNumber);
};

面のクラス(Face)のコンストラクタに塗り色の引数が加わったので,面の配列をつくる関数(getFacesVertices())からの呼出しにランダムなカラーを与える。ランダムなカラーを返す関数(getRandomColor())は,前掲のランダムな整数が得られるメソッド(MathUtils.getRandomInt())を用いた。

function getFacesVertices() {
  var vertices = [
    /*
    new Face(0, 1, 2, 3),
    new Face(1, 5, 6, 2),
    new Face(4, 0, 3, 7),
    new Face(5, 4, 7, 6)
    */
    new Face(0, 1, 2, 3, getRandomColor()),
    new Face(1, 5, 6, 2, getRandomColor()),
    new Face(4, 0, 3, 7, getRandomColor()),
    new Face(5, 4, 7, 6, getRandomColor())
  ];
  return vertices;
}
function getRandomColor() {
  return createjs.Graphics.getRGB(Math.floor(MathUtils.getRandomInt(0, 0xFFFFFF)));
}

そして,ひとつひとつの面を描く関数(draw())にも塗り色を引数(color)として加える。面の線描は除いた。立方体を描く関数(drawFaces())は,面のオブジェクト(face)のプロパティ(color)から塗り色を定めている。

function drawFaces(points, faces) {

  var facePoints = face.getFacePoints(points);
  // draw(facePoints);
  draw(facePoints, face.color);

}

// function draw(points) {
function draw(points, color) {

  drawGraphics
  // .beginStroke("mediumblue")
  // .setStrokeStyle(1)
  .beginFill(color)
  .moveTo(point.x, point.y);

}

これで,立方体の面がランダムな色で塗られる。もちろん,まだ塗り重ねについて考えていないので,面の前後関係は崩れている(前掲図1参照⁠⁠。面の裏表を調べるために必要なメソッドをクラス(MathUtils)に加えよう。

外積を計算するには,ベクトルを定めなければならない。始点(vector0)と終点(vector1)のふたつの座標から,位置ベクトルを求めるメソッド(MathUtils.subtractVectors())は,xy座標それぞれを引き算してPointオブジェクトで返す。ふたつのベクトル(vector0とvector1)から外積を導く関数(crossProduct2D())は,前項で示した2次元ベクトルの外積の計算式にしたがって値を返している。

MathUtils.subtractVectors = function(vector0, vector1) {
  var vectorX = vector1.x - vector0.x;
  var vectorY = vector1.y - vector0.y;
  return new createjs.Point(vectorX, vectorY);
};
MathUtils.crossProduct2D = function(vector0, vector1) {
  return vector0.x * vector1.y - vector0.y * vector1.x;
}

立方体を描く関数(drawFaces())は,表向きの面だけを描く。面が表向きかどうかは,関数(isFront())で調べる。引数(facePoints)は4頂点座標をもつ面のオブジェクトだ。初めの3頂点座標から,表の面に対して右ネジに定められたふたつのベクトル(vector0とvector1)を得る。そのうえで,外積が0以上,つまりふたつのベクトルが右ネジの位置にあるかどうかをブール(論理)値で返している。

function drawFaces(points, faces) {

  if (isFront(facePoints)) {
    draw(facePoints, face.color);
  }

}
function isFront(facePoints) {
  var origin = facePoints[0];
  var vector0 = MathUtils.subtractVectors(origin, facePoints[1]);
  var vector1 = MathUtils.subtractVectors(origin, facePoints[2]);
  return (0 <= MathUtils.crossProduct2D(vector0, vector1));
}

これで,立方体は表向きの面だけが塗られる。面を描く順序はとくに変えることなく,水平に回る立方体が正しく表現される。ベクトルを求めたり,外積を計算したりするのは,簡単な四則演算だ。Array.sort()メソッドより,ずっと負荷は軽い。しかも,見えない面は描かないので,無駄な描画も省ける。かなりお得な処理といえる。

図6 水平に回る立方体の表向きの面だけを描く

図6左 水平に回る立方体の表向きの面だけを描く 図6右 水平に回る立方体の表向きの面だけを描く

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書