rn.log

備忘録など

【シェーダーグラフメモ その41】流れるLEDライトのような表現を作る

はじめに

シェーダーグラフを利用して、流れるLEDライトのようなものを作る方法を解説します。

f:id:r-ngtm:20190113134141g:plain


サンプル

github.com

 

解説

今回の表現ですが、3枚の板を組み合わせて作っています。

f:id:r-ngtm:20190113134744g:plain

ノード全体

f:id:r-ngtm:20190113155354p:plain

作り方解説

準備: 板を作る

以下のような板を作り、 

f:id:r-ngtm:20190113142016p:plain

 

シェーダーグラフから作成したマテリアルを板に登録しておきます

f:id:r-ngtm:20190113142220p:plain

シェーダーグラフから作成したマテリアルを登録しておく

 

STEP1: 円を並べる

f:id:r-ngtm:20190113135455p:plain

 

UVに8を乗算します。

これにFractionを適用してEllipseノードのUVとして使用します。

f:id:r-ngtm:20190113135839p:plain

 

STEP2 : 円とグラデーションを乗算する

f:id:r-ngtm:20190113140639p:plain

 

UVにPosterizeノード(Steps = 8) を適用し、x成分を取り出してSTEP1の円と乗算します。

f:id:r-ngtm:20190113140714p:plain

 

STEP3 : グラデーションを動かす

f:id:r-ngtm:20190113141324g:plain

 

X座標から時間を減算し、Fractionをかけるとグラデーションがスクロールするようになります。

f:id:r-ngtm:20190113141500p:plain

 

STEP4 : 板を3倍に引き延ばす

板のx方向のスケールを3に設定します。

f:id:r-ngtm:20190113142557p:plain

当然ですが、円も引き延ばされてしまいました。

 

STEP5 : 模様を1/3倍に縮小する

x方向に3倍に引き延ばされた円を1/3倍に縮小するため、UVのx座標を3倍します。

f:id:r-ngtm:20190113142838p:plain

f:id:r-ngtm:20190113144232p:plain

STEP6 : 色を付ける(シェーダーグラフ完成)

模様に色を付けます。

f:id:r-ngtm:20190113145211g:plain

 

f:id:r-ngtm:20190113144822p:plain

 

板を正三角形のように並べれば今回の表現の基礎の完成となります。

f:id:r-ngtm:20190113150447g:plain 

 

微調整

調整1 : グラデーションを2値化する

f:id:r-ngtm:20190113150251g:plain

 

グラデーションにStepをかけると、グラデーションがくっきりとした感じになります。

f:id:r-ngtm:20190113145536p:plain

 

調整2: 円の数を変更する

PosterizeノードとMultiplyノードの数値を変更することで、円の数を変更することができます。

先ほどは8を設定していましたが、24に設定すると以下のようになります。

f:id:r-ngtm:20190113150959g:plain

f:id:r-ngtm:20190113150809p:plain

 

 

Vector1などの定数はプロパティ化すると便利

Vector1ノードをプロパティ化すると、マテリアルのInspector上から変更できるようになるので便利です。

f:id:r-ngtm:20190113151937g:plain

 

f:id:r-ngtm:20190113151911g:plain



調整3 : LEDをランダムにずらす

f:id:r-ngtm:20190113152938g:plain

 

Y座標でノイズを生成し、X座標に足すことでグラデーションがランダムにズレます。

f:id:r-ngtm:20190113152744p:plain


調整4: ランダム値を調整

バラつきが大きすぎてうるさいので、

SimpleNoiseに数値を乗算して、スクロールのバラつきを調整します。

 

0.3を乗算した場合は以下のようになります。

f:id:r-ngtm:20190113153626p:plain

 

ノードは以下のように組んでいます。

f:id:r-ngtm:20190113153434p:plain

調整5 : 円の大きさを調整(調整終わり)

円の大きさが0.5だったものを、0.4に設定すると以下のようになります。

f:id:r-ngtm:20190113154904p:plain

 

ノードは以下のように組んでいます。

f:id:r-ngtm:20190113154801p:plain

 

【シェーダーグラフメモ その40】テクスチャを水玉パターンに加工する

 

はじめに

テクスチャを水玉パターンのような見た目に加工するシェーダーグラフの作り方を解説します。f:id:r-ngtm:20190111211722p:plain 

作り方解説

 STEP1 : モザイクをかける

Posterizeノードを利用して、テクスチャにモザイクをかけます。

今回はStepの部分に64を設定しました。

f:id:r-ngtm:20190111212405p:plain

 

64x64のドット絵のような見た目の絵が描画されます。

f:id:r-ngtm:20190111212533p:plain

 

STEP2 : 円を並べる

64倍したUVにFractionをかけ、0~1のUVを縦横64個並べます。

このUVを利用して円を描画すると縦横64個の円が並びます。

f:id:r-ngtm:20190111213353p:plain

 

STEP3 : テクスチャの色を円のサイズに利用する(完成)

テクスチャのRGBの平均値を円の大きさに利用します。

f:id:r-ngtm:20190111214104p:plain

 

 

以下のような水玉模様なテクスチャが描画されます。

f:id:r-ngtm:20190111214125p:plain

UnityのShaderGraphで音を作る

はじめに

ShaderGraphを利用して、サウンド合成をやってみました。

以下の動画は、ShaderGraphを使って実際に音を作っているところをキャプチャしたものです。

www.youtube.com

www.youtube.com

サンプル

github.com

サウンド合成までの流れ

f:id:r-ngtm:20190110220303p:plain

まずはテクスチャを用意し、これをShaderGraphで加工します。
そして、加工したテクスチャをOnAudioFIlterReadメソッド経由でオーディオデータに書き込み、音としてスピーカーから再生します。

OnAudioFilterReadについて

Unityのサウンド再生では、ゲームシーン内のAudioSourceが再生した音をAudioListenerが拾いスピーカーへ流します。
f:id:r-ngtm:20190111002131p:plain

OnAudioFilterReadメソッドを利用することで、AudioSourceからAudioListenerへのデータの流れに独自の処理を挟み、音を加工することができます。
例えば、自分でディレイエフェクトを実装して音に反響を付けたり、ローパスフィルターを実装して音の高周波成分を削ったり・・・

Unity公式リファレンス

Unity公式リファレンスにも解説やサンプルが載っています。
docs.unity3d.com

OnAudioFilterReadの利用例 : ディレイエフェクト

ディレイエフェクトの実装例が載っている記事
qiita.com

実装

STEP1. ソースコード

実装自体は以下のソースコードで完結します。

using UnityEngine;
using Random = System.Random;

[RequireComponent(typeof(AudioSource))]
public class SoundShader : MonoBehaviour
{
    const int Width = 128; // texture width
    const int Height = 64; // texture height

    [SerializeField, Range(0f, 1f)] private float soundVolume = 0.05f;
    [SerializeField] private Material soundMaterial; // Material for audio synthesis
    RenderTexture soundRT; // シェーダーで加工した結果を保持するためのRenderTexture
    Texture2D soundTexture; 
    float[] textureBuffer; // オーディオに渡すためのデータ
    int bufferReadPos = 0; // データの読み取り位置

    void Start()
    {
        soundRT = new RenderTexture(Width, Height, 0);
        soundRT.Create();
        textureBuffer = new float[soundRT.width * soundRT.height];
        soundTexture = new Texture2D(soundRT.width, soundRT.height);
    }

    void Update()
    {
        UpdateBuffer();
    }
    
    private void UpdateBuffer()
    {
        // シェーダーでテクスチャを加工し、結果をsoundRTに保存
        Graphics.Blit(soundRT, soundRT, soundMaterial, 0);

        // RenderTextureはそのままではピクセルにアクセスできないのでTexture2Dに変換
        RenderTexture.active = soundRT;
        soundTexture.ReadPixels(new Rect(0, 0, Width, Height), 0, 0); // RenderTexture -> Texture2D

        // Texture2D -> float[]
        // Texture2D.GetPixel()をOnAudioFilterRead()の中で使うと怒られるので注意
        int dst = 0;
        for (int y = 0; y < soundRT.height; y++)
        {
            for (int x = 0; x < soundRT.width; x++)
            {
                // とりあえず、テクスチャのrチャンネルをオーディオに渡す
                textureBuffer[dst++] = soundTexture.GetPixel(x, y).r * 2f - 1f; // [0:1] -> [-1:1]
            }
        }
    }

    void OnDestroy()
    {
        soundRT.Release();
        DestroyImmediate(soundTexture);
    }
    
    void OnAudioFilterRead(float[] data, int channels)
    {
        int dst = 0;
        while (dst < data.Length)
        {
            float value = textureBuffer[bufferReadPos] * soundVolume;
            for (int i = 0; i < channels; i++)
            {
                data[dst + i] = value; // write
            }

            dst += channels;
            bufferReadPos ++;
            if (bufferReadPos == textureBuffer.Length)
            {
                bufferReadPos = 0;
            }
        }
    }
}


STEP2. シェーダーグラフを作る

今回は以下のようなノイズを出力するシェーダーグラフを作ってみます。
f:id:r-ngtm:20190111002723p:plain

STEP3. マテリアル作成

シェーダーグラフを右クリックしてマテリアル作成します f:id:r-ngtm:20190111002952p:plain

STEP4. マテリアル登録

適当なオブジェクトにSTEP1.のコンポーネント(SoundShader)をアタッチし、STEP3のマテリアルを登録します
f:id:r-ngtm:20190111003218p:plain

STEP5 ゲーム再生(完成)

ゲームを再生すると、ノイズのような音が再生されます。

Ryoji.Ikeda 風のノイズを作って遊んでみた

ノイズを作って遊んでみました。
www.youtube.com

ノード全体

f:id:r-ngtm:20190111004840p:plain

【シェーダーグラフメモ その39】ランダムな斜線パターン

 

 はじめに

以下のような模様を出力するシェーダーグラフの作り方を解説します。

f:id:r-ngtm:20190109000045p:plain

 

サンプル

github.com

 

シェーダーグラフ全体

f:id:r-ngtm:20190109000632p:plain

作り方解説

STEP1 : ランダムな白黒ドットを作る

UVPosterizeをかけて解像度を下げます。

これにSimpleNoiseを適用してモザイク模様を作り、Stepをかけて2値化します。

f:id:r-ngtm:20190108235040p:plain

f:id:r-ngtm:20190109000243p:plain


 

 

STEP2 : 2種類の斜線パターンを作る

f:id:r-ngtm:20190108234629p:plain

 

STEP3 : 白黒ドットを使って斜線パターンを混ぜる

STEP1で作成した白黒ドットを使い、STEP2で作った斜線パターンを混ぜます。

f:id:r-ngtm:20190108235616p:plain

f:id:r-ngtm:20190108235712p:plain

 

STEP4 : マス目の数を12に設定(完成)

マス目の数を12に設定して完成です。

f:id:r-ngtm:20190108235854p:plain

f:id:r-ngtm:20190109000045p:plain

 

 

【Unityシェーダーグラフ+Processing その3】 ランダムに円弧を敷き詰めて色を付けてみた

初めに

ProcessingとUnityのシェーダーグラフを組み合わせて、以下のような絵を作ってみました。

f:id:r-ngtm:20190108101745p:plain:w320
Processing+シェーダーグラフで作った絵

今回の記事では、この絵の作り方を解説します。

目次

解説

Processing

Processing側で円弧をランダムに大量に並べます。

f:id:r-ngtm:20190108102142p:plain:w320
Processingで描画したテクスチャ

シェーダーグラフ

これをUnityのシェーダーグラフに取り込んで色を付けて完成となります。

f:id:r-ngtm:20190108101745p:plain:w320
シェーダーグラフで色を付けたもの

作り方

STEP1 : Processingで絵を描く

f:id:r-ngtm:20190108102142p:plain:w256
Processingで描画する絵


以下のコードを実行すると、pdeファイルと同じ場所にpngとして絵が出力されます。

final boolean isSave = true; // save as png
final int N = 5000; // arc number
final int lineSize = 5; // arc line size
final float radiusMin = 10; 
final float radiusMax = 400;
float arcRange = radians(100); 

String getPngName()
{
  return "arc_"
    + "_N_" + N
    + "_lineSize_" + lineSize
    + "_radiusMin_" + radiusMin
    + "_radiusMax_" + radiusMax
    + "_arcRange_" + arcRange
    + ".png";
}


void setup()
{
    size(1024, 1024);
    background(255);
    strokeWeight(lineSize);
    strokeCap(RECT);
    noFill();

    // draw arc
    for (int i = 0; i < N; ++i) 
    {
        stroke(random(1, 255));
        drawArc();
    }
    
    if (isSave)
    {
      save(getPngName()); // save as png
    }
}

void drawArc()
{
    float x = width / 2;
    float y = height / 2;
    float r = random(radiusMin, radiusMax);
    float size = r * 2;
    float radian1 = random(0, 2 * PI);
    float radian2 = radian1 + arcRange;

    arc(x, y, size, size, radian1, radian2);
}


f:id:r-ngtm:20190108212737p:plain:w300
Processingによって出力されたpng

出力されたpngをUnityプロジェクトに取り込んだら、シェーダーグラフ上での作業に入ります。

STEP2 : シェーダーグラフで加工する(完成)

以下のようなシェーダーグラフを組みます。
f:id:r-ngtm:20190108212131p:plain


以下のような絵が出力されます。

f:id:r-ngtm:20190108101745p:plain:w512
シェーダーグラフで加工した結果

【Unityシェーダーグラフ+Processing その2】ランダムウォークを利用して雷の球っぽいものを作る

ProcessingとUnityシェーダーグラフを組み合わせて、雷の球っぽいものを作る方法を解説します。
f:id:r-ngtm:20190105202714p:plain:w512

目次

作り方解説

STEP1 : Processingでランダムウォークを描画

f:id:r-ngtm:20190105203013p:plain:w320
Processingで描画するテクスチャ

Processing上で下記のコードを実行すると、pdeファイルがある場所と同じ階層にpngとして絵を出力します。

final boolean isSave = true; // save as png

final int N = 5000; // random walk number
final int alpha = 15; // line alpha

// random walk parameter
final float startRadius = 45;
final float addRadius = 45;
final float degreeRandom = 180;
final float radianRandom = radians(degreeRandom); // degree -> radian

// save file name
String getFileName()
{
  return "randomWalkSpread_"
    + "_N_" + N 
    + "_Alpha_" + alpha 
    + "_StartRadius_" + startRadius 
    + "_AddRadius_" + addRadius
    + "_DegreeRandom_" + degreeRandom
    + ".png";
}

void setup()
{
  size(1024, 1024);
  background(255);
  stroke(0, alpha);
  
  for (int i = 0; i < N; i++)
  {
    drawLine(); // draw random walk line
  }
  
  fill(0, 255);
  ellipse(width/2, height/2, startRadius * 2, startRadius * 2);
  
  if (isSave)
  {
    save(getFileName()); // save as png
  }
    
}

// draw random walk line
void drawLine()
{
  float x1, y1;
  float x2, y2;
  x2 = width / 2;
  y2 = height / 2;
  
  float baseRadian = random(0, 2 * PI);
  x2 += startRadius * cos(baseRadian);
  y2 += startRadius * sin(baseRadian);
  while (dist(width/2, height/2, x2, y2) < width)
  {
    float radian = baseRadian + radianRandom * random(-0.5, 0.5);
    x1 = x2;
    y1 = y2;    
    x2 += addRadius * cos(radian);
    y2 += addRadius * sin(radian);
    
    line(x1, y1, x2, y2);
  }
}

f:id:r-ngtm:20190105203510p:plain:w512

コードの軽い解説

コードでやっていることは、
「画面中央から画面の外側へ向かって点をランダムに動かし、その軌跡を描画する」
これを5000回繰り返しています。

Processingが出力したpngをUnityプロジェクトに取り込んだら、シェーダーグラフ上の作業に移ります。

STEP2 : シェーダーグラフで加工する(完成)

SampleTexture2Dノードでテクスチャを取り込み、Smoothstepで明暗のコントラストを補正します。
OneMinusノードで明暗を反転、Powerノードで色味を補正、最後にSampleGradientノードで色を付けます。
f:id:r-ngtm:20190105204210p:plain

上記のシェーダーグラフを組むと、以下のような絵が出力されます。
f:id:r-ngtm:20190105202714p:plain:w320

【Unityシェーダーグラフ+Processing その1】線をたくさん出して色を付けてみた

はじめに

最近、Processingを触りはじめました。

https://processing.org/


「Processingを使って何か面白いことはできないだろうか?」と考えていたところ、

「Unityのシェーダーグラフと組み合わせれば面白いことできそうじゃない?」

と思いつきました。  

Processingで作った絵をシェーダーグラフで加工してみた

そこで、Processingで描画した以下の絵を引っ張り出してきて、

f:id:r-ngtm:20190104233418p:plain:w320
 
Unityシェーダーグラフに取り込み、SampleGradientで色を付けてみました。
 

そして出来上がった絵が以下になります。
f:id:r-ngtm:20190104233731p:plain:w320

お、いろいろ遊べそう。

 

前置きが長くなってしまいましたが、今回の記事ではこの絵を作る方法を解説します。

 

作り方解説

STEP1 Processingで絵を描く

以下のコードをProcessingで実行します。

final int N = 15000; // line number
final int alpha = 15;

String getFileName()
{
  return "lines" + "_N_" + N + "_alpha_" + alpha +".png";
}

void setup()
{
  size(1024, 1024);
  background(255);
  stroke(0, alpha);
  for (int i = 0; i < N; i++)
  {
    drawLine();
  }
  
  save(getFileName());
}

void drawLine()
{
  line(random(0, width), random(0, height), random(0, width), random(0, height));
}

やっていることはシンプルで、
「キャンバス上でランダムな位置の点を2か所とり、2点を結ぶ線を描画する」
これを15000回繰り返しているだけです

上記のコードをProcessing上で実行すると以下のような絵が出力され、pdeファイルと同じ場所にpngとして保存されます
f:id:r-ngtm:20190104233418p:plain:w320


f:id:r-ngtm:20190104234520p:plain


出力されたpngをUnityプロジェクトに取り込んだら、次にUnity上でのシェーダーグラフ上での作業に入ります。

STEP2 : シェーダーグラフで加工する(完成)

SampleTexture2Dノードでテクスチャを取り込み、Smoothstepで色味を補正。
最後にSampleGradientノードで色をつけて完成です。
f:id:r-ngtm:20190104235327p:plain

f:id:r-ngtm:20190104233731p:plain:w320

色を変えて遊んでみた。

SampleGradientの色を変更すると絵の色も変化します。
色を弄っているだけでもいろいろ遊べそうです。

f:id:r-ngtm:20190105000637p:plain:w300
f:id:r-ngtm:20190105000145p:plain:w320


f:id:r-ngtm:20190105000239p:plain:w280
f:id:r-ngtm:20190105000347p:plain:w280
f:id:r-ngtm:20190105001153p:plain:w280
f:id:r-ngtm:20190105001431p:plain:w280
f:id:r-ngtm:20190105001553p:plain:w280