はじめに
こんにちは、Putinuです。
本記事では、UnityのShaderGraphの機能を用いて動く2Dのハーフトーンシェーダーを制作していきます。
技術記事を書くことにはまだ不慣れのため、誤字脱字・表現の誤り等が含まれている可能性があります。
発見した際はコメントや私のTwitter(@putinu3)の方にでもご連絡頂けると幸いです。
本記事作成の経緯
時折お洒落なUI・影の表現として登場するハーフトーンですが、「作りたい!」と興味を持ち調べてみたところ、あまりUI周りに関連した記事を見つけることが出来ませんでした。(3Dの影に関するハーフトーンの記事は沢山見られましたが...。)
であれば、自身でUI向けのハーフトーンシェーダーを制作し、一例として記事でご紹介できればと考えました。
興味がありましたら、ご一読ください。
注意点
- 本記事では、UIのハーフトーンシェーダーの作り方にのみにフォーカスしています。
- 3D向けのハーフトーンシェーダーについては触れません。
- UIを表示する
Canvas
について、Screen Space - Overlay
では動作しません。-
Screen Space - Camera
のみで正しく動作します。 - 詳細は後述します。
-
今回作るもの
本記事では以下のようなものを制作していきます。
プロパティ名 | 型 | 説明 |
---|---|---|
MainTex | Texture 2D |
Sprite のテクスチャ情報を保持する |
Roughness | Float | マルの粗さ |
MaxCircleSize | Float | マルのサイズ上限値 |
HideOffset | Float | ハーフトーンの消える位置 |
HideDistance | Float | ハーフトーンが消えるまでの距離 |
Rotation | Float |
UV の回転量 |
MoveSpeed | Float | ハーフトーンの移動速度 |
MoveDirection | Vector 2 | ハーフトーンの移動方向 |
環境
- Unity 2021.3.9f1 Personal
- Universal RP 12.1.7
1. ハーフトーン(Halftone)とは
網点(あみてん)またはハーフトーン(英: Halftone)とは、グレイスケールやカラーの画像を限られた色数(例えば、白い紙上の黒い点など)の小さな点のパターンで表すことで印刷可能にしたものである。
マル(水玉模様)の大きさを調整することによって、影などの色の濃淡を表現していたようです。
主に印刷のために用いられていたようですが、今ではデザインの一種としても使用されています。
ゲームでも、UIの一部に使用されている例がいくつか見られました。
以下リンクより、ハーフトーンを利用した様々なゲームUIを確認することができます。
2. 準備する
シェーダーを作るための環境を準備します。
UnityやShaderGraphの基本的な操作については触れません。
適宜チュートリアルページをご確認ください。
2.1. ファイルの作成
まず、2D (URP)
で新しいUnityプロジェクトを作成します。
プロジェクトが起動したら、Project
ウィンドウ内で右クリックから、Create > Shader Graph > URP > Sprite Unlit Shader Graph
を選択し、新しいファイルを作成します。
2.2. 表示するUIの配置
Hierarchy
ウィンドウ内で右クリックし、UI > Image
を選択し、今回のシェーダーを適用するゲームオブジェクトを作成します。
使用するSprite
については、独自で用意するか、以下トグル内の素材を使用してください。
作成すると、その親オブジェクトとしてCanvas
が作成されるのでそれを選択します。そして、Inspector
ウィンドウ内のCanvas > Render Mode
をScreen Space - Camera
へと変更しましょう。
Render Camera
にMain Camera
をアタッチすることも忘れずに。
Screen Space - Overlayにおける問題
2022/9/18現在、Unity2021.2以降において、Canvas
のRender Mode
をScreen Space - Overlay
に設定している場合、UI
にシェーダーを適用しようとすると透過すべき部分が透過されず、真っ黒になってしまうというバグ(?)が存在しています。
2D Object
として利用する場合であれば問題ありませんが、UI
として使用する場合には以上の問題が発生するため注意が必要です。
Unityのフォーラムにおいても、この問題に関するスレッドが立ち上げられていますが、現在のところ改善される様子はなく、素直にScreen Space - Camera
を使用することが解決策として挙げられています。
2.3. Materialの作成・アタッチ
Project
ウィンドウより、先ほど作成したシェーダーファイルを選択した状態で右クリックし、Create > Material
からシェーダーを適用した状態のMaterial
を作成します。
そしてシェーダーを適用するImage
をHierarchy
ウィンドウから選択し、先ほど作成したマテリアルをInspector
ウィンドウ内のMaterial
欄にアタッチさせましょう。
以上で準備は完了です。
3. 要素ごとに作っていく
はじめに、今回のハーフトーンシェーダーを作る上で必要な構成要素を考えます。
その上で実際にUnity上でシェーダー作成を行っていきます。
今回は以下の手順で進めることとします。
- ハーフトーンの形を作る
- 縦横比を維持できるようにする(綺麗なマルにする)
- 位置に応じてマルを小さくする
- 回転させる
- 移動させる
- テクスチャに合わせる
3.1. ハーフトーンの形を作る
ハーフトーンの模様を作るにあたって、以下のことを意識する必要があります。
- 大きさが変化する
- 等間隔にある(パターンになっている)
- 移動する
まず「大きさが変化する」ことに関しては、中心が1
、外側が0
となっているものを、Step
関数を用いて二値化することで表現が出来るでしょう。
続いて「等間隔にある」ことは、揺らぎの無いVoronoi
ノードを使用してAngle Offset
を0
にする。
「移動する」ことは、その入力に使用するUV
をスクロールさせることで表現が出来そうです。
以下画像のように配置し、出力先をAlpha
に繋げます。
Voronoi
ノードは各マルの中心が黒色の0
になっています。そのため、Step
関数を用いて二値化した後、One Minus
ノードを使用して値を反転させています。
また、Voronoi
ノードのCall Density
については、粗さを自由にカスタマイズできるようにFloat
型のプロパティRoughness
を用意し、接続しておきます。
ここまで作った状態でSave Asset
を実行すると、以下のような状態になっています。
3.2. 縦横比を維持できるようにする
上画像のように縦長や横長のSprite
を扱う場合は、それに合わせてUV
が0~1
の範囲内で引き延ばされてしまいます。
その結果、横に引き延ばされたマルが描画されてしまいます。以上のような問題を解決するために、縦横比を維持させる必要があります。
具体的には、現在0~1
の範囲しか持っていないUV
の範囲をSprite
の縦横比に合わせて変化させる必要があります。
ここではSprite
の縦の長さを1
として固定します。
そして、横の長さが縦の長さに対してどれほど長いかを調べ、その比率で元のUV
と掛け合わせます。
これでUV
の範囲を変化させることができます。
Sprite
の縦横の長さをそれぞれw
、h
とし、初めのUV
の縦横の長さをu0
、v0
と置くと、算出されるu
、v
は、
(u, v) = (\frac{w\cdot {u_0}} h, v_0)
となります。
具体例(縦:100、横:200のとき)
例えば、Sprite
の縦の長さが100
、横の長さが200
とします。
この場合であれば、上記の計算式に落とし込むと、
(u, v) = (2u_0, v_0)
となります。つまり、u軸方向(横方向)に2倍することで綺麗なマルを描画できるようになります。
ShaderGraphでは、TexelSize
ノードを用いることで、テクスチャの縦横の長さを取得することができます。
今回はこれを用いて、縦横比を維持できるようにします。
Texture
に接続しているMainTex
プロパティは、画像左下の+マーク
からTexture 2D
を選択し、名前をMainTex
として作成します。
プロパティのReference
名は_MainTex
となっていることを確認してください。
先ほどの等式をShaderGraph
に落とし込むと、以下の画像のようになります。
縦横比を維持した状態の値が一番右側のVector 2
ノードより出力されています。
この出力値をVoronoi
ノードのUV
と接続することで、綺麗なマルへと戻すことができます。
3.3. 位置に応じてマルを小さくする
今回、ハーフトーンはVoronoi
ノードの出力値をStep
関数で二値化することで表現するようにしました。
また、この境界値を変化させることでマルの大きさを変化させることが出来るようにしました。
よって、位置に応じてマルを小さくするには、UV
座標に応じて二値化する境界値を変化できるようにすれば良さそうです。
3.3.1. UVと直接接続する
UV
ノードの出力をStep
ノードのEdge
に接続しました。
すると、以下画像のように左端が大きさ0
、右端が大きさ1
のハーフトーンが作成されました。
3.3.2. 上限を設ける
続いて、マルのサイズに上限を設けられるようにします。
上限・下限を設定するためには、Clamp
ノードを利用することが出来ます。
UV
ノードとStep
ノードの間に配置し、Max
に新しくFloat
型のプロパティMaxCircleSize
を設定します。
Min
についてはお好みでどうぞ。
これでStep
ノードへ与える境界値に制限を与えることが出来ました。
3.3.3. 消える位置を調整できるようにする
次に、ハーフトーンが消えていく位置を調整できるようにします。
元々持っているUV
座標の位置をずらすことにより、ハーフトーンの消える位置を調節します。
以下のように、境界値が0
となる位置をずらすイメージです。
位置を変えるためには、Add
ノードを用いてオフセット値を加算します。
ここで加算するオフセット値はHideOffset
としてプロパティ化し、自由に後から変更出来るようにします。
3.3.4. 消える距離を調整できるようにする
最後に、ハーフトーンが消えるまでの距離を調整できるようにします。
以下のイメージのように、境界値を減少させる幅を指定倍数伸ばすことで調整できるようにします。
これを表現するためには、割り算のDivide
ノードを使用し、割られる数として新しくプロパティHideDistance
を用意します。
ここまでの配置が終わると、シェーダーをアタッチしたMaterial
内のプロパティを調整することで、ある程度ハーフトーンらしい調整が可能になってきます。
3.4. 回転させる
ここからは、これまでの内容に回転の要素を入れていきます。
回転についても、これまでと同様に、UV
座標に変化を加えることで表現することができます。
回転の表現には、Rotation
ノードを使用し、UV
ノードとDivide
ノードの中間に接続します。
また、この時Rotation
の値をRotation
という名前でプロパティ化し、自由に回転出来るようにします。
以上のように配置すると、以下画像のように傾いたハーフトーンを作成することが出来ます。
3.5. 移動させる
ついにハーフトーンを動かせるようにします。
ここでは、ハーフトーンを表現するために使用していたVoronoi
ノードのUV
をスクロールすることで移動を表現します。
3.5.1. とりあえず動かす
移動を表現するためには、まずある地点のUV
座標がt秒後どんな位置にあるかを考える必要があります。
始点を0
として、距離をd
、移動速度をv
、時間をt
として表すと、
d = vt
と書きあらわすことができます。
これをグラフ上に落とし込んでいきます。
まず、Move
グループ内にて経過時間を示すTime
と、新しく作成した移動速度のプロパティMoveSpeed
を掛け合わせた値を用意します。
そして、それを縦横比を維持したUV
座標の出力値と加算し、Voronoi
ノードのUV
と接続します。
以上の状態でSave Asset
から保存すると、斜め方向へハーフトーンがスクロールするようになっています。
3.5.2. 移動方向を与える
現在のままでは一方向にしか移動できません。
そのため、新しいVector 2
型のプロパティMoveDirection
を作成することで移動方向を与えられるようにします。
ここで注意すべきは、移動速度は既に設定されている点です。
MoveDirection
の値を掛ける際には、掛ける前に一度正規化を行い、ベクトルの大きさを1
にする必要があります。
以上の内容を取り入れると、以下グラフのようになります。
Normalize
ノードを使用し、移動方向を正規化したベクトルと、元々の出力とで掛け合わせています。
そして、そこで得られた出力値を新しくAdd
ノードと繋ぎ直します。
One Minus
ノードについては、移動方向の調整という意味で配置しています。
ここで、MoveDirection
の値を(x, y)=(-1, 0)
とすると、左方向へ移動していくことが確認できます。
3.6. テクスチャの形状に合わせる
ここまでで大方の調整は完了しました。
ここからは、取り付けているテクスチャの形状に合わせる作業を行います。
まず、テクスチャの形状や色を取得するために、Sample Texture 2D
ノードを使用し、Texture
にMainTex
プロパティを接続します。
テクスチャ内でアルファ値が0
の部分に関しては映す必要が無い透過部分のため、これまでAlpha
に出力していた値とアルファチャンネルの不透明度を掛け合わせます。
以下グラフのように、アルファチャンネルとOne Minus
ノードの出力をMultiply
ノードを使用して掛け合わせ、Alpha
に繋ぎ直します。
色に関してはSample Texture 2D
ノードのRGBA
をBase Color
に接続することで表現することが出来ます。
ここまで作成できれば、完成となります!
Save Asset
から保存し、確認すると、今回の目的であったUIの形状に沿って動くハーフトーンを見ることが出来ます。
4. まとめ
以上、ShaderGraph
を用いた、動く2D向けハーフトーンの制作の手順紹介でした。
ここまでの手順をざっくりとまとめます。
-
Voronoi
ノードを使用して、ハーフトーンの形を作る -
Texel Size
ノードをもとに、縦横比を維持できるようにする -
UV
座標に応じてマルを小さくする -
UV
を回転させる -
UV
スクロールで移動させる -
Sample Texture 2D
ノードで形状や見た目を整える
5. あとがき
ここまで記事を読んでくださり、ありがとうございました。
今回作成したシェーダーは、UI
のアクセントや装飾としてのみならず、画面遷移などの場面でも活用できる余地がありそうですね。
また、今回のハーフトーンは縦横が揃ったものになっていますが、マルの位置が段ごとに交互になっているようなハーフトーンを作ってみるのも面白いかもしれません。
これは今後の課題にしたいと思います。
筆者なりに、ある程度利用しやすいように・汎用化できるように制作しましたが、もっと様々な活用の仕方はあると思いますので、是非読者の方々もここから自由に拡張して頂ければと思います。
それでは。
参考文献