agehama's diary

年一更新

加算ブレンドでメタボールっぽい表現

f:id:agehama:20130823223033p:plain

円形の光の画像を用意して、加算ブレンドでたくさん描画した後、比較ブレンド?で閾値以下の明度の部分を単色で塗りつぶせばそれっぽくなりそうと思った。

光の画像はここの濃度分布関数を参考にして作った。
http://www.syuhitu.org/other/meta/meta.html

ソースコード

#include <Siv3D.hpp>

//濃度分布関数に基づいてImageを作成
Image BallImage(int size)
{
	const double ts=0.1,te=1.0;
	const double C=1.0;
	const int radius=size/2;
	
	const Vec2 center(radius,radius);
	Image image(size,size);
	for(int y=0; y<image.height; ++y)
	{
		for(int x=0; x<image.width; ++x)
		{
			const double tm = Vec2(x,y).distanceFrom(center)/radius;
			const double a = Min(tm-te,0.0);
			const double Cm = C*a*a/(ts-te)/(ts-te);
			image[y][x] = ColorF(Cm);
		}
	}
	
	return image;
}

void Main()
{
	const int threshold = 250;
	const Texture texthr(640,480,Color(threshold));
	const Texture texball(BallImage(200));

	std::vector<std::pair<Vec2,Vec2>> balls(70);
	for(auto& ball : balls)
	{
		ball.first = Vec2(Random(0,640),Random(0,480));
		ball.second = Vec2(Random(-1.0,1.0),Random(-1.0,1.0));
	}

	while(System::Update())
	{
		Graphics::Set2DBlendState(true,Blend::SrcAlpha,Blend::One,BlendOp::Add);
		for(auto& ball : balls)
		{
			ball.first += ball.second;
			texball.drawAt(ball.first);
		}

		Graphics::Set2DBlendState(true,Blend::One,Blend::One,BlendOp::Max);
		texthr.draw();
	}
}

実行結果

f:id:agehama:20130823223051p:plain

メタボール部分のRGB値がそれぞれ255でそれ以外の部分が250だから大分見づらい。

最後の比較ブレンドを省いて赤くしたのが一番上に貼った画像で、こっちは見やすいけど有効範囲の外にまで色がついてしまっている。まあ工夫すればどこかで使えるかもしれない。

牛乳

せっかくなので、Box2Dを使って流体っぽくしてみた。

f:id:agehama:20130823224745g:plain