SubstanceDesignerで関数を使うためのちょっといい話

初めに

本テキストではSubstanceDesigner(以下SD)で関数を使う場合の足掛かりとしての情報をまとめています。

すでにSDを使っており基本的な操作ができ関数を使ってみたい方向けです。

本テキストは個人的に検証した情報をまとめているものでありSubstanceDesignerの開発元であるAllegorithmicの公式の情報を紹介しているものではありません。そのため内容に誤謬がある可能性があります。

本テキストを使用した場合に発生する事態のいかなる責任も負いかねますのでご了承ください。

Allegorithmic社について

SDに関しての公式の情報はAllegorithmic社が提供しているドキュメントやチュートリアルを確認することをお勧めします。

Allegorithmic社公式サイト
https://www.allegorithmic.com/

SubstanceDesignerはAllegorithmic社の登録商標です。

SDで関数で関数を使うために知っておきたいこと

パラメータ

各ノードにはさまざまなパラメータがあります。

これらのパラメータを使って位置を変えたり、色を変えたり、角度を変えたりできますよね

各パラメータは一つの数値だけでなくいくつかの値をもっていることが多いです。

SDで関数を使う場合は関数内でパラメータの値を扱うことがほとんどかと思います。

つまりパラメータを関数で使う際の方法を知る必要があります。

パラメータの値の種類

パラメータの値には大きく分けて3つの種類があります。この種類のことを値の型(SDのノードの場合は変数の型と呼んだ方が正しいかもしれません)などと呼びます。

  • Float 小数点のある数値
  • Integer 小数点の無いちょっきりな数値(つまり整数)
  • Boolean スイッチのようなどちらかを選ぶような値(TrueとFalse)

これを踏まえたうえでパラメータをどの型に見分けられるのかをまとめてみたのが以下です。

  • Float1 パラメータの項目が1つで小数点のある数値をつかっている
  • Float2 パラメータの項目が2つで小数点のある数値をつかっている
  • Float3 パラメータの項目が3つで小数点のある数値をつかっている
  • Float4 パラメータの項目が4つで小数点のある数値をつかっている
  • Integer1 パラメータの項目が1つで整数をつかっている
  • Integer2 パラメータの項目が2つで整数をつかっている
  • Integer3 パラメータの項目が3つで整数をつかっている
  • Integer4 パラメータの項目が4つで整数をつかっている
  • Boolean パラメータの項目が切り替えの時

値の例

Colorは?

例えばColorはどの型になるでしょうか?Colorにはグレースケールと三原色カラーがあります。

グレースケールの場合はFloat1として扱います。グレースケールは黒の値しかありませんので1項目ですよね。ですのでFloat1です。

それではカラーはどうでしょうか?カラーは光の三原色である赤・緑・青の三要素で定義できます。ですのでFloat3と思いきや、実はFloat4です。カラーには赤・緑・青のほかにアルファチャンネルの存在があります。
赤・緑・青・アルファの4項目になるのでFloat4です。

※アルファがない場合のRGBカラーはFloat3で処理できます。
※Color関係の項目は表面上整数値に見えますが内部的にはFloatで動いているようです

ColorModeは?

いくつかのノードではフルカラーとグレースケールを切り替えることができます。

このスイッチのようなパラメータの場合はBooleanを使います。

基本的にSDでは切り替え項目は2つになっており、3つや4つの選択肢があるスイッチパラメータはありません。

Booleanの値との対応はパラメータの左側の項目がTrueで右側の項目がFalseになります。

確認方法は?

あまり多くの種類の型ではないため値を見ればほとんどの場合判別ができるかと思います。

解らなくなった場合はパラメータをエクスポーズするとInputParametersタブで値の型を確認することができます。

またEmptyFunctionを作ってみてEditすると必要な入力値の型が左下に表示されています。そこで確認してみてもいいかもしれません。

さらに関数の処理結果の出力はそのパラメータの型でなければ関数のOutputにすることができないので間違ってしまうことはほとんどないと思います。

関数でつかえるノードについて

Float系、Integer系ノード、Boolean系ノード

先にも説明した通りSDでは大まかに3つの値の型があります。

Floatは小数点、Integerは整数、BooleanはTrue、Falseのどちらかを扱います。

SDのパラメータの多くはFloatなので関数を作る時はFloatの方が出番が多いかと思います。

しかしIntegerは単純増減、Booleanは処理の切り替えなどに使う重要な役目があります。

Constant系ノード(Constant Nodes)

例えばFloatノードをグラフエリアに入れるとノードには”Constant/Float”と表示されます。Constantはプログラミング上では「定数」を表します。変化しない値(関数実行時に変化しないという意味で値は自由に設定できます)のことです。

これは関数内で任意の値を扱うときに使います。

Constant系ノードは以下の種類があります。

  • Float 
  • Float2
  • Float3
  • Float4
  • Integer
  • Integer2
  • Integer3
  • Integer4
  • Boolean
  • String

Get系ノード(Variables nodes)

Float系、Integer系、Boolean系にはそれぞれGet系ノードがあります。Getという名前からわかる通り値を取得するノードです。

SDではInputParametersにて任意のパラメータを作ることができます。このパラメータを関数で使うために使うのがGet系ノードです。

つまり値の入り口ですね。

組み込み変数を使うときもその変数に対応した型のGet系ノードを使います。

Get系ノードは以下の種類があります。

  • Get Float 
  • Get Float2
  • Get Float3
  • Get Float4
  • Get Integer
  • Get Integer2
  • Get Integer3
  • Get Integer4
  • Get Boolean
  • Get String

Swizzle系ノード(Swizzle nodes)

基本的に関数内では同じ種類の型でなければ計算することができません。

integerとFloatは混ぜられませんし、Float1とFloat4を混ぜることもできません。

しかしそれだと値を扱うのに不都合な場合があります。

例えばFloat2のYだけを扱いたい場合やFloat4のXとWだけを扱いたい場合などです。

この時に活躍するのがSwizzle系ノードです。

Swizzle系ノードは使いたい値だけを抽出することができます。またXをYとして扱ったり、WをZとして扱うなどの「あべこべ繋ぎ」をすることもできます。

  • 1つの値だけ抽出したいときはSwizzle Float1、Swizzle Integer1
  • 2つの値を抽出したいときはSwizzle Float2、Swizzle Integer2
  • 3つの値を抽出したいときはSwizzle Float3、Swizzle Integer3
  • 4つの値を「あべこべ繋ぎ」にしたい場合はSwizzle Float4、Swizzle Integer4

To系ノード(Cast nodes)

先ほど説明した通り関数内では同じ種類の型でなければ計算できません。

SwizzleではFloat1と、Float4の値を分解して計算することができるようになりますが、 FloatとIntegerなどの型の種別が違うものではSwizzleで分解しても計算できません。

しかしFloatとIntegerで計算したい場合があるはずです。この時にTo系ノードを使います。

このノードはプログラミングでいうところのキャスト、型の変換をするノードです。

Float4をInteger4にしたり、Integer3をFloat3にしたりできます。

To系ノードとSwizzle系ノードを連携させて使うことで任意の値を計算させることが可能になります。

To系ノードには以下の種類があります。

  • To Float
  • To Float2
  • To Float3
  • To Float4
  • To Integer
  • To Integer2
  • To Integer3
  • To Integer4

※To Booleanノードは用意されておらず、プリセット関数としてBoolean to Flaot1が存在しています。

Vector系ノード(Vector nodes)

Swizzle系ノードが分解するノードならVector系ノードは合体させるノードです。

例えば計算過程でFloat4をSwizzle系ノードでFloat1に分解したとします。

しかしOuputの型はFloat4だとしたら、値を合体させてFloat4にしなくてはなりません。

そんな時にVector系ノードが役に立ちます。

Vector系ノードには以下の種類があります。

  • Vector Float2
  • Vector Float3
  • Vector Float4
  • Vector Integer2
  • Vector Integer3
  • Vector Integer4

演算子ノード(Operator nodes)

関数内で値の計算を行うときに使うノードです。

  • Add 足し算
  • Subtraction 引き算
  • Multiplication 掛け算
  • ScalarMultiplication ベクトルのスカラ倍
  • Division 割り算
  • Modulo 剰余計算(余り)
  • Negation マイナス変換
  • DotProduct 内積計算

これらのノードでさまざまな計算を行って値を加工していくことになります。四則計算は計算の根幹ですのできわめて重要なノードです。

また周期性のある処理にModulo、ベクトルの処理を行うためにScalarMultiplication、DotProductも多用することになるでしょう。

比較ノード(Comparison nodes)

値の比較を行って処理を分岐させたくなる場合があります。このとき比較ノードを使います。

いずれも比較の真偽でTrueかFalesを出力します。

後述する論理ノードとの組み合わせ、またIf…Elseノードとの組み合わせで多用することになります。

  • Equel 等しい(AとBが等しい時にTrue、等しくない時にFalseを出力)
  • NotEquel 等しくない(AとBが等しい時にFalse、等しくない時にTrueを出力)
  • Greater 以上(AがB以上の場合True、それ以外はFalseを出力)
  • Greater or Equel 以上か等しい(AがB以上か等しい場合True、それ以外はFalseを出力)
  • Lower 未満(AがB未満の場合True、それ以外はFalseを出力)
  • Lower or Equel 以下(AがB以下の場合True、それ以外はFalseを出力)

論理ノード(Logical nodes)

関数内で条件の真偽が必要になる場合があります。この場合に使うのが論理ノードです。比較ノードや後述するIfElseノードとの組み合わせで使われる場合が多いです。

  • And どちらもTrueならTrueを出力、それ以外はFalseを出力
  • Or どちらかがTrueもしくはどちらもTrueならTrueを出力、それ以外はFalseを出力(つまりどちらもFalseならFalseを出力)
  • Not 入力がTrueならFalseを、FalseならTrueを出力

関数ノード(Function nodes)

値に対して丸め等を行ったり、三角関数で値を求めたりするときに使うノードです。

  • Absolute 絶対値
  • Floor 小数点以下切り捨て
  • Ceil 小数点以下切り上げ
  • Random ランダムな値を出力
  • Cosine コサイン
  • Sine サイン
  • Tangent タンジェント
  • ArcTangent2 アークタンジェント2
  • Logarithmic 対数
  • Exponential 指数
  • Cartesian デカルト座標
  • Exponential 指数
  • SquareRoot 平方根
  • Max 最大値
  • Min 最小値
  • LinerInterpolation 線形補完
  • Pow2 二乗

三角関数系のノードは座標計算に極めて重要なノードです。また値の丸め系ノードも値の加工に大変便利です。便利なノードがいろいろ用意されています。

制御ノード(Control nodes)

ノードの処理進行の分岐を行うためのノードです。

  • If…Else Booleanによる処理の分岐
  • Sequence 関数内変数を出力する場合に使用

    SDの関数にはfor構文等のループがないためIf…Elseは極めて重要になります。

Samplerノード(Sampler nodes)

処理上でインプット画像のピクセルの色情報を取得する場合に使います。フィルタ系など画像に対してなんらかの加工を行う関数では必須のノードです。

カラーとグレースケール用が用意されています。

  • SampleGray グレイスケール用のサンプラー
  • SampleColor カラー用のサンプラー

関数内にパラメータを引き込む

パラメータをより理解するためにノードの構造を知っておきましょう。

アトミックノードとインスタンスノード

アトミックノード

アトミックノードはそれ以上分解できないハードコードなノードです。

アトミックノードの場合、BaseParametersSpecificParametersという分類のパラメータがあります。

Base Parametersはサイズやタイリングなどに関する基本的でほぼすべてのノードで共通のパラメータです。

Specific Parametersはそのノードに固有のパラメータです。多くの場合このSpecificParametersを使用することになります。

インスタンスノード

アトミックノード以外のSDのライブラリ等にに入っているノードはすべてアトミックノード(と関数)の組み合わせでできているノードです。

これらのノードはインスタンスノードと呼ばれています。

インスタンスノードの場合、BaseParametersとInstanceParametersという分類のパラメータがあります。

Base Parametersは先ほどの説明と同じで、InstanceParametersはアトミックノードで言うところのSpecificParametersとほぼ同じものです。

違うのはこのInstance Parametersは既存のノードのパラメータをExposeしたか、InputParameters機能によって作られたパラメータであるという点です。(この点は後述します)

インスタンスノードは編集はできませんが、その構造を確認することが可能です。

例えばSlopeBlurノードの中身をのぞいてみましょう。

ノードを右クリックしてOpenReferenceを選択します。編集の確認のダイアログが表示されるのでOKをクリックするとSlopeBlurノードがどのようなアトミックノードや関数から作成されているかが確認できます。

SlopeBlurノードは大量のWarpノードとBlendeノード、またそれらのノードのパラメータに関数を設定して作られていることがわかります。

Blendeノードを確認してみるとOpacityとBlendeingModeに関数が設定されていることがわかります。その関数内ではSamplesというパラメータを取得して値の計算をしていることがわかります。

SlopeBlurノードのグラフルートに戻ってInputParametersパネルを確認してみると確かにSamplesパラメータが作成されており初期値は8になっています。

これは今後自作のノードを作る際の仕組みと何ら変わりはありません。いろいろなノードの構造を確認するとより理解が深まるのではないかと思います。

パラメータを自由に扱いたい

ノードのパラメータは普通スライダーなどで動かせるようになっています。それは各ノードに張り付いていますのでそのパラメータを操作するにはそのノードのそのパネルに行かなくてはなりません。

しかし時にはノードにパラメータが張り付いているのが面倒な時があります。フレキシブルにパラメータ値を変更したい場合などはどこかで一括してパラメータを操作できた方が楽ですよね。

ですのでSDではノードからパラメータを分離させることができます。つまりパラメータを「扱える場所」を
各ノードのパネル以外に作れる
のです。

そしてそのパラメータは変数として関数内で使うことも可能になります。

Expose

パラメータはExposeすることで簡単に分離させることができます。

ExposeするとそのパラメータはグラフルートのInputParametersパネルへ管理が移動します。

関数内で値を加工する必要のない値などは直接ExposeしてInputParametersパネルへ持っていくことで扱えるようになります

パラメータを自由に作る

グラフルートのInputParametersパネルで新しいパラメータを作ることができます。

基本的にはSDで関数を使う場合ここでパラメータを作ることが多くなるかと思います。

ここで誤解の無いようにしたいのですが、InputParametersで作成するパラメータは「パラメータそのもの」を作るのではなく「パラメータインターフェース」を作るということです。

ここで作られたばかりのパラメータはどのノードのパラメータとも接続されているわけではなくただパラメータの空箱のような状態なのです。

これはプログラミング的にいうと数値を入れられる変数とその変数を操作する操作盤を作るみたいなものです。

作った「パラメータインターフェース」から送られる数値を各ノードの各パラメータの関数に入力することで、そのパラメータと接続されることになります。

後述するノードの説明でも触れますがGet系ノードが「パラメータを取ってくる」役目を行います。

グラフのルートに作られらパラメータを任意のノードの任意のパラメータの関数内で取得することで、値を受け取り関数で加工して出力することが可能になります。

実際の操作に関しては実践編で後述します。

注意・値を扱う時はこんがらがりやすい

値はFloatにしてもIntegerにしてもX,Y,Z,Wで表せられますが、このX,Y,Z,Wで値を表すのは便宜的なもので、なんでもX,Y,Z,Wになります。例えば位置情報を扱っているときもX,Yですし、色を扱っているときでもX,Y,Z,Wです。

位置情報の場合はX,Yだけで表せますが、色の場合は例に挙げたようにRGBAの4つの値が存在ます。

色を扱うときはX=R、Y=G、Z=B、W=Aという風に対応するわけです。

自動的に値の名前に切り替わってくれるといいのですが、そうはなってくれないのでこれは頭の中で「このXはいま色情報のRの値が入っている…」と認識しないといけません。

後々見返す時のためにコメントなどで値を状況を分かりやすくするのも大切です。

組み込み変数

SDではいくつの変数(パラメータだと考えてもらってOKです)があらかじめ用意されています。いずれも非常に重要な値できわめて有用です。

種類は少ないので役割をしっかり覚えましょう。

$pos

$posは現在処理しているピクセルの位置情報が入っています。値はFloat2でUV座標と考えるといいかもしれません。

この変数はとても重要です。Fx-mapでもPixel Processorでも使えるうえに「ピクセル数分の繰り返し」処理には必須です。

$posはテクスチャのサイズにかかわらず常に0~1の値になります。つまり1ピクセル当たり$posが進む量は1/ピクセル数ということになります。
つまりたとえば2048px(2k)テクスチャの場合、1ピクセル当たりのは1/2048で0.00048828125となります。

XとYにそれぞれ2048ずつピクセル列があるわけですので全体のピクセル数は4194304となります。

実際のイメージはこうなります。座標のようにイメージするとよいかもしれません。

$posは0から始まるためX行一行目は(X,0)となります。

テクスチャサイズが2048pxの場合の$posがどのような値になっているか?

  • 最初のピクセルは(0,0)でX方向に次のピクセルは(0.00048828125,0)となります。
  • 2つめのピクセルは(0.0009765625,0)
  • 3つ目のピクセルは(0.00146484375,0)
  • ずっと進んで512コ目のピクセルは(0.25,0)になります。
  • さらに進んで1024コ目のピクセルは(0.5,0)になります。
  • そしてX行最後の2048コ目のピクセルは(1,0)となります。

イメージできましたでしょうか?

オフセット的な挙動

お気づきの方もいらっしゃるかと思いますが、例えば(0.5,0.5)とした場合それはテクスチャ画像の中央を表すことになります(つまりX方向に1024個目、Y方向に1024個目のピクセル)。

また(0.25,0.25)(0.25,0.75)(0.75,0.25)(0.75,0.75)はテクスチャ画像を4分割した場合のそれぞれ左上、左下、右上、右下の中央を表すことになります。

こう見るとピクセルの絶対数を扱うより相対で値を扱うほうがテクスチャサイズに対して柔軟に対応できることがわかるかと思います。

$size

$sizeは名前の通りテクスチャのサイズが格納されています。値はFloat2でテクスチャサイズがそれぞれX,Yに入っています。

2048px×2048pxならX=2048,Y=2048となります。

テクスチャサイズがわかると先ほど説明した$posをより柔軟に扱うことができます。

1/$sizeを計算すると$posのピクセル当たりの値を計算することができます。つまりピクセル位置の単位になりえるわけです。

$sizelog2

$sizelog2はテクスチャサイズを2の累乗で表したときの指数を取得できます。2048×2048の場合なら2048は2の11乗なので11が返ってきます。

この数字Absolut時のOutputSizeの数値と同じだと気が付いた方もいらっしゃるかもしれません。

関数実践編 PixelProcessorノードで画像を回転させてみる

PixelProcessorノード(以下PPノード)はピクセル処理に特化したノードです。Fx-mapも強力なノードですが、PPノードはFx-mapノードよりも柔軟な処理を行うことができます。

PPノードは入力された全ピクセルを対象に処理を行います。

PPノードではほぼ間違いなく処理に関数を使用することになるため関数に慣れるための題材としとは最適です。

処理としては単純にピクセル分関数が繰り返し実行されることになります。

例えば2048×2048であれば4194304回関数を実行します。

非常に繰り返しが多いように感じますが計算はほぼ一瞬で終わりますので負荷はほとんど気にしなくて大丈夫です(厳密には関数の状況によって負荷が高まりコストが高くなる計算になる可能性もあります)

それでは早速画像を加工していきましょう。

回転を実施するための画像を一枚用意してください。正方形の画像が好ましいです。大きさは任意ですがあまり大きくない方がいいでしょう。

回転させるとは?

回転の公式は以下のようになります。本テキストでは著者自身が数学に詳しくないこともあり、また本テキストの範囲外となるため公式の詳しい説明は割愛させていただきます。

もし必要であれば数学の該当する書籍(行列、ベクトル等)を参照してください。

回転の公式

原点を中心として(x,y)を(x',y')へ回転させる場合

x’=x cosθ – y sinθ
y’=x sinθ + y cosθ

この公式をノードで再現することになります。

処理のイメージ

GetFloat2で組み込み関数の$posを取得します。

$posは画像の左から右へ、上から下への順番でピクセルの座標を取得することができます。

取得した座標に加工を加えることで任意の場所の座標に変換させてあげることができます。

そして最終的にSamplerノードにて加工した座標を用いて、Input画像のピクセルの色情報を取得し左上から右下に向かって並べ直します。

今回は画像を回転させたいので回転先へInput画像から読み取ったピクセル色情報を配置させるということになります。

$posはあくまでもピクセル座標を順番に取得できるだけですし、最終的にOutputする際も順番にピクセルが出力されることになります。

「ピクセルを移動させる」というよりも、「移動先に入るピクセルを何らかの座標加工で取得して左上から右下の順に並べ直す」といったいめイメージがより近いかと思います。

この点は$posをつかった処理で少しイメージしにくい部分ですが、理解できるといろいろな処理を行えるようになります。

パラメータを準備する

今回は画像を回転させたいので回転させるための値が必要になります。そのためのパラメータを作成します。

グラフの何もないところをクリックしてInputParametersパネルにてプラスボタンを押しましょう。

そうするとinputというパラメータが一つできました。

いろいろ設定できる項目があります。順を追って確認していきます。

Identifier

グラフ内で一意の名前です。他のパラメータと名前が被ってはいけません。今回は”Rot”にしました。

Type/Editer

値の型と値を操作するためのインターフェスの形状を設定します。初期状態では型がFloat1でインターフェースはSliderになっています。今回はこのままでOKです。

ちなみにインターフェースは型ごとに若干違います。

  • Float1ではSlider、Angle、Color(GrayScale)
  • Float2ではSliderのみ
  • Float3ではSliderとColor(RGB)
  • Float1ではSlider、Tranceformation、Color(RGBA)
  • Integer1ではSlider、DropDownList
  • Integer2ではSlider、Size pow 2
  • Integer3ではSliderのみ
  • Integer4ではSliderのみ
  • BooleanではButtonsのみ
  • stringではTextのみ

使えるインターフェースからもどの型がどんなパラメータに対応しているかがわかってきますね。

Description

パラメータの説明です。他人にグラフを使ってもらうときにあると親切ですが今回はなくてOKです。

Label

パラメータの表示名です。ここで設定した名称で表示されることになります。ここも”Rot”でOKです。

Group

いくつかのパラメータが存在する場合にパラメータを分類させるためのパネル名称です。ここにグループ名を設定しておくと他のパラメータに同じグループ名を設定すればそれらのパラメータは同じパネルに分類されるのでパラメータが見やすくなります。ここは今は空白でOKです。

Defalt

初期値です。ノードを設置したときに最初から設定される値をここで指定します。0に設定してください。

Min/Max

値の最大値/最小値です。値がとれる範囲を限定できます。Minが0、Maxは1に設定しておいてください。

Clamp

値の固定のスイッチです。これはFalseのままでOKです。

Step

値の増減の単位を設定します、ここはとりあえず0.01にしてください。

UserDataおよびVisible If

UserDataには任意のインフォーメーションを記入できます。今回は空白のままでOKです。

Visible Ifは一定の条件においてパラメータを見える状態にするかどうかの設定です。条件式を記入することでパラメータの可視属性をコントロールすることができますが今回は空白でOKです。

ノードを組んでみる

さてそれでは実際にノードを組んでいきましょう。

まず回転させたい画像が必要です。Bitmapノードを設置し回したい画像を読み込みます。LinkにするかImportにするかは今回どちらでも大丈夫ですのでお好きな方法でOKです。

そしてPPノードを設置しBitmapノードの出力をPPノードのInputにつなげます。

PPノードのPerPixelFunctionのEditボタンを押してPPノードの関数編集画面に移行します。

実際に組んだノードはこのようになりました。

まずGetFloat2で組み込み変数の$posを取得しています。

$posを取得するにはGetFloat2のVariables/GetFloat2パネルのドロップダウンリストから$posを選択します。ここで選択できるパラメータはそのノードの型で規定されたパラメータのみが表示されます。

この変数は説明したとおり順次現在処理対象のピクセルの座標を出力してくれます。つまり座標を順繰り処理するために必要になります。

$posから受け取った座標はSineノードやCosineノードで計算する必要があるのでSwizleFloat1でX値とY値に分解します。

ここからは回転の公式を使って計算するためのノードです。

回転の公式は以下のようなものでした。

x’=x cosθ – y sinθ
y’=x sinθ + y cosθ

これは

X値とcosθをMultiplicationした結果から、Y値とSinθをMultiplicationした結果をSubtractionすることでX’の値を算出する
x値とsinθをMultiplicationした結果に、Y値とcosθをMultiplicationした結果をAddすることでY’の値を算出する

ということになります。

この部分を実際ノードで組んでみると以下のようになります。

作業の様子を動画にしましたのでこちらも参照してください。

計算のθは回転の角度で、今回はこのθを先ほど作ったRotパラメータから入力することになります。

cosθ sinθ がそれぞれ一つずつあればいいのですが、見た目でわかりやすさを優先したためcosθ sinθはそれぞれ2個ずつ用意しました。

効率を考えるならもちろん省略した方がいいのですが、将来的に何らかの計算を追加することが考えられる場合はできるだけ計算は別個で行っておくと値の切り分けがスムーズになることもあります。

上段部分のノードではcos×Rotの算出値にX値をMultiplicationした値からsin×Rotの算出値にy値をMultiplicationした値をSubtractionしています。

下段部分のノードではSin×Rotの算出値にX値をMultiplicationした値とcos×Rotの算出値にY値をMultiplicationした値をAddしています。

Multiplicationに関しては値をどちらのInputに挿しても結果は変わりませんが(9×3と3×9は同じになる理屈)、Subtractionの場合はノードの接続順で算出される値が異なります(9-3と3-9は違う答えになる理屈)ので注意が必要です。

SubtractionやDivisionなど計算順が結果にかかわるノードの場合は必ずノードInputのAとBの関係を把握しておきましょう。

この工程で算出された値は「処理対象のピクセルを原点を中心に回転させたときの座標値」でしたね。

ですのでこの座標値を使ってSampleColorノードで回転対象の画像からピクセルを取得して並べ替えます。

今回はカラー画像を想定していますが、グレースケールの場合はSampleGrayノードを使いますし、どちらをインプットしても処理を行えるようにするには比較ノードや論理ノード、If…Elseノードを使って処理を分岐させることもできます。

SamplerノードではFloat2をInputとして扱いますので算出した値はVectorFloat2でFloat2にまとめます。

まとまったFloat2をSampleColorノードのInputに挿します。

先ほども説明した通りSDの関数でピクセルを並べ直す場合は、「ピクセルを移動させる」というよりも、「移動先に入るピクセルを何らかの座標加工で取得して左上から右下の順に並べ直す」というイメージです。

Samplerノードはその処理をおこなうノードです。

この点はイメージしにくく直観的ではありませんがオフセット(ずらす)的に処理を行うことで相対的な値として扱えるのがSDの魅力でもありますのでなるべく理解するようにしましょう。

最後にSampleColorノードを最終的なOutputにしたいので、右クリックしてSet as Output Nodeを選択します。

これで画像を回転させる関数ができあがりました。

さて組んでみたノードで実際に画像を回転させてみてください。

グラフルートに戻りRotの値を変更すると回転するはずです。

パラメータとしての見た目にしたい場合はSwitch to the preview modeボタンを押すことで本来のパネルに表示させるパラメータの表示形式になります。

しかし回転するにはしましたが回転の中心が画像右上(0,0)の位置になっていますね。これはあまり好ましくないですね。

回転の中心を変更する

任意の位置を中心として回転させたい場合、回転の中心を計算する必要があります。

なにも仕組みを用意しない場合、回転の中心は左上つまり(0,0)になります。

多くの場合で画像中央を原点として回転させたいのではないかと思いますので原点を(0.5,0.5)にしたいですよね。

これは簡単で画像の中心である座標(0.5,0.5)を取得した座標からsubtractionし、回転の公式を計算しSamplerノードに座標を渡す直前で座標(0.5,0.5)を公式計算後の座標にaddすることで回転の中心を画像中央にすることが可能です。

SDの値は相対値であることが多いですのでこのようなオフセット的な考え方でノードを組むことが多くなるかと思います。

簡単にイメージするとずらして計算してもとに戻すといった感じの処理をしていることになります。

実際にそのようにして組んだノードが以下のようになります。

作業の様子を動画にしましたのでこちらも参照してください。

先ほどのノードよりも複雑にみえますが、単に座標をずらして計算して元に戻す処理を加えただけです。

2つのConstanceノードが増えています。

左の増えたノードは座標をずらすために必要なノードですね。これはFloat1を二つ用意してそれぞれXとYとして扱ってもかまいませんが、後々パラメータ化する可能性もあることからFloat2で取得できた方がいいかと思います。

このFloat2ノードではX=0.5、Y=0.5の値を設定しています。つまり画像の半分の幅だけずらす値ですね。

このノードをSwizleFloat1で分解して、それぞれ$posをSwizleFloat1で分解した座標値のXとYからSubtractionしています。これで$posから取得された値は上下に0.5ずつずれたことになります。

回転の計算部分に関しては変わっていません。

回転の計算をしたのちにずらした分の0.5を足してもとに戻しています。これでずれた状態を解消しています。

さらにVectorFloat2で値を合わせる直前に別な値をXとYに足していますね。

これは任意で画像の移動を行えるようにしました。

パラメータを増やしてより機能を増やす

この値とさきほど回転の原点を設定するために設置した値をパラメータ化してコントロールできるようにしましょう。

先にパラメータを作ります。

回転の原点パラメータのIdentifierとLabelは"RotationCenterCoordinates"に、画像を移動させるパラメータのIdentifierとLabelは"ImageOffset"にしてみました。

Defaltは"RotationCenterCoordinates"が0.5、0.5で"ImageOffset"は0、0です。

回転の原点を設定する値も画像を移動させる値も型はFloat2です。

インターフェースはSliderで良いでしょう。

また今回はパラメータが増えたので整理の意味合いも含めてGloupを設定してみましょう。

Rotと"ImageOffset"は変形のためのパラメータなのでTrancformationというグループにしましょう。

またこの際Rotではわかりにくくなるので"ImageRotation"にIdentifierとLabelを書き換えて意味を分かりやすくしておきましょう。

"RotationCenterCoordinates"は変化の中心のパラメータなので"RotationCentert"というグループにしてみます。

パラメータの順番も変えておきましょう。

"RotationCenterCoordinates"が上にあった方がいいと思いますので"RotationCenterCoordinates"パラメータを一番上に移動させます。

パラメータの左端部分をドラックすることで順番を変えることができます。

そのほかは初期値のままでOKです。

GetFloatノードの設置

パラメータができましたので、グラフのConstanceノードをGetFloatノードで置き換えます。

座標をずらすためのパラメータが"RotationCenterCoordinates"ですのでGetFloat2を設置してRotationCenterCoordinatesパラメータを設定し取得状態にしてグラフ右端にある0.5、0.5のFloat2ノードと差し替えます。

また画像を移動させるためのパラメータが"ImageOffset"ですので"ImageRotation"の隣にある0、0のFloat2ノードを、"ImageOffset"を取得状態にしたGetFloat2で差し替えます。

さてこれで回転の中心点を変える、画像を移動させるという機能を実装できました。

パラメータ確認

グラフルートに戻り実際のパラメータの見た目、挙動を確認してみましょう。

Switch to the preview modeを押してパラメータの見た目を確認してみてください。

ちゃんとグループ分けされており見やすくなっていますね。パラメータの名称もわかりやすくなりました。

SDに限らないことですが、再利用を多用するソフトウェアでは名称設定は非常に重要です。

1か月前に作ったものを正確に記憶できている人は稀有なはずです。

大抵なんの処理を行っていたのか、そのパラメータがなんなのかを忘れます。

そのときパラメータ名がデフォルトのinputのような場合いちいち確認しなくてはならなくなります。

非常に無駄な時間を費やすことになるので、未来の自分を楽させてあげられるように面倒でも名称設定はしっかり行っておきましょう。

そしてパラメータをいろいろ動かしてみてちゃんと機能するかどうかを確認してください。

ノードが間違っていなければちゃんと回転し中心を変えられ移動させられるノードになっているはずです。

補足 $posの挙動で重要なこと

$posから取得した値を加工した場合

便宜的に整数で説明しますが、例えば$posから取得した値が1ピクセルあたり1だった場合に、2を掛けたとします。

つまり取得した座標と加工した座標は以下のようになりますね。

(0,0) (0,0)
(1,0) (2,0)
(2,0) (4,0)
(3,0) (6,0)
(4,0) (8,0)
(5,0) (10,0)

2つのピクセル分の座標を抜かして座標が進んでいくことになります。こうして進めると加工した座標の方が先にXなりYなりの終端にたどり着くのが早くなりますよね。

もしテクスチャサイズが2048×2048の場合、本来Xのその行の終端にたどり着くには2048回の繰り返しが必要になるのですが、上記の加工した座標の場合2倍で進んでいるので1024回の繰り返しの時点でXのその行の終端にたどり着くことになります。

しかしPPノードはそんなことはお構いなくテクスチャの総ピクセル分の繰り返しを行います。

つまり加工して早く終端にたどりついた座標値もそこで処理が終わるわけではなく、もう一度最初の位置から座標を取得することになります。

1024回目の繰り返しで終端にたどり着いた座標はまだ1024分の繰り返しが残っているので、その行のXの始点の座標から再度取得していくことになります。

実際にノードを確認した方がわかりやすいかと思います。

このノード例は$posで取得した座標をSwizleで抽出してXとYそれぞれに係数を掛けています。先ほどの説明と同じく座標が設定した係数倍で進んでいくことになります。

例では係数を8にしてみました。

このノードを出力してみると画像がタイリングされました。それぞれXYとも8回繰り返し始点から終点に取得されたことを表しています。

この$posとPPノードの挙動は処理を考えるときに重要になってきますので是非理解してくださいね。

まとめ

本テキストは未完成です。Fx-mapノードやPPノードでの関数を活用した実際例を追加して更新していきます。

また質問や疑問などをいただけると記事にフィードバックできるかもしれません。

ブログのコメント欄はOFFにしているので、Twitterで問い合わせいただけると幸いです。

@MINO_8601

[Blender]辺や面の情報(長さ・角度・面積)を表示する

辺や面の情報

Blenderでは辺の長さや面の面積を表示させることが可能です。

長さや面積がわかると楽な場面もありますので、必要な時には表示させてみましょう。

Nキーでプロパティパネルを出すと、MeshDisplay(メッシュ表示)にEdgeInfo(辺情報)とFaceInfo(面情報)という項目があります。

いずれもEditモード(編集モード)にて動作します。

チェックボックスは以下のような意味になります。

Eage Info
Length Edgeの長さ
Angle 選択した2辺のなす角度

Face Info
Area 面積
Angle 面の内角のそれぞれの角度

モデリング時に目検討ではなく数値的に捉えられるのは重宝します。この数値表示でちょっきりに合わせるのは少し苦労しますが、移動回転縮小の時にShiftキーで詳細動作モードを併用すると小刻みに編集できます。

[Blender]法線を常に確認できるようにする

法線を確認する

法線を確認する場合はEditMode(編集モード)に入る必要があります。

Nキーでメニューを出して、MeshDisplayのNomalsを設定します。

Vertex(頂点)、Face(面)それぞれにON・OFFできるようになっています。線のようなものがVertexやFaceに表示されるかと思います。デフォルトではVertexの法線が濃い青Faceの法線が薄い青で表示されます。

Size(サイズ)は法線の長さです。値を大きくするとびょーんと長い法線が表示されます。Hairみたいですね。

法線を確認できると嬉しいことの例

法線が確認できていると裏返った面を発見しやすくなったり、法線方向になんらかの作業する場合に見当が付きやすくなります

裏返ったFace

例えばこちらは一か所だけ法線が裏返っていた場合。Faceの色でも見分けはつくかもしれませんが、法線表示させるとその部分だけ法線が逆を向いているのがわかります。Ctrl+Nで反転させて直すことができます。

Nomal軸の挙動確認

こちらはTransformOrientation(座標系)のNomalでの挙動がわかりやすくなる事例です。

モデリングなどでは法線方向にVertex、Faceを動かしたい場合がありますが、その際要素の法線がどの方向に向いているかがわかるので正確に編集することが可能になります。

見てもらうと分かります通り、TransformOrientationがGlobalの段階では法線と3DManipulator(3Dマニピュレータ)のZ軸の方向があっていないことがわかります。

しかしTransformOrientationをNomalに変更するとZ軸の方向が法線とそろいます

例えば移動を行うときはG→Z→Zで法線方向に(つまり3DManipulatorのZ軸)動かすことができます。G→ZだとGlobal方向になりますので注意です。

このように視認することができるのでなかなか便利です。

[Blender]VertexBevel-頂点をベベルする

VertexBevel

Blenderではモデリングの時にBevel(ベベル)を使うことができます。

Bevelとは斜面という意味になるそうで、文字通り斜面をつくる機能です。

通常は辺を選択してctrl+Bでべべります。こんなふうに(EdgeBevel)。

辺のあった場所に新たにFace(面)が挿入されたような感じで、色んな所で使いドコロマックスです。

ctrl+Bの後VキーでVertexモード

でもこのBevel、実はVertex(頂点)にも適用できるって知ってました?

Vertexを選んでctrl+Bでベベりますが、このままではべべれません。

ctrl+Bの後に、Vキーを押してください

これでBevel機能のVertexモードがONになります。

その状態でマウスを動かすと…、おおVertexがべベッてる!!Bevel中にマウスホイールを動かすことで分割ができるのもEdgeBevelの時と同じです。

ちなみにVertexを複数選択してVertexモードにて個別にBevelを適用することも可能ですよ。

機械とかのモデリング時にはこのVertexBevelすごく重宝するのではないかと思います。

ぜひお試しください。

[Blender]選択しているオブジェクトだけ表示して編集しやすくする

いくつかのオブジェクトを組み合わせてモデリングを進めていると、ほかのオブジェクトが邪魔で作業がしにくい時が結構あります。

かといって表示・非表示を切り替えするのも意外と面倒なものです。

そんなときはローカルモードを使いましょう。

テンキーの/(スラッシュ)を押すと、現在選択しているオブジェクトだけを表示するモードに切り替わります。

EditモードでもObjectモードでも挙動は同じです。

元の表示に戻したいときはもう一度テンキーのスラッシュを押せば、全体表示モードになります。

ローカルモードに入っている場合3Dビューの上部に以下のようにLocalの表記が出ます。

またローカルモードに入っている間はレイヤー欄は隠れます。

Hキーの非表示とともによく使う機能ですので、キーがちょっと遠いのが難点な気もしますが、ともかく編集すべきオブジェクトだけに集中できるのはいいですね。

[Blender]3Dカーソルを活用する基本編

3Dカーソルはとても使える奴です

Blenderを触り始めた当初は3Dカーソルに対してどういう感想をもっていたでしょうか?

なんか邪魔なやつだなと思っていたのではないでしょうか?

何も設定していないBlenderだとマウス左クリックで3Dカーソルが動くだけでオブジェクトを操作できないのもトラウマになったものですよね。

3Dカーソルの位置にプリミティブオブジェクトが生成されるので、オブジェクトが生える場所くらいの認識の人もいるかもしれません。

でもこの3Dカーソル、かなり使える奴なんですよ。

3Dカーソルの位置決めの基本

Locationで数値入力

3Dカーソルはプロパティシェルフの3DCursor(3Dカーソル)メニューのLocation(位置)で場所を数値入力することが可能です。

基本的にはこのパラメータで位置を操作することができます。

ちょっきりな位置に3Dカーソルを移動させオブジェクトを生やしたいときはここで設定するといいかと思います。

3Dカーソルを原点に戻す

またShift+C3Dカーソルは原点に戻ります。つまりX:0 Y:0 Z:0に戻ってくれます。

もし変なところに3Dカーソルが飛んでしまったら、 Shift+Cと覚えておけばとりあえず原点に戻ってくれるのであせらずに済みます。

Originを任意の場所に移動させるために3Dカーソルを使う

Shift+Ssnap(スナップ)メニューのショートカットですが、このショートカットの中に3Dカーソルを移動させるメニューが存在しています。

以下の4つです。

  • Cursor to Selected  3Dカーソルを選択した要素の中心に移動
  • Cursor to Center 3Dカーソルを原点に移動
  • Cursor to Grid  3Dカーソルを直近のグリッドに吸着
  • Cursor to Active  3Dカーソルをアクティブな要素の中心に移動

でも3Dカーソルをいろいろ動かすことができたら何が嬉しいの?とお思いになる方もいるかもしれません。

それは3Dカーソルが「編集の中心点」になりえるからなのです。

BlenderではPivot Point(ピボットポイント・編集の中心点)が5つあります。どれも有用で使い道のあるものですが、そのなかの3DCursor(3Dカーソル)は3Dカーソルの性質上非常に自由度の高いPivot Pointを実現してくれます。

3Dカーソルを使ってOriginを移動させる手順

例えばロボットの関節を作っていたとします。関節は多くの場合そのオブジェクトのOrigin(原点)が軸となって表現されます。

つまり関節の折れ曲がる場所にOriginを移動させる必要があります。

これにはObjectモードでオブジェクトを移動させてOriginを任意の場所にもっていく方法もありますが、やはり手動だと思った通りの場所に移動させるのはなかなか大変です。

またOriginを移動させた後、Mesh(メッシュ)を相対的に移動させないといけなくなるので面倒ですよね。

そこで3Dカーソルを使ってOriginを移動させます。

今回の例では肘関節部分を想定しています。

肘関節を構成する二つのオブジェクトがあります。originは中途半端な場所にあります。

Editモードで中心となりえる要素を選択

いったんEditモード(編集モード)に入ります。

そして対象となる関節位置の点や辺や面などを選択します。

このとき選択するのは選択全体の中心が肘関節の回転軸の中心となる要素にします。

例では関節の円状部分の面を両外側それぞれ2か所ずつ選択しています。

選択した要素の中心を捉えることができるので、関節が傾いていても関係ありません。オブジェクトを動かすときのようにXYZ軸に悩まされることはありません。

3Dカーソルの移動

そしてShift+SにてCursor to Selectedを選択します。

すると3Dカーソルが選択した要素の中心に移動してくるはずです。

視点回転するなどして、正しい位置に3Dカーソルが来ているかを確認してください。

もし、正しい位置に3Dカーソルが移動しなかった場合は、選択要素をもう一度検討してみてください。多くの場合上下左右に対称的に要素を選択すると中心を捉えられるかと思います。

Originを3Dカーソルの位置に移動させる

確認してよければ、Objectモード(オブジェクトモード)に戻って、Ctrl+Shift+Alt+Cを押します。

このショートカットはSet Originメニュー(原点を設定メニュー)が表示されます。Originの移動のためのショートカットですね。

そしてOrigin to 3D Cursor(原点を3Dカーソルへ移動)を選択します。

そうすると3Dカーソルの位置にそのオブジェクトのOriginが移動するはずです。

回転軸を肘に移動させることができました。

ちゃんと肘関節のようにまげることができるようになりました。

まとめ

上述はObjectモードでの例ですが、もちろんEditモードでも3Dカーソルは大活躍します。

さらなる応用編は別な記事にまとめたいと思います。

[Blender]Cyclesノードを理解するのに便利なレビュー機能

Cyclesのノードを理解するために

Cyclesのノードはなかなか複雑で理解しにくいものです。

まずCyclesノードで理解を阻む要素として「ノードが何を出力しているかわからない」ということがあります。そのため「ノード同士を掛け合わせる際の結果が想像できない」という事態にもなります。

これを回避する方法としてノード出力のレビュー(確認)があります。意外とこのノードレビューに言及している資料やチュートリアルが少ないように感じマス。

おそらく初心者のうちからこのノードレビューの方法を身に着けておくとCyclesの理解が早まるのではないかと思います。

仕組みとしては以下のようになります。

  • レビューを行うのは3DViewPort(3Dビュー)でのRendered(レンダー)にて
  • レビュー対象のノードはNodeEditer(ノードエディター)で選択

ですのでレビューを行いたい場合は最低でも3DViewPortとNodeEditerを表示させておく必要があります。配置はお好みで大丈夫です。

Cyclesのノードの出力をレビューする方法

それでは早速ノードレビューの方法です。

UserPrefarenceのInputから調べると「link viewer」という機能が今回の内容に該当します。

マテリアルを適用させたオブジェクトが必要です。ここはスザンヌさんに活躍してもらいましょう。

blender

テクスチャノードの場合

テストとしてNoiseTexture(ノイズテクスチャ)を出してレビューしてみます。

blender

blender

NoiseTextureを出してShift+Ctrlを押しながら左クリックします。

そうするとViewerというノードが現れ、MaterialOutput(マテリアル出力)とNoiseTextureとを自動的に繋いでくれます。

blender

これでレビュー状態になりました。

今度は3DViewPortをRenderedにします。3DViewPort上でShift+Zを押すと簡単です。

すると以下のように薄いパステルカラーのスザンヌが現れます。

blender

これがNoiseTextureからの出力です。もう少し正確にいうとNoiseTextureのColor(カラー)からの出力です。

NoiseTextureはこういった薄いパステルカラーをランダムで出力するのですね。

複数出力がある場合のレビュー対象の切り替え

NoiseTextureにはもう一つFac(係数)という出力があります。こちらもレビューしてみましょう。

Shift+Ctrlを押しながらNoiseTextureを再度左クリックしてください。

ノードには複数出力が存在する場合がありますが、Shift+Ctrlを押しながら左クリックを繰り返すことで出力の上から順番に切り替わっていきます。

そうするとColorからFacに接続が移動します。スザンヌさんが白黒になりました。

blender

これがFacの出力です。

ではNoiseTextureのパラメータを変更してどうなるか見てみましょう。好き勝手にいろいろパラメータをいじってみてください。

パラメータを変更するとその都度Renderedが更新され新しいレビューが表示されます。

blender

これでNoiseTextureの出力が手に取るようにわかります。

もちろんその他のテクスチャ系ノードも同じようにレビューが行えます。

ノード接続時のレビュー

通常ではNoiseTexture単体で使うよりなんらかのノードと組み合わせて使うことが多いでしょう。その場合でもレビューができます。

Converter(コンバーター)のColorRamp(カラーランプ)を出してNoiseTextureとViewerの間に挿入します。接続線の上にColorRampを移動させると自動的に結線されますので便利です。

もちろん手動で繋げてColorRampをShift+Ctrlを押しながら左クリックすることでもレビュー状態になります。

blender

blender

これでNoiseTextureからの出力がColorRampに入力され、ColorRampで処理された結果の出力のレビューができるようになります。

ColorRampの設定を何か変更してみてください。その結果が3DViewPortで確認できます。

blender

シェーダーの場合

もちろんシェーダーのレビューもできます。下記の画像のようなノードを用意してみました。NoiseTexture、ColorRamp、DiffuseBSDF(ディフューズBSDF)を2経路用意してMixShader(ミックスシェーダー)で混合している状態です。

blender

上の青い経路だけを確認してみます。上のDiffuseBSDFをShift+Ctrlを押しながら左クリックしてください。

今度はViewerというノードは現れませんが、NoiseTextureからの接続が直接DiffuseBSDFからの接続に変更されます。

blender

これで上の経路だけの出力が3DViewPortで確認できます。上の経路の設定をいろいろ変更してみてください。

今度は下の経路を確認しましょう。下のDiffuseBSDFをShift+Ctrlを押しながら左クリックしてください。

3DViewPortの出力が切り替わりましたでしょうか?

blender

レビュー状態から元に戻す

MaterialOutputにつながるはずの最終ノード上(おそらくShaderノードのはずですが)でShift+Ctrlを押しながら左クリックすると結線が元にもどります。

まとめ

これでノードが何を出力しているのか、ノード同士の接続がどのような結果になるのかが確認できるようになるかと思います。

この方法を使うことでCyclesの理解が進むことでしょう。ぜひ活用してみてください。