ランダム無限都市ジェネレーターの作成をしたいと常日頃から思っています。
今度仕事で都市を作りそうなので、事前にどのようにビル群を作ると効率的か考えてみました。
まずはモジュールを作ってそれを並べて作る方法を思いついたので、並べ方の原則について考察しました。
それでは、まずモジュールの作成から見ていきましょう。
目次
3DCGの背景の作り方:3dsMAXのモジュールから建物を作る
3DCGでの背景の作り方を考える時に、根本的に建築のモデリングと違うところがあります。
それは、建築では、平面図、断面図を作ることを前提に、
内部構造まで考えて柱、壁、床等構造体をボックスで作ることが多いと思うのですが、
背景モデリングでは見えないところのポリゴンは無駄という考え方なので、構造よりも見た目重視になります。
よって、見えないポリゴンを全部削除した表面だけの悪く言えば張りぼてポリゴンモデルを作ることになります。
意匠設計をやってから、背景モデリングをやると躓くポイントはここです。
例えば、建物の外壁のワンモジュールを作成するといった時には、背景モデリングでは下のようなものを作ります。
モジュールの作成
凹んだ所がバルコニーで、四角が窓です。これがポリゴン数を削減する上で最適解ではないにしろ、
柱、壁、床を別々に奥まで作るよりかはよっぽどマシな(ポリゴン数が少なく)できるというメリットがあります。
もっとローポリで作るのであれば、階によってモジュール化しないという選択肢もありますが、
今回はモジュールを使った自動都市ジェネレーターを考えるので、モジュールベースで進めます。
3dsMAXでUV展開をすることを考慮して、今回はこのモジュールを3dsMAXで作っています。
それではこのモジュールを使って家を作ってみます。
モジュールを使った家の作成
これで500ポリゴンくらいです。屋根のトポロジーがモジュールと合っていませんが。
編集ポリゴンにアタッチするかは別途考えます。
例えばビルにするのであればこのモジュールを組み合わせてもう少し横長のものを作るという手もあります。
モジュールを使ったビルの作成
これで、1300ポリゴン位です。
ビルがどの程度出てくるかによって割けるポリゴン数が決まってくると思うのですが、
quest等のstandalone機でVRを作成する事を考えると、これでもかなり重いかもしれません。
すると、ガラス面を分割せず、一枚でやるとか色々工夫がいるのかもしれませんが、
今回はモジュールをテーマに建物を作りたいので、とりあえずこの方向で進めます。
例えばこのモジュールを数種類用意しておいて、それをランダムで積み上げるみたいなことをしたいという時に、
3dsmaxでは限界があるのではないかと思っていて、そういうのはHoudiniの得意分野ではないかと思い当たりました。
そこでUV展開後のモジュールをHoudiniにFBXモデルとして渡して、それをHoudiniでランダムに積み上げ、
ランダムに配置するというワークフローを想像しました。それではHoudini側の処理を考えてみましょう。
3DCGの背景の作り方:モジュールをHoudiniで並べる
まず、Houdiniで作る以上、任意のカーブに沿って、好きな数モジュールを並べるといった事が出来たら便利ですよね。
そこで階数とペリメーターの形状は任意という前提で、スクリプトを組みます。
モジュールを使った階数とペリメーターの形状は任意のビルの作成
参考にしたのは下のGuard Tower | Unityです。
Guard Tower 2 | Wood Wall Part 11 | Layout the Wall Asset from SideFX Houdini on Vimeo.
まず、適当に線を引いてトランスフォームをかませて後でスケールを調整できるようにし、Facetで面をきれいにしておきます。
面が裏返っているので、Reverseし、10mのモジュールに合わせてペリメーターが調整されるようにWrangleに書きます。
Resampleでポイントを10m間隔(モジュール)で拾うようにし、各点の法線をPolyframeで辺に対して接線方向に取ります。
Groupを作成してポイントのみを抽出します。$OSと書くことでノードの名前をグループ名にできます。
Polycutでポイントで分割し、PolyframeでFirstEdgeの法線を拾います。
For Each Primitiveの間にBlast(groupに1を入れる)を入れて不要なものを消去し、そのポイントに対してCopy to Pointで、
読み込んだFBXモデルをObjectMergeからポイントへコピーします。
For Each はForEachEndのSinglePathをオンにすることで、各Iterationでの挙動をマイフレーム確認できます。
最後にCopy and Transformで好きな数階数を増やします。
始めに仕込んだtransformをいじるとタワーのフットプリントが変化するのが確認できます。
Lsystemを使用したランダムペリメータービルの作成
Lsystemを使ったランダムフットプリントを考える時に参考にしたのは下のYOUTUBEです。
Lsystemについて詳しくはまだわかっていないのですが、下のように設定しました。
これによって90度でランダムに線が伸びていきます。
お決まりのFuse、Polyframeをかませてからポイントに2x2グリッドを配置します。これが建物のフットプリントになります。
PolyExtrudeでBoundaryGroupにチェックをいれExtrudeBackSeamを拾います。
そして、Labs Edge groups to Curveでカーブに変換します。
これはgroupノードのUnshared Edgeを拾う事で同じような事が出来るのですが、エッジの身を取り出すところで詰まったので、
上のやり方になりました。蛇足ですが、スクショを貼っておきます。
後は先ほどのスクリプトを流用して全く同じ要領でビルにしてしまいます。
モジュールをHoudiniで横並びにはできたのですが、高さにランダム性を与えたいですね。
そこで、今度は高さをランダムにすることを考えたいと思います。
3DCGの背景の作り方:モジュールをHoudiniで積み上げる
建物を積み上げる前に、よりシンプルな形で練習をしたく、まずはキューブを積み上げたいと思いました。
ForEachPrimitiveとメタデータを使ったキューブの積み上げ
Gridに対してCopy toPointでグリッド上にCubeを配置します。
そして、Assembleを使ってCreatePackedGeometryで1プリミティブが一つのキューブになるようにします。
それによって、ForEachPrimitiveを使用した時にCube毎に積み上げができるようにします。
このAssembleはConnectivity+Partitionを使用しているコンポーネントのようで、
一塊のFBXから連続していないメッシュごとに固めるのにも使えそうです。
For Each Primitiveを使ってIterationのメタデータを使用したランダムの積み上げを行っています。
Copy and TransformのTranslateには以下のように書いています。detail(xxx)がイテレーションの回数が入るようになっているので、
その回数を0~1のランダムバリューに変えて、それを10倍したのち、整数にキャストしています。
int(rand(detail("../meta","iteration",0))*10)
これで、ランダムにキューブを積み上げる事には成功したのですが、階を積み上げる事を考えると、
一階には複数のジオメトリが入っているので、それをまとめて積み上げてあげる必要があることに気付きます。
よってForEachPrimitiveでは、対応できないのでは??という疑問が出てきました。
そこで、例えばグループごとに積み上げるというようなことができないか考える事にしました。
gourp毎のForEachNamedPrimitiveによる積み上げ
まず、ボックスをグリッド上に配置して、グループ化します。GroupNameには$OSとタイプしてノード名がグループ名になるようにします。
これによって複製を作成するとノード名が自動的にリネームされるので、グループ名も自動でリネームされることになります。
Nameノードを使う事で所属グルプ名をnameアトリビュートに変えられます。
これによってForEachNamedPrimitiveを使用した時にグループ毎のイテレーションでloopを回せます。
ForEachNamedPrimitiveの中のTransformには以下のようにDetailのMeta情報を入れました。
これによって、グループ毎のループ処理が可能になりました。
モジュールをランダムに組み合わせる、並べる、積み上げる、という事が出来そうなので、今後はこれを駆使して、ランダム都市を作成しようと思います。
まだモジュールの種類が一種類しかありませんし、モジュールの組み合わせもできていないので、これから色々試していきたいと思います。
とりあえず原則が出来てきたので、これを組み合わせて何とか面白い表現が可能になれば良いなと思っています。
もっとローポリで建物を作るには
VRで都市を作ることを想定すると、体験位置から周囲4ブロックを作成して6棟ずつとして24棟、それから十字上に16棟、
さらに中距離のやつが10棟程度と想定して、50棟くらいは欲しいと思うのです。
しかし、30万ポリ以内でシーンを作成することを考えると、電柱とか信号機とかを作らないといけないので10万ポリはそういったプロップに、使いたいので、
残り20万ポリで何とか建物を作成してしまいたいという計算になりそうです。すると平均して、4000ポリで建物を作らないといけないという計算になります。
4000ポリなんて背の高いビルを作ったら、上の作り方をしていたら全く達成できないことが分かるので、何らかの工夫が必要ですね。
そこで、考えられるのは、以下のポイントです。
ポイント見える面しかディテールを入れない。
ポイント距離によってディテール量の強弱を付ける。
ポイント建物のディテールをアルベドとMSOだけで表現する。
ポイント建物をまとめてSetPathCallを抑える。
UnrealEngine5のマトリックスの建物のようなPCのスペックに依存した街並みではなく、あくまでstandalone機で見る事を想定しの場合です。
当然非力なアンドロイドで見るのでリソースに無駄があってはこまるわけですね。
これから、細かく見ていきたいと思いますが、ちょっとしばらく更新出来なさそうなので、中途半端な所でまた機会がある時に更新することにします。
おわりに
まだ具体的にどういった背景モデリングをするかについて考察が出来ずにいますが、
今後の更新に期待してください。
それではまた!