スクリプトからメッシュを作成する方法について、だんだん自信がなくなってきた解説その5。テクスチャが綺麗に見えるよう調整をします…
※このページの内容の動作確認にはUnity5.3を使用しています。
前回はテクスチャをスクリプトから作成し、メッシュに貼り付けました。でも、よく見るとなんだか汚い箇所があります。
Wrap Modeを変更する
まずは地形の端で色がおかしくなっている部分。山の上なのに青色が見える |
これはテクスチャがループする仕様になっていて、反対側の端の色が見えてしまっているためです。直し方は簡単で、テクスチャを作成するときに次の行を加えるだけ。
texture.wrapMode = TextureWrapMode.Clamp;
TextureにはWrap Modeというパラメータがあり、テクスチャの貼り方を選択することができます。Repeatに設定するとテクスチャを繰り返して隙間なく埋める、Clampにするとテクスチャを引き伸ばしてメッシュの端にピッタリ合わせて貼る、という感じです。今回はClampに設定しましょう。もしこれが壁や床のタイリングであればRepeatを使えばいいですね。
というわけでバッチリ改善しました。
次の問題はこれ。
ぼやけている |
ブロック化
手っ取り早い解決策はpublic bool blockMode;
if(blockMode) texture.filterMode = FilterMode.Point;
という感じでFilter ModeパラメータをPointにしてしまう方法。
くっきり! |
Filter Modeはテクスチャを3Dのモデルに貼り付けるときにどのように拡大するかを設定する項目で、Pointにするとそれぞれのピクセルがブロック状になります。
根本的な解決になってないし、そもそも「くっきり」ってそういうことじゃねえだろ感がすごいですが、ともかくぼやけた表示を直すという問題には対処できましたし、何よりパフォーマンス的な観点でいうと良い影響しかありません。個人的にこういう解決策は大好きです。
テクスチャの解像度を高くする
では次に、テクスチャのクオリティを上げるという本質的な改善案を実装してみます。[Range(1,16)] public int textureDetail;
int textureSize = (size - 1) * textureDetail + 1; Color[] colorMap = new Color[textureSize * textureSize]; for (int z = 0; z < textureSize; z++) { for (int x = 0; x < textureSize; x++) { float sampleX; float sampleZ; float y = 0; foreach (PerlinNoiseProperty p in perlinNoiseProperty) { p.scale = Mathf.Max(0.0001f, p.scale); sampleX = (x / (float)textureDetail + p.offset.x) / p.scale; sampleZ = (z / (float)textureDetail + p.offset.y) / p.scale; y += Mathf.PerlinNoise(sampleX, sampleZ) * p.heightMultiplier; } float percent = Mathf.InverseLerp(minHeight, maxHeight, y); colorMap[z * textureSize + x] = meshColorGradient.Evaluate(percent); } } Texture2D texture = new Texture2D(textureSize, textureSize);
まずテクスチャの解像度をどれだけ上げるかを指定するtextureDetailという変数を追加しました。
上の図のように、textureDetailの値が大きくなるごとにメッシュの頂点を補間する数を多くします。つまり、テクスチャのサイズをsizeではなく(size-1)*textureDetail+1として、大きめに作成するわけです。
そのあとは、メッシュの頂点を求めたのとまったく同じ方法でパーリンノイズを使い、それぞれの点でのY座標を求めます。パーリンノイズのサンプルを取得するときに、座標をtextureDetailで割るのを忘れないようにしましょう。さらに求めたY座標から表示する色を求め、テクスチャに適用するという前回と同じ流れになります。
わーい!キレイになったよ~!
…ただ、 このコードはさすがにパフォーマンス的に無理があります。たとえばメッシュのsizeが64の場合、実際の頂点数は64×64=4096個。textureDetailを4に設定した場合、テクスチャのサンプル数は253×253で64009個にもなります。textureDetailが増えるごとにそのおよそ2乗分が増えていくことになるので、そのすべてでパーリンノイズを算出して処理していくのはとんでもなくコストがかかります。指定したタイミングで1度だけ読み込むとかならいいと思いますが、たとえば高解像度のテクスチャを毎フレーム計算したりするのは現実的ではありません。
というわけで、さすがにもうテクスチャを貼り付けるだけでは間に合わなくなってきました。ここまで作っておいてなんですが、おとなしく専用のシェーダーを用意したほうがよさそうですね。
と言いつつ、今回はこのへんで。最適化の夢を見ながら寝ます…
0 件のコメント:
コメントを投稿