Unity
reaction-diffusion

反応拡散波で作った模様をテクスチャーにしてみる

More than 1 year has passed since last update.

前回の投稿にて、反応拡散波で均等パターンを描くことができるようになったので、これをテクスチャーとして3Dオブジェクトに貼り付けてみます。Unityを使用します。

Source: https://drive.google.com/open?id=0BwyNTY13C2gkSWgxcGpHZE52Ujg

Textureの色を実行時に変える

Texutureの色を実行中に変えるには、単純にSetPixelを使用します。ただ、この方式を毎フレーム実行すると遅いので検証用としてです。

IEnumerator UpdateTexture () {
  for (int y = 0; y < cell_length; y++) {
    for (int x = 0; x < cell_length; x++) {
      Cell c = cells [x,y];
      float r = (c.u/Umax);
      float b = (c.v/Vmax);
      Color color = Color.HSVToRGB(.1f+r*.3f,.8f,r/b, true);
      texture.SetPixel(x, y, color);
    }
  }
  texture.Apply();
  yield return new WaitForSeconds (.5f);
  StartCoroutine (UpdateTexture());
}

とりあえず、縦横128ピクセルのテクスチャーに反応拡散波の模様を転写することができましたので、これをCubeに貼ります。

スクリーンショット 2017-10-01 12.30.18.png

予想通りの出来になりました。
せっかくこの模様なので、テクスチャーだけでなく法線マップも貼り付けたくなってきます。

バンプマップをテクスチャーから実行時に生成する

実行時に作成したテクスチャーからバンプマップを作成するには、テクスチャーの各ピクセルの色を法線ベクトルに変換できればよさそうです。

各ピクセルの輝度を算出する

まず、テクスチャーの各ピクセルを統一的に比較するために、各ピクセルの色から輝度を算出します。

float Luminance (Color c) {
    return c.r * 0.298912f + c.g * 0.586611f + c.b * 0.114478f;
}

スクリーンショット 2017-10-01 12.20.53.png
輝度をテクスチャーに書き込むとこんな感じになります。

輝度から凸凹具合を求める

バンプマップを生成するためには、ピクセルの箇所がフラットなのか傾いているのかを調べる必要があります。ピクセルの近傍の輝度を調べることでそれがわかります。これには Sobel Filter というものを使用します。Soble Filter を使うと、左右上下のピクセルを見て、輝度が変化している箇所を抽出することができます。この部分がバンプマップの凸凹部分となります。

int w = texture.width;
int h = texture.height;
for (int y=0; y<h; y++) {
  for (int x=0; x<w; x++) {
    float topLeft = Luminance (texture.GetPixel(Clamp(x-1,w),Clamp(y-1,h)));
    float top = Luminance (texture.GetPixel(x,Clamp(y-1,h)));
    float topRight = Luminance (texture.GetPixel(Clamp(x+1,w),Clamp(y-1,h)));
    float left = Luminance (texture.GetPixel(Clamp(x-1,w),h));
    float right = Luminance (texture.GetPixel(Clamp(x+1,w),h));
    float bottomLeft = Luminance (texture.GetPixel(Clamp(x-1,w),Clamp(y+1,h)));
    float bottom = Luminance (texture.GetPixel(x,Clamp(y+1,h)));
    float bottomRight = Luminance (texture.GetPixel(Clamp(x+1,w),Clamp(y+1,h)));

    float dx = (topLeft + 2.0f * left + bottomLeft) - (topRight + 2.0f * right + bottomRight);
    float dy = (topLeft + 2.0f * top + topRight) - (bottomLeft + 2.0f * bottom + bottomRight);
    float dz = 1.0f / strength;
    Vector3 vec = new Vector3 (dx, dy, dz);
    vec.Normalize ();
    bumpMap.SetPixel (x, y, new Color(
      VectorValueToRgbValue(vec.x), 
      VectorValueToRgbValue(vec.y), 
      VectorValueToRgbValue(vec.z)));
  }
}
bumpMap.Apply ();

スクリーンショット 2017-10-01 12.31.10.png
いい感じに凸凹具合が現れました。

白黒だとこんな感じ。
スクリーンショット 2017-10-01 11.50.18.png

色を変えてみる

いろいろ色を変えてみると楽しいです。

Movie: http://hogehogeman.tumblr.com/post/165930354941

スクリーンショット 2017-10-01 20.43.28.png
Movie: http://hogehogeman.tumblr.com/post/165930363832

スクリーンショット 2017-10-01 20.43.43.png
Movie: http://hogehogeman.tumblr.com/post/165930369452

Tips

見せたいオブジェクトを中心に置いてシーンを撮影する際、オブジェクト以外の背景がUnityのデフォルトの状態から、ちょっと工夫すると非常に見栄えが変わります。

デフォルトだとこんな感じ
スクリーンショット 2017-10-01 21.03.41.png

今回やったことは
- スカイボックスをNoneにする
- PostProcessにてBloomとVignetteを追加する
- カメラの位置と角度を調節する
- ライトを追加、調整していい感じにする

これだけでいい感じの絵になります。