クリスマスだしp5.jsでコッホ雪片を降らせてみたよ


2017年12月24日
With
クリスマスだしp5.jsでコッホ雪片を降らせてみたよ はコメントを受け付けていません。

本日は12月24日。「クリスマスイブだから…」というのは後付けっぽいですが、見ようによってはクリスマスっぽく見えなくもない、こんなスケッチを作りました。

●聖夜に降るコッホ雪片(PC/Mobile両対応、クリックすると別タブが開きます)

昨日のエントリで紹介した「コッホ雪片」というフラクタル図形、雪の結晶みたいですよね。サイズや色の違うコッホ雪片が上から降ってくるような感じにアニメーションさせています。色や回転方向、落下スピードはrandom()で、左右の動きはnoise()で付けてみました。

var dots = [];
var count = 50;
var noiseval = 0.01;
var img = [];

function setup() {
	createCanvas(windowWidth, windowHeight);
	img[0] = loadImage('./images/kochcrystal.png');
	img[1] = loadImage('./images/kochcrystal2.png');
	img[2] = loadImage('./images/kochcrystal3.png');

	pointinit();
	for (var i = 0; i < count; i++) {
		dots[i].initMe();
	}
}

function draw() {
	background(20);
	for (var i = 0; i < count; i++) {
		dots[i].drawMe();
		dots[i].updateMe();
	}
}

function pointinit() {
	for (var i = 0; i < count; i++) {
		dots[i] = new SnowObj();
	}
}

function SnowObj() {
	var x, y;
	var sizeScale;
	var rotAngle;
	var rotSpeed;
	var speed, xnoise;
	var imgCol;
}

SnowObj.prototype.initMe = function () {
	this.x = random(0, width);
	this.y = random(0, height);
	this.imgCol = floor(random(0, 3));
	this.sizeScale = random(0.05, 0.3);
	this.rotAngle = 0;
	this.rotSpeed = random(-3, 3);
	this.speed = random(0.5, 2);
	this.xnoise = random(100);
}

SnowObj.prototype.updateMe = function () {
	this.x = this.x + noise(this.xnoise) * 2 - 1;
	this.xnoise = this.xnoise + noiseval;
	this.y = this.y + this.speed;
	if (this.y > height + 100) {
		this.initMe();
		this.y = -100;
	}
	this.rotAngle += this.rotSpeed;
}

SnowObj.prototype.drawMe = function () {
	push();
	translate(this.x, this.y);
	rotate(radians(this.rotAngle));
	scale(this.sizeScale, this.sizeScale);
	image(img[this.imgCol], -(img[this.imgCol].width / 2), -(img[this.imgCol].height / 2));
	pop();
}

さすがにオブジェクトごとに再帰のアルゴリズムで描画するのはパフォーマンス的に厳しいので、あらかじめ作っておいたコッホ雪片のpng画像を読み込ませて、縮小したり、回転させたりしています。色は「白」「赤紫」「青紫」の3種類です。

p5.jsの「tint()」は重すぎて気安く使えない

p5.jsには、ビットマップイメージを表示するときに、その色合いやアルファ値を設定できる「tint()」という関数があります。

・tint() - p5.js reference

前にリファレンスを眺めたとき「tint()」の存在を知り、機会があれば使ってみようと思っていました。

今回のスケッチを作るにあたって、最初「画像は白いものだけを用意して、色や透明度をtint()でいろいろ変化させてみたい」と思っていたのですが、結果的にダメでした。

なぜなら、このtint()、超激重なのです。もう、理不尽なレベルで。

最初、普通に書いて走らせてみたところ、デスクトップのそこそこリッチな環境でもせいぜい「3fps」くらいしか出ませんでした。オブジェクト数を1個に減らしても改善が見られず、何が悪いんだろうと調べているうちに「Processing.jsはtint()が激重」という情報が見つかりまして、試しにtint()をコメントアウトしてみたら、それだけでマトモになったという。いろいろ試してはみたのですが、「tint()が激重になる条件」のようなものがあるわけではなさそうで、もう、どこかに1行「tint()」と書いてあるだけで絶対的な効果を発揮する「フレーム数激オチ君」です。

静止画像に対し、明示的なイベントきっかけでフィルタかけるようなスケッチには使えるかもしれませんが、常に画面に動きがあるようなスケッチや、画像のフェードイン、フェードアウトのような用途でtint()は使えなさそうですね…。

このスケッチではあらかじめアルファ値を設定した3色の画像を個別に読み込ませておき、配列の添字で切り替えるという方針にしました。こういう画像のフィルタ処理みたいなのって、きっとCreateJSなんかは得意なんだろうなぁとボンヤリと考えながら、みなさんが素敵なクリスマスを過ごされますことを東京の片隅で祈っております。