こんにちは。ロジカルビート情熱開発部プログラム課・廣江です。
梅雨の季節が近づき、だんだんと暖かくなってきました。
皆さんはいかがお過ごしでしょうか?
私は基本インドア派ではありますが、最近は少しずつ散歩などするようにしています。
さて今回は、タイリング可能なノイズテクスチャの生成について紹介したいと思います。
ノイズテクスチャはご存じの方も多いとは思いますが、3Dグラフィックスにおいて、エフェクトや高さマップ、雲の表現等、様々な用途で使用されています。
この記事では、ノイズテクスチャをタイリングした際に、継ぎ目が発生しないような、タイリング可能なノイズテクスチャの生成方法について紹介します。
検証はUE5のバージョン5.0.1で行っています。
タイリング可能なノイズテクスチャとは?
まず、一般的にタイリングとは、同じ大きさのものを縦横に規則正しく並べる処理をタイリングといいます。
また、3Dグラフィックスにおいては次のような処理を指すようです。
3DCG(3次元グラフィックス)のテクスチャマッピングでは、物体表面に小さな画像パターンを継ぎ目なく繰り返し貼り付ける操作をタイリングという。画像の上と下、左と右がうまく(シームレスに)繋がるような画像を用いると、大きな面を小さな画像で一定の模様や質感に仕上げることができ、データ容量の節約になる。
参照 : タイリング 【tiling】 タイル表示
なので、ここでいうタイリング可能なノイズテクスチャとは、ノイズテクスチャをタイリングした際に、継ぎ目が目立たないシームレスなノイズテクスチャのことを指します。
ノイズテクスチャをタイリングした際の問題点
タイリング可能なノイズテクスチャの生成を紹介する前に、通常のノイズテクスチャをタイリングした際の問題点を確認します。
次の画像は通常のノイズテクスチャを2×2でタイリングしたものです。
テクスチャの境界部分に継ぎ目が発生しており、見た目が不自然になっているかと思います。
また、次のようにノイズテクスチャを使用し、ディゾルブエフェクトのようなものを実装する場合も、モデルによってはノイズの継ぎ目が目立つ場合があります。
こちらの画像は、左側がタイリング可能ノイズテクスチャを使用したエフェクトで、右側は通常のノイズテクスチャを使用しています。
少しわかりずらいかもしれませんが、通常のノイズテクスチャの方はテクスチャの境界線部分に不自然な線が入るような見た目となっています。
このエフェクトの例は少し特殊かもしれませんが、高さマップなどでノイズテクスチャをタイリングして使用する場合は、継ぎ目の部分で急な段差が発生する可能性があり、想定していない見た目となることがあります。
これらを回避したい場合は、タイリング可能なノイズテクスチャを生成する必要があります。
継ぎ目が発生する原因
それでは、この継ぎ目が発生する原因について説明していきます。
まず、今回はパーリンノイズを使用しています。
パーリンノイズに関しては、ここでは詳細な説明はしませんが、パーリンノイズを理解するという記事で詳しく説明されているので、興味がある方はこちらの記事をご参照ください。
簡単に説明すると、次の手順で計算を行います。
Step.1 入力点に対してグリッドを計算する
通常パーリンノイズでは、いくつかのグリッドに分割して計算を行うので、
入力点が所属しているグリッドをここで求めます。
Step.2 勾配ベクトルと距離ベクトルを計算する
今回勾配ベクトルは擬似乱数で生成しており、擬似乱数は同じ入力値に対して常に同じ結果が出力されるという特性があります。
下の画像の黄色い矢印かこれにあたります。
また、距離ベクトルはグリッドの各点から入力点までのベクトルとなります。
下の画像の青い矢印がこれにあたります。
Step.3 勾配ベクトルと距離ベクトルの内積を計算する
そして、勾配ベクトルと距離ベクトの内積を計算します。
他にも計算は必要ですが、大まかに説明するとこのような手順で計算を行います。
ここで、タイリング可能なノイズテクスチャを作成するにあたって重要なのが、グリッドの計算です。
ノイズテクスチャをタイリングする場合、グリッドは次のようになっています。
今回は4×4のグリッドを生成しているのですが、グリッドが0~4の値となっており、最初と最後の値が異なっていることによって、タイリングした際に継ぎ目が目立つノイズとなります。
つまり、[ 0, 1, 2, 3, 0 ]のように最初と最後の値を揃えることにより、タイリング可能なノイズテクスチャを生成することが可能になります。
タイリング可能なノイズテクスチャの生成
それでは、これらを踏まえてタイリング可能なノイズテクスチャの生成について説明します。
先ほど少し説明してしまいましたが、タイリング可能なノイズテクスチャを生成するには、最後のグリッドと最初のグリッドの値を揃える必要があります。
それでは、実装について説明していきます。
次のコードはパーリンノイズのグリッドを計算している処理です。
引数のuv
は0~1の座標で、period
はグリッドの分割数を指定します。
また、floor
関数は小数点以下を切り捨てる関数です。
float noise( float2 uv, float2 period ){
float2 pos = uv*period;
float4 grid = floor( pos ).xyxy + float4( 0.f, 0.f, 1.f, 1.f );
grid = modulo( grid, period.xyxy );
// noiseの実装...
}
ここで重要なのがmodulo
関数です。
この関数でノイズテクスチャのシームレス化を対応しています。
modulo
関数の詳細は次の通りです。
float4 modulo( float4 dividend, float4 divisor ){
return dividend % divisor;
}
また、dividend
にマイナスの値が入ってくることを考慮する場合は、次のようにmodulo
関数を修正する必要があります。
float4 modulo( float4 dividend, float4 divisor ){
float4 positiveDividend = dividend % divisor + divisor;
return positiveDividend % divisor;
}
このmodulo
関数を挿むことにより、グリッドの値は次のようになります。
境界部分のグリッドの値が0で揃い、タイリング可能なノイズテクスチャを生成できます。
実装例
今回の実装ではUE5でRenderTargetへノイズを書き込み、それをテクスチャとして使用する形で実装しています。
ここでは詳細な実装手順などは省かせていただきますが、もし興味などある方は、Draw Material to Render Targetなどを調べてみてください。
それでは早速、実装したノイズを紹介していきます。
次の画像ですが、UE5で2×2のタイリングを実装したものです。
左側がタイリング可能なノイズを実装したもので、右側が通常のノイズを実装したものです。
比較してわかる通り、左側は多少ノイズがループした見た目にはなりますが、継ぎ目に関しては目立たなくなっています。
また、セルラーノイズの記事で紹介されているノイズもこれと同じ手法でタイリング可能なノイズテクスチャを生成することが可能です。
最後に
今回はタイリング可能なノイズテクスチャの作成を紹介しました。
ノイズテクスチャはゲームグラフィックスにおいて様々な用途で使用されています。
また、タイリング可能なノイズテクスチャを生成することで、メモリ使用量の削減や、処理負荷の軽減などのメリットがあります。
実装もそこまで難しい内容ではないので、興味がある方は是非試してみてください。