Life, Education, Death

プログラミング以外でも思ったことをつらつらと書きたい

PCGを使ってペイントしたら木のモデルが生えるようにする

nilfs.hatenablog.jp

前回はPCGとBlueprintを使って自分でPCGノードを作成するところまでやりました。 これができるとC++を書かなくても色んな事ができることができるようになるのですが、今回は木のモデルをいい感じに生やす機能を実装しようと思います。

ランドスケープを使ってレベルデザインをしている場合、複数のレイヤーを定義してそれぞれ草や地面などのマテリアルを割り当てるのではないかと思います。このレイヤーの情報を元に背景モデルを配置出来たら、簡単にそこそこのクオリティのマップが作れるのではないでしょうか?

どんどん、モデルを生やしていきましょう。

今回重要なノードはこの”Get Interpolated PCGLandscape Layer Weights”です。このノードはある座標のランドスケープのレイヤー情報を取得できるので特定のレイヤーだけ操作の対象にすることができます。 今回は、特定のレイヤー名だった場合はDensityをレイヤーウェイト値、それ以外は0を返す仕様で実装していきます。

まず、前回同様に新しいBPクラスを作成します。PCGE_LandscapeLayerWeightToDensityという名前のBPにしました。 親クラスはPCGBlueprint Elementを指定します。ExcuteWithContextの中身は前回と同じにします。

次に、PointLoopBodyをオーバーライドして中身を以下のように実装します。

変数TargetLandscapeLayerはノードのパラメータとして予めレイヤー名が入っているという想定でBPは実装されています。

左のノードから処理を説明していきます。

  1. Get Interpolated PCGLandscape Layer WeightsにはWorld Context Objectが必要なので、Get Componentを実行します。
  2. Get Interpolated PCGLandscape Layer Weightsは特定の位置のレイヤー情報を取得できるので、現在のポイントのTransformからLocationだけ取り出して渡します。
  3. レイヤーは複数重なってることがあるので配列で結果が返ってきますので、For Each Loopで1つ1つ中身を確認していきます。Target Landscape LayerとElement Nameを比較し、目的のレイヤー名がかどうか判断します。
  4. 目的のものであった場合は、DensityをWeightにして、他の値はそのままにしたいのでPoint Loop Bodyの引数のまま設定してreturnします
  5. エラー処理としてもしも、レイヤーが全く見つからないときはそのままの値を返すようにしています。これは要件によって適切なロジックに変更したほうがよいでしょう。

これで必要なノードが作成できました。これを使ってPCGグラフ上で特定のレイヤーをフィルタしていきましょう。 PCGグラフは先ほどのノードを使って、このようにします。

先ほど作成した、PCGE_LandscapeLayerWeightToDensityノードを通すとDensityがレイヤーのウェイトと同じになるのでDensity Filterノードを使ってフィルタすることができます。

また、PCGE_LandscapeLayerWeightToDensityノードのパラメータはこのように設定されています。デフォルトのレイヤーがSoilとなっていて、そこに木のモデルを出現させたいので、最後のStatic Mesh Spanwnerでは前回同様の木のモデルを設定しています。

この実装をしたPCGグラフをレベルに配置するとこのようになります。砂地のような白っぽいところと茶色(Soil)のレイヤーの繋ぎ目のところは木があったりなかったり、塗られ具合によって結果が異なっていることが確認できます。

これで、ランドマークペイントをしたらモデルが出るところまで出来ました。簡単に地形を作っていく際には使える機能ではないでしょうか?