Houdiniで橋のモデリングを行いUnityのHDRPでセットアップして表示してみる

はじめに

Houdiniで橋をつくり、UnityのHDRPで表示しました。

せっかくなのでこのモデルの制作手順をもとにHoudiniモデリングのチュートリアルを作ってみました。

Houdiniというとエフェクト作成のイメージが強いかもしれませんが、モデリング用途にも強みがあることが示せればと思います。 今回のモデルは大きさのバリエーションをさまざまに用意できるモデルを作成します。

Houdiniの無料体験版Apprenticeでもモデリング部分は行なえます。 ただしApprenticeでは頂点カラー付きでモデルを出力する手段がない気がするので、テクスチャリング以降の作業はお預けです。

HoudiniとゲームエンジンというとHoudini Engineがありますが、今回はfixしたモデルにSubstance Painterでテクスチャを作っている関係で、Houdini Engineは使っていません。 Houdini Engineの情報を求めてきた人には申し訳ないです。

それではHoudiniでのモデリングのチュートリアルを始めます。 ぜひ楽しんでいってください!

  • Houdini: 18.0.287
  • SideFX Labs: 311
  • Substance Painter: 2019.3.1
  • Substance Designer: 2019.3.0
  • Unity: 2019.3.0f3
  • HDRP: 7.1.7

.hiplcファイル

今回作成する橋の.hiplcファイルはこちらです。

橋の作成にあたって自作したhdaの.hiplcファイルは次のとおりです。

橋をシーンに配置したシーンの.hiplcファイルはこちらです。

作成する橋の仕様の決定

まずは、作成するモデルのどの部分をパラメータとして操作可能にするかを決定します。

今回は次のようなパラメータを用意することにしました。

バウンディングボックスのサイズとしてsizex、sizey、sizezを用意します。

橋の両脇の欄干部分の高さとしてbalustradeheightを用意します。

橋の開始と終わりの部分の長さについて、startlength、endlengthを用意します。

橋の開始と終りの部分の支柱について、オン・オフできるようにします。

橋の裏側のグリッドのサイズについて、gridsizex、gridsizeyを用意します。

これらの用意したパラメータで、橋のモデルのサイズなどをあとから自由自在に変更できるようモデルを構築していきます。

橋の長さを変更した際に、橋の裏側のパターンなどが大きさに合わせて適切に繰り返し処理を行うようにします。


Houdiniでモデリングをする際は、どの程度パラメータ化しモデルを弄られるようにするかを予め決定しておくのがよいです。 何でもかんでもパラメータとして外部に公開すると使うのも大変ですし、作るのも大変になります。 一方で、パラメータが少ないと作れるバリエーションが少なくなります。 ここはトレードオフになっているので、よくよく考えて自分の用途に必要なパラメータというものを見極める必要があります。 今回は大きさを自由に変更できるようにして、その他のディティールなどは大きさに合わせて自動で繰り返してくれるようにします。

HDAの作成

今回、モデリングの作業にはいくつかの自作ノードを利用します。 まずは、その自作ノードの作成から解説をします。

Boltノード

ボルトの頭の部分のノードを作成します。 こういったパーツをHDAにしておくと使い回しがきいて便利です。 ベイク用のハイポリモデルの他、LOD対応のために荒いモデルにも切り替えられるようにします。


Houdiniを新しく開きます。

ネットワークビュー上でTabキーを押して「geo」と入力し、Geometryでエンターを2回押してGeometryノードを作成します。

geo1ノードを選択した状態でEnterキーかiキーを押してgeo1ノードの中に入ります。

Tabキーからcircleと入力してcircle1ノードを作成します。

Primitive TypeをPolygonに変更し、Divisionsを24とします。

PolyExtrudeノードを作成し接続します。

PolyExtrudeノードのディスプレイフラグを有効にします。

polyextrude1のDistanceを0.2にします。

polyextrude1のFront Groupを有効にします。

PolyBevelノードを接続します。

polybevel1ノードのパラメータを次のように設定します。

シーンビューは次のようになります。

新たにCircleノードを作成します。

circle2ノードのパラメータを次のように設定します。

PolyExtrudeノードを新たに作成しcircle2ノードに接続します。

polyextrude2ノードのパラメータを次のように設定します。

シーンビューは次のようになっています。

さらにPolyExtrudeノードを接続します。

polyextrude3ノードのパラメータを次のように設定します。

さらにPolyExtrudeノードを接続します。

作成したpolyextrude4ノードのパラメータを次のように設定します。

シーンビューは次のようになっています。

PolyBevelノードを追加して接続します。

作成したpolybevel2ノードのパラメータを次のようにします。

シーンビューは次のようになっています。

Transformノードを作成し接続します。

作成したtransform1ノードのパラメータを次のようにします。

Mergeノードを作成し接続します。

シーンビューは次のようになっています。

新たにCircleノードを作成します。

作成したcircle3ノードのパラメータを次のように設定します。

Groupノードを作成し接続します。

作成したgroup1ノードのパラメータを次のように設定します。

For-Loop with Feedbackを接続します。

repeat_begin1にPolyExtrudeノードを接続します。

polyextrude5のノードのパラメータを次のように設定します。

さらにPolyExtrudeノードを接続します。

接続したpolyextrude6ノードのパラメータを次のように設定します。

repeat_end1にPolyBevelノードを接続します。

接続したpolybevel3ノードのパラメータを次のように設定します。

シーンビューは次のようになっています。

polybevel3ノードにTransformノードを接続します。

transform2ノードのパラメータを次のように設定します。

transform2ノードからmerge1ノードへ接続します。

シーンビューは次のようになっています。

これでハイポリのボルトのモデルは完成です。

ネットワーク全体を選択してShift+Oでネットワークを囲っておきます。

続いてLOD0のモデルを作成していきます。

新しくCircleノードを作成します。

作成したcircle4ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し接続します。

作成したpolyextrude7のパラメータを次のように設定します。

新たにCircleノードを作成します。

作成したcircle5ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成してつなげます。

作成したpolyextrude8ノードのパラメータを次のように設定します。

さらにPolyExtrudeノードを作成し接続します。

作成したpolyextrude5ノードのパラメータを次のように設定します。

さらにPolyExtrudeノードを作成し接続します。

作成したpolyextrude10ノードのパラメータを次のように設定します。

Transformノードを接続します。

作成したtransform3ノードのパラメータを次のように設定します。

Mergeノードを作成し接続します。

シーンビューは次のようになっています。

これでLODのモデルの完成です。

LOD0のモデルのノードを選択しShift+Oで囲います。

続いてLOD1のモデルを作成します。

新たにCircleノードを作成します。

作成したcircle6ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し接続します。

接続したpolyextrude11ノードのパラメータを次のようにします。

シーンビューは次のようになっています。

これでLOD1のモデルは完成です。

Shift+Oでネットワークを囲います。

Switchノードを作成しハイポリ、LOD0、LOD1の順に接続します。

Transformノードを作成し接続します。

作成したtransform4ノードのパラメータを次のように設定します。

パラメータをまとめるnullノードを新たに作成します。

Cキーを押してノードの色を黄緑にします。

Zキーを押してノードの形を丸にします。

null1をparametersと名前を変更します。

パラメータウィンドウのギアマークから「Edit Parameter Interface」を実行します。

新しいウィンドウが開きます。

すでにある2つを選択しInvisibleにチェックを入れます。

左側のリストからFloatをドラッグ&ドロップします。

Nameをuniformscaleに、LabelをUniform Scaleに変更します。

Channelsからデフォルト値を0.015に変更します。

左側からOrdered Menuをドラッグ&ドロップします。

Nameをlod、LabelをLODとします。

MenuからHi、LOD0、LOD1を追加します。

Acceptを押すとparametersノードにUniform ScaleとLODのインタフェースが追加されています。

Uniform Scaleの数値の上で右クリックしてCopy Parameterを実行します。

transform4ノードのUniform ScaleにPaste Relative Referencesします。

parametersのLODをCopy Parameterします。

switch1のSelect InputにPaste Relative Referencesします。

これでparametersのパラメータを変更するとswitch1ノードやtransform4ノードのペーストした値が変更されるようになりました。

これらすべてのノードをHDAにまとめます。

すべてのノードを選択します。

Shift+Cでサブネットに格納します。

subnet1の名前をbolt_000に変更します。 この名前をアセットの名前とします。

bolt_000のパラメータのギアマークからEdit Parameter Interfaceを実行します。

最初からある4つのインタフェースを全部選択します。

Invisibleにチェックを入れて隠します。

Edit Parameter Interfaceウィンドウを開いたままで、bolt_000のサブネットを選択し、iキーもしくはエンターキーで内部に入ります。

ネットワーク内部のparametersを選択し、Uniform ScaleとLODのパラメータをドラッグ&ドロップしてsubnetのパラメータとして追加します。

Acceptを押します。 uキーでひとつ上の階層に上がります。

bolt_000にパラメータが出ているのがわかります。

試しにLODをHiからLOD0に変更してみます。

ちゃんとパラメータが生きているのがわかります。

bolt_000の上で右クリックをして、Create Digital Asset…を実行します。

Operator NameやOperator Labelを適当に指定しAcceptを押します。

Edit Operator Type Propertiesというウィンドウが開きます。

InteractiveのShelf ToolsのContextのTab Submenu Pathで作成したDigital Assetのタブメニューでの位置を指定できます。

Acceptを押して確定します。

Tabメニューからbolt000と打ってエンターを押すと作成したDigitalAssetが作成できます。

これでボルトのノードは完成です。

bolt_000.hiplc

Edge Damageノード

選択したエッジにダメージを与えるノードを作ります。 これは、ハイポリのモデルにディティールを加えるために使います。


まずはHoudiniを新規に開きます。

Geometryノードを作成し内部に入ります。

テスト用にboxを用意します。

Groupノードを作成し接続します。

作成したgroup1ノードのパラメータを次のように設定します。

これでエッジが1つグループに入れられた状態になります。 このグループをとりあえずの対象としてノードを組み立てていきます。

nullノードをつなげてinputと名付けます。

さらにnullノードをつなげてparametersと名付け、色と形を変更します。

Edit Parameter Interfaceを実行します。

不要なインタフェースをinvisibleにし、Stringを追加してNameをedgegroupとします。

Edge Groupsにgroup1と入力しておきます。

Float型のnoise1amplitudeとnoise2amplitudeを用意します。

それぞれ適当な数字を設定しておきます。

Toggleを追加しNameをaddcolorとし、Colorを追加しNameをcolorとします。 colorの初期値は(0,1,0)としました。

Normalノードを作成し接続します。

作成したnormal1ノードのパラメータを次のように設定します。

Addノードを作成し接続します。

作成したadd1ノードのパラメータを次のように設定します。 これで入力されたジオメトリの点だけを残します。

Point Wrangleを次のように接続します。

パラメータに次のように記述します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int n[] = neighbours(1, @ptnum);
string groups[] = split(chs("../parameters/edgegroup"));

foreach (int pt; n)
{
if (pt > @ptnum)
{
foreach(string g; groups) {
if (inedgegroup(1, g, @ptnum, pt)) {
int pr = addprim(geoself(), 'polyline', @ptnum, pt);
break;
}
}
}
}

これで次のようにグループで指定したエッジとすべて点のジオメトリが作成されます。

VEXの中身について解説をします。

Point Wrangelなのですべての点に対して実行されます。 実行されている点の番号は@ptnumで取得できます。

最初に2番目に接続されたジオメトリを利用して、現在の点と接続している点の番号をint n[]で受け取っています。

次の行で、parametersのedgegroupのグループ名を配列として取得しています。

隣接する点についてforeachでループを回しています。

その点が現在のポイント番号より後ろだった場合で、かつグループに含まれている場合にpolylineなprimitiveを追加しています。 ptが@ptnumより後ろなのを確認しているのは線が重複をするのを避けるためです。

Addノードを作成し接続します。

作成したadd2ノードのパラメータを次のようにします。

これによって、使っていないポイントが削除されます。

Point Wrangleを作成し接続します。

作成したpointwrangle2ノードのVEXに次のように記述します。

横のボタンを押してパラメータのスライダを出します。

Distanceに適当に小さい値を入れます。

distance分だけ、あらかじめ計算したpoint normalの方に位置をずらしています。

PolyWireノードを作成し接続します。

次にVDB from Polygonsノードを作成し接続します。

次にConvert VDBノードを作成し接続します。

作成したconvertbdb1ノードのパラメータを次のように設定します。

Attribute Noiseノードを作成し接続します。

attribnoise1ノードのパラメータを次のように設定します。

Amplitudeの部分はch("../parameters/noise1amplitude")です。

もう一つAttribute Noiseノードを作成し接続します。

作成したattribnoise2ノードのパラメータを次のように設定します。

Amplitudeの部分はch("../parameters/noise2amplitude")です。

Colorノードを作成し接続します。

Colorをparametersからコピーしてreferenceをペーストします。

ClassをVertexにしておきます。

Switchノードを作成し、次のように接続します。

switch1のSelect Inputにch("../parameters/addcolor")と入力します。

Booleanノードを作成し次のように接続します。

inputが左の入力に、switch1が右の入力に接続されています。

作成したboolean1ノードのOperationをSubtractにします。

これでシーンビューは次のようになっています。

Normalノードを作成し接続します。

作成したnormal2のパラメータを次のように設定します。

最後にLabs Delete Small Partsノードを挿しておきます。

LabsツールはSideFX Labsと呼ばれるものです。 このノードが存在しない場合はSideFX Labsツールをインストールしてください。

Houdiniの内部システムからの直接インストール | インディゾーンHoudini情報日本語ブログ

inputより下のノードを選択します。

Shift+Cでノードをサブネットに格納します。

サブネットの名前をedge_damageとします。

edge_damageのEdit Parameter Interfaceを実行します。

最初からあるインタフェースをInvisibleにします。

Edit Parameter Interfaceを開いたままでサブネットの内部に入ります。

parametersからパラメータをドラッグ&ドロップします。

pointwrangle1のDistanceをドラッグ&ドロップします。

vfbfrompolygons1のVoxel SIzeをドラッグ&ドロップします。

attributenoise1とattributenoise2のノイズのパラメータをドラッグ&ドロップします。

フォルダに入れ並べ替えて整理します。

colorのHidfe Whenに{ addcolor == 0 }と入力します。

edgegroupのMenuタブからUse Menuとし、Toggleに変更します。

Menu Scriptに変更して次のスクリプトを記述します。

1
2
3
4
5
6
7
inputs = hou.pwd().inputs()
result = []
if len(inputs):
node = inputs[0]
groups = [ x.name() for x in node.geometry().edgeGroups()]
result = sum(zip(groups, groups),())
return result

Edge Groupに既存のグループを選択するドロップダウンリストができました。

Action Buttonのタブを開いて次のスクリプトを書きます。

1
2
3
4
import soputils
kwargs['geometrytype'] = (hou.geometryType.Edges,)
kwargs['inputindex'] = 0
soputils.selectGroupParm(kwargs)

Action Iconを「BUTTONS_reselect」とします。

これでその場でグループを選択から作る矢印が表示されました。

Voxelサイズを小さくし、ノイズのパラメータを変更するとよい感じのエッジダメージになります。

サブネットを右クリックしてCreate Digital Asset…をクリックします。

適当に名前を決めてAcceptを実行します。

Input/Putputのタブからわかりやすいラベルを与えます。

InteractiveのShelfToolsのContextのTab Submenu Pathからタブメニューでの場所を設定します。

作成したEdge Damageノードには弱点があります。 PointNormal方向にずらしたものをbooleanで抜いているので、 たとえばpigheadのように入り組んだ部分では 選択したエッジの反対側までくり抜けてしまいます。

堅牢にどんなときでもうまく動くようなノードを作るのは難しいので、入り組んだ部分には使わないということで妥協しています。

edge_damage.hiplc

Rect Trim Off Edgeノード

長方形のエッジから切り落とすように分割するノードです。

入力の各長方形に対して働きます。

四角形以外の面が入力に含まれている場合にはエラーとなります。

エッジからの長さをdistanceパラメータで指定できます。

axisパラメータで好きな軸の方向から分割できます。

分割の際にグループ名をつけることができます。

次の画像はグループごとに色を割り振ったものです。


Houdiniの新規シーンを新しく開きます。

Geometryノードを作成し内部に入ります。

テスト用にGridを配置します。

nullノードをつなげてinputと名付けます。

さらにnullノードをつなげてparametersと名付け、色と形を変更します。

Edit Parameter Interfaceを実行します。

最初から含まれる不要なインタフェースをinvisibleにし、Stringを追加してNameをgroupとします。

Ordered Menuを追加してNameをaxisとします。

Menu欄から次のように指定します。

FloatとStringを2つ追加し、それぞれNameをdistance、edgegroupname、maingroupnameとします。

Acceptします。

Blastノードを作成質疑のように接続します。

作成したblast1ノードのパラメータのGroupを次のように指定します。

blast1ノードを選択しCtrl+CでコピーしてCtrl+Vで貼り付けます。

ペーストしたblast2ノードのDelete Non Selectedをチェックします。

Primitive Wrangelノードを作成質疑のように接続します。

Primitive WrangleノードのVEXに次のように記述します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int vcount = primvertexcount(geoself(), @primnum);
int closed = primintrinsic(geoself(), "closed", @primnum);
string typename = primintrinsic(geoself(), "typename", @primnum);

if (vcount != 4 || !closed || typename != "Poly") {
setdetailattrib(geoself(), "errorflag", 1, "max");
return;
}

vector pos[];
for (int i = 0; i < 4; i++) {
pos[i] = point(geoself(), "P", primpoint(geoself(), @primnum, i));
}

vector v01 = pos[1] - pos[0];
vector v12 = pos[2] - pos[1];
vector v23 = pos[3] - pos[2];
vector v30 = pos[0] - pos[3];

// error flag
setdetailattrib(
geoself(), "errorflag",
!(
abs(dot(v01, v12)) < 1e-5 &&
abs(dot(v12, v23)) < 1e-5 &&
abs(dot(v23, v30)) < 1e-5 &&
abs(dot(v30, v01)) < 1e-5
),
"max"
);

VEXの解説をします。

このノードはRun Over Primitivesになっているので、各Primitiveについて実行されます。

最初に@primnumで取得できる現在のPrimitiveが頂点数4で閉じていてタイプがポリゴンであるか確認しています。 いずれかの条件を満たしていない場合、detailにerrorflagというアトリビュートを追加して1をセットしています。 Run OverされるPrimitiveのいずれかでエラーが有った場合にエラーを検知したいので、"max"で一つでも1になったら1とするようにしました。

次に頂点の座標を取得し、すべての角が90度であるかを調べています。 内積の絶対値がある程度小さければその角が90度であると判定しています。 いずれかの角が90度でない場合はdetailにerrorflagというアトリビュートを追加して1をセットしています。

次にErrorノードを作成し接続します。

作成したerror1ノードのパラメータを次のように設定します。

Report This Errorはdetail("../primitivewrangle1", "errorflag", 0)です。

次にAttribute Deleteノードを作成し次のように接続します。

作成したattribdelete1ノードのパラメータを次のように設定します。

次にPrimitive Wrangleノードを作成し次のように接続します。

priimitivewrangle2ノードのVEXに次のように記述します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
int pt[];
vector pos[];
for (int i = 0; i < 4; i++) {
pt[i] = primpoint(geoself(), @primnum, i);
pos[i] = point(geoself(), "P", pt[i]);
}

// sort points
// make 0-1 edge start side

int axis = chi("../parameters/axis");

void shiftpoints(int pt[]; vector pos[]) {
int tmpPt;
vector tmpPos;
// shift
tmpPt = pt[0];
tmpPos = pos[0];
pt[0] = pt[1];
pos[0] = pos[1];
pt[1] = pt[2];
pos[1] = pos[2];
pt[2] = pt[3];
pos[2] = pos[3];
pt[3] = tmpPt;
pos[3] = tmpPos;
}

if (axis == 0) {
while (
!(
pos[0].x >= pos[3].x &&
pos[1].x >= pos[2].x &&
pos[0].x >= pos[2].x &&
pos[1].x >= pos[3].x
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 1) {
while (
!(
pos[0].y >= pos[3].y &&
pos[1].y >= pos[2].y &&
pos[0].y >= pos[2].y &&
pos[1].y >= pos[3].y
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 2) {
while (
!(
pos[0].z >= pos[3].z &&
pos[1].z >= pos[2].z &&
pos[0].z >= pos[2].z &&
pos[1].z >= pos[3].z
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 3) {
while (
!(
pos[0].x <= pos[3].x &&
pos[1].x <= pos[2].x &&
pos[0].x <= pos[2].x &&
pos[1].x <= pos[3].x
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 4) {
while (
!(
pos[0].y <= pos[3].y &&
pos[1].y <= pos[2].y &&
pos[0].y <= pos[2].y &&
pos[1].y <= pos[3].y
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 5) {
while (
!(
pos[0].z <= pos[3].z &&
pos[1].z <= pos[2].z &&
pos[0].z <= pos[2].z &&
pos[1].z <= pos[3].z
)
) {
shiftpoints(pt, pos);
}
}

// end sort points

float edgeDistance = ch("../parameters/distance");
string mainGroupName = chs("../parameters/maingroupname");
string edgeGroupName = chs("../parameters/edgegroupname");

vector dir = normalize(pos[3] - pos[0]);

int newpt0, newpt1;
vector newpos0, newpos1;
newpos0 = pos[0] + dir * edgeDistance;
newpt0 = addpoint(geoself(), newpos0);
newpos1 = pos[1] + dir * edgeDistance;
newpt1 = addpoint(geoself(), newpos1);

int prim;
prim = addprim(
geoself(), "poly",
pt[0], pt[1], newpt1, newpt0
);
setprimgroup(geoself(), edgeGroupName, prim, 1);
prim = addprim(
geoself(), "poly",
newpt0, newpt1, pt[2], pt[3]
);
setprimgroup(geoself(), mainGroupName, prim, 1);

removeprim(geoself(), @primnum, 1);

最初にpt[]pos[]でポイント番号と位置を取得しています。 これより前で長方形以外のプリミティブはエラーになっているので、ここでは長方形のプリミティブが渡されたものとして進めています。

1
2
3
4
5
6
int pt[];
vector pos[];
for (int i = 0; i < 4; i++) {
pt[i] = primpoint(geoself(), @primnum, i);
pos[i] = point(geoself(), "P", pt[i]);
}

parametersで指定したaxisの値をもとに、長方形のポイントをシフトして並べ替えています。 axisで指定したエッジ側がpt[0]pt[1]となるように並べ替えています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// sort points
// make 0-1 edge start side

int axis = chi("../parameters/axis");

void shiftpoints(int pt[]; vector pos[]) {
int tmpPt;
vector tmpPos;
// shift
tmpPt = pt[0];
tmpPos = pos[0];
pt[0] = pt[1];
pos[0] = pos[1];
pt[1] = pt[2];
pos[1] = pos[2];
pt[2] = pt[3];
pos[2] = pos[3];
pt[3] = tmpPt;
pos[3] = tmpPos;
}

if (axis == 0) {
while (
!(
pos[0].x >= pos[3].x &&
pos[1].x >= pos[2].x &&
pos[0].x >= pos[2].x &&
pos[1].x >= pos[3].x
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 1) {
while (
!(
pos[0].y >= pos[3].y &&
pos[1].y >= pos[2].y &&
pos[0].y >= pos[2].y &&
pos[1].y >= pos[3].y
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 2) {
while (
!(
pos[0].z >= pos[3].z &&
pos[1].z >= pos[2].z &&
pos[0].z >= pos[2].z &&
pos[1].z >= pos[3].z
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 3) {
while (
!(
pos[0].x <= pos[3].x &&
pos[1].x <= pos[2].x &&
pos[0].x <= pos[2].x &&
pos[1].x <= pos[3].x
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 4) {
while (
!(
pos[0].y <= pos[3].y &&
pos[1].y <= pos[2].y &&
pos[0].y <= pos[2].y &&
pos[1].y <= pos[3].y
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 5) {
while (
!(
pos[0].z <= pos[3].z &&
pos[1].z <= pos[2].z &&
pos[0].z <= pos[2].z &&
pos[1].z <= pos[3].z
)
) {
shiftpoints(pt, pos);
}
}

// end sort points

並べ替え処理のためにshiftpointsという関数を用意しています。 VEXにおいてユーザ定義関数のパラメータは常に参照になるそうです。

VEX言語リファレンス

その後、parametersノードからdistanceとmaingroupnameとedgegroupnameを取得しています。

1
2
3
float edgeDistance = ch("../parameters/distance");
string mainGroupName = chs("../parameters/maingroupname");
string edgeGroupName = chs("../parameters/edgegroupname");

長方形の分割に直行する方向をdirとして計算しています。

1
vector dir = normalize(pos[3] - pos[0]);

新しくポイントを追加します。

1
2
3
4
5
6
int newpt0, newpt1;
vector newpos0, newpos1;
newpos0 = pos[0] + dir * edgeDistance;
newpt0 = addpoint(geoself(), newpos0);
newpos1 = pos[1] + dir * edgeDistance;
newpt1 = addpoint(geoself(), newpos1);

作成したポイントと既存のポイントをもとに長方形のprimitiveを追加しています。 作成したPrimitiveには与えられたグループに属するようにしています。

1
2
3
4
5
6
7
8
9
10
11
int prim;
prim = addprim(
geoself(), "poly",
pt[0], pt[1], newpt1, newpt0
);
setprimgroup(geoself(), edgeGroupName, prim, 1);
prim = addprim(
geoself(), "poly",
newpt0, newpt1, pt[2], pt[3]
);
setprimgroup(geoself(), mainGroupName, prim, 1);

最後に、新しく面を作ったので最初からあるPrimitiveは必要なくなったので、それを削除して終了です。

1
removeprim(geoself(), @primnum, 1);

新しくMergeノードを作成し、次のように接続します。

最後にfuseノードを作成し、次のように接続します。 これでblastで分割した境界部分の頂点をマージします。

input以下のノードを選択します。

Shift+Cでサブネットに格納します。

subnet1の名前をrect_trim_off_edgeと名付けます。

rect_trim_off_edgeのEdit Parameter Interfaceを実行します。

最初からあるラベルのインタフェースを非表示にします。

Edit Parameter Interfaceのウィンドウを開いたまま、rect_trim_off_edgeノードの内部に入ります。

parametersノードにまとめてあるパラメータをドラッグ&ドロップで追加します。

groupのMenuからUse Menuにチェックを入れてToggleにします。 Menu Scriptで次のPythonスクリプトを追加します。

1
2
3
4
5
6
7
inputs = hou.pwd().inputs()
result = []
if len(inputs):
node = inputs[0]
groups = [ x.name() for x in node.geometry().primGroups()]
result = sum(zip(groups, groups),())
return result

このスクリプトで接続されたノードのprimitiveのグループの一覧をトグルするドロップダウンが追加されます。

groupのAction Buttonを追加します。 Action Buttonのタブに次のpythonコードを記述します。

1
2
3
4
import soputils
kwargs['geometrytype'] = (hou.geometryType.Primitives,)
kwargs['inputindex'] = 0
soputils.selectGroupParm(kwargs)

Action Iconの欄にBUTTONS_reselectとしてアイコンを設定します。

これで接続されたgeometryのプリミティブグループを選択することができるようになりました。

サブネットを右クリックしてCreate Digital Asset…をクリックします。

適当に名前を決めてAcceptを実行します。

Input/Putputのタブからわかりやすいラベルを与えます。

InteractiveのShelfToolsのContextのTab Submenu Pathからタブメニューでの場所を設定します。

これでRect Trim Off Edgeノードの完成です。

rect_trim_off_edge.hiplc

Rect Multi Splitノード

長方形を複数に分割するノードです。

mainとsubの長さを指定します。

メインとサブを交互に並べて詰め込む形で分割されます。

入力の長方形の大きさによって分割数が変わります。

メインとサブの指定した大きさでピッタリ割り切れない場合はメインの大きさが伸びます。

入力の各長方形に対して働きます。

axisパラメータで分割の軸の方向を決定できます。

入力に長方形以外の面が含まれる場合エラーとなります。

分割の際にmainとsubのグループ名を与えることができます。

各グループに色を付けると次のようになります。

元になる長方形のPrimitiveのサイズを変更するとそれに合わせて分割数が変わります。

この機能をつかって橋の裏の構造の繰り返しなどを作っていきます。


新しくHoudiniのシーンを立ち上げ、geoノードを作成し内部には入ります。 テスト用にgridノードを作成し、RowsとColumnsをそれぞれ2にします。

nullノードを新たに作成し名前をinputに変更して接続します。

さらにnullノードを作成し接続し、名前をparametersとします。 ノードの形状と色を変更します。

Edit Parameter Interfaceでparametersのインタフェースを変更します。

最初に2つの必要ないインタフェースをInvisibleにします。

Stringをドラッグ&ドロップし、Nameをgroupに変更します。

Ordered Menuをドラッグ&ドロップし、Nameをaxisに変更します。

次のようにMenuの内容を変更します。

Floatを2つドラッグ&ドロップし、Nameをそれぞれmainwidthとsubwidthとします。

2つStringをドラッグ&ドロップし、Nameをそれぞれmaingroupnameとsubgroupnameとします。

Acceptを押して確定します。 Main WidthとSub Widthには適当な値を入れておきます。

Rect Trim Off Edgeノードのときと同じようにして次のようにノードを接続します。

primitivewrangle2のVEXコードを次のように書き換えます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
int pt[];
vector pos[];
for (int i = 0; i < 4; i++) {
pt[i] = primpoint(geoself(), @primnum, i);
pos[i] = point(geoself(), "P", pt[i]);
}

// sort points
// make 0-1 edge start side

int axis = chi("../parameters/axis");

void shiftpoints(int pt[]; vector pos[]) {
int tmpPt;
vector tmpPos;
// shift
tmpPt = pt[0];
tmpPos = pos[0];
pt[0] = pt[1];
pos[0] = pos[1];
pt[1] = pt[2];
pos[1] = pos[2];
pt[2] = pt[3];
pos[2] = pos[3];
pt[3] = tmpPt;
pos[3] = tmpPos;
}

if (axis == 0) {
while (
!(
pos[0].x <= pos[3].x &&
pos[1].x <= pos[2].x &&
pos[0].x <= pos[2].x &&
pos[1].x <= pos[3].x
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 1) {
while (
!(
pos[0].y <= pos[3].y &&
pos[1].y <= pos[2].y &&
pos[0].y <= pos[2].y &&
pos[1].y <= pos[3].y
)
) {
shiftpoints(pt, pos);
}
} else if (axis == 2) {
while (
!(
pos[0].z <= pos[3].z &&
pos[1].z <= pos[2].z &&
pos[0].z <= pos[2].z &&
pos[1].z <= pos[3].z
)
) {
shiftpoints(pt, pos);
}
}

// end sort points

float totalLength = distance(pos[0], pos[3]);
float mainWidth = ch("../parameters/mainwidth");
float subWidth = ch("../parameters/subwidth");
int count;
if (totalLength < mainWidth) {
count = 1;
mainWidth = totalLength;
} else {
count = floor((totalLength + subWidth) / (mainWidth + subWidth));
mainWidth = (totalLength + subWidth) / count - subWidth;
}

string mainGroupName = chs("../parameters/maingroupname");
string subGroupName = chs("../parameters/subgroupname");

int pt0 = pt[0], pt1 = pt[1];
vector pos0 = pos[0], pos1 = pos[1];
vector dir = normalize(pos[3] - pos[0]);

int newpt0, newpt1;
vector newpos0, newpos1;
int prim;
for (int i = 0; i < count - 1; i++) {
newpos0 = pos0 + dir * mainWidth;
newpt0 = addpoint(geoself(), newpos0);
newpos1 = pos1 + dir * mainWidth;
newpt1 = addpoint(geoself(), newpos1);
prim = addprim(
geoself(), "poly",
pt0, pt1, newpt1, newpt0
);
setprimgroup(geoself(), mainGroupName, prim, 1);
pt0 = newpt0;
pt1 = newpt1;
pos0 = newpos0;
pos1 = newpos1;

newpos0 = pos0 + dir * subWidth;
newpt0 = addpoint(geoself(), newpos0);
newpos1 = pos1 + dir * subWidth;
newpt1 = addpoint(geoself(), newpos1);
prim = addprim(
geoself(), "poly",
pt0, pt1, newpt1, newpt0
);
setprimgroup(geoself(), subGroupName, prim, 1);
pt0 = newpt0;
pt1 = newpt1;
pos0 = newpos0;
pos1 = newpos1;
}
prim = addprim(
geoself(), "poly",
pt0, pt1, pt[2], pt[3]
);
setprimgroup(geoself(), mainGroupName, prim, 1);

removeprim(geoself(), @primnum, 1);

最初にポイントとその位置を取得しソートしている部分はRect Trim Off Edgeのときと同じです。 Axisが+-を気にしないためその部分だけ違います。

その後、分割方向の長さと指定したmainとsubの長さから分割数を決定しています。

mainWidthよりもtotalLengthが短い場合は分割数を1としています。 それ以外の場合は、mainを分割数だけ、subをmainの間なので分割数-1だけ、詰め込めるだけ詰め込んで分割数を計算しています。 もとの分割方向の長さに足りない分はmainを引き伸ばすことで対応しています。

1
2
3
4
5
6
7
8
9
10
11
float totalLength = distance(pos[0], pos[3]);
float mainWidth = ch("../parameters/mainwidth");
float subWidth = ch("../parameters/subwidth");
int count;
if (totalLength < mainWidth) {
count = 1;
mainWidth = totalLength;
} else {
count = floor((totalLength + subWidth) / (mainWidth + subWidth));
mainWidth = (totalLength + subWidth) / count - subWidth;
}

その後for文でcount-1回だけmainとsubの面を貼っています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int newpt0, newpt1;
vector newpos0, newpos1;
int prim;
for (int i = 0; i < count - 1; i++) {
newpos0 = pos0 + dir * mainWidth;
newpt0 = addpoint(geoself(), newpos0);
newpos1 = pos1 + dir * mainWidth;
newpt1 = addpoint(geoself(), newpos1);
prim = addprim(
geoself(), "poly",
pt0, pt1, newpt1, newpt0
);
setprimgroup(geoself(), mainGroupName, prim, 1);
pt0 = newpt0;
pt1 = newpt1;
pos0 = newpos0;
pos1 = newpos1;

newpos0 = pos0 + dir * subWidth;
newpt0 = addpoint(geoself(), newpos0);
newpos1 = pos1 + dir * subWidth;
newpt1 = addpoint(geoself(), newpos1);
prim = addprim(
geoself(), "poly",
pt0, pt1, newpt1, newpt0
);
setprimgroup(geoself(), subGroupName, prim, 1);
pt0 = newpt0;
pt1 = newpt1;
pos0 = newpos0;
pos1 = newpos1;
}

その後、mainをもう一個だけ貼っています。

1
2
3
4
5
prim = addprim(
geoself(), "poly",
pt0, pt1, pt[2], pt[3]
);
setprimgroup(geoself(), mainGroupName, prim, 1);

最後にもとからあった面を削除しています。

1
removeprim(geoself(), @primnum, 1);

input以下のノードをすべて選択し、Shift+Cでサブネットに格納します。

subnet1の名前をrect_multi_splitとします。

Edit Parameter Interfaceを開きます。

はじめからあるラベルはInvisibleにしてしまいます。

Edit Parameter Interfaceウィンドウを開いたままでrect_multi_splitノードの内部に入ります。 parametersのパラメータをドラッグ&ドロップします。

groupのMenuからUse Menuにチェックを入れてToggleにします。 Menu Scriptで次のPythonスクリプトを追加します。

1
2
3
4
5
6
7
inputs = hou.pwd().inputs()
result = []
if len(inputs):
node = inputs[0]
groups = [ x.name() for x in node.geometry().primGroups()]
result = sum(zip(groups, groups),())
return result

このスクリプトで接続されたノードのprimitiveのグループの一覧をトグルするドロップダウンが追加されます。

groupのAction Buttonを追加します。 Action Buttonのタブに次のpythonコードを記述します。

1
2
3
4
import soputils
kwargs['geometrytype'] = (hou.geometryType.Primitives,)
kwargs['inputindex'] = 0
soputils.selectGroupParm(kwargs)

Action Iconの欄にBUTTONS_reselectとしてアイコンを設定します。

Acceptして確定します。 rect_multi_splitノードのインタフェースで操作できるようになりました。

rect_multi_splitノードで右クリックをしてCreate Digital Asset…を実行します。

適当な名前をつけてAcceptします。

Inputのラベルの変更やTabメニューの階層の変更などを行います。

AcceptしてRect Multi Splitノードは完成です。

rect_multi_split.hiplc


これでひとまず橋の作成に使うノードは完成です。

橋のモデリング

さて、ここからが本番です。 橋のモデリングを進めていきますよ。

新しくHoudiniのシーンを開いてgeoを作成して内部に入ります。 nullノードを作成しparametersと名付け、ノードの色と形を変更します。

Edit Parameter Interfaceを開きます。

次のパラメータを追加します。

  • Float Vector 3のsize
  • Float Vector 3のcenter
  • Floatのuniformscale
  • Float Vector 2のgridsize
  • Floatのbalustradeheight
  • Floatのstartsize
  • Floatのendsize
  • Toggleのstartprop
  • Toggleのendprop
  • Ordered Menuのlod
  • Toggleのgenerateuv

lodのOrdered Menuのメニュー項目を次のようにして作ります。

適当に初期値を入れておきます。

橋の裏側部分のモデリング

最初に橋の裏側の底の部分を作っていきます。

Gridノードを作成します。

作成したgrid1ノードのパラメータを次のように設定します。

Sizeはxyそれぞれch("../parameters/sizex")ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")です。

nullノードを作成し、bottom_part0_lod2と名付けて次のように接続します。

Clipノードを作成し次のように接続します。

作成したclip1ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し次のように接続します。

作成したrect_trim_off_edge1ノードのパラメータを次のように設定します。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude1ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し次のように接続します。

作成したrect_trim_off_edge2ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し次のように接続します。

作成したrect_trim_off_edge3ノードのパラメータを次のように設定します。

Rect Multi Splitノードを作成し次のように接続します。

作成したrect_multi_split1ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し次のように接続します。

作成したrect_trim_off_edge4ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し次のように接続します。

作成したrect_trim_off_edge5ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し次のように接続します。

作成したrect_trim_off_edge6ノードのパラメータを次のように設定します。

Rect Multi Splitノードを作成し次のように接続します。

作成したrect_multi_split2ノードのパラメータを次のように設定します。

Mirrorノードを作成し次のように接続します。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude2ノードのパラメータを次のように設定します。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude3ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

nullノードを作成し、bottom_part0_lod1_lod0と名付けて次のように接続します。

Rect Multi Splitノードを作成し次のように接続します。

作成したrect_multi_split3ノードのパラメータを次のように設定します。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude4ノードのパラメータを次のように設定します。

Groupノードを作成し、次のように接続します。

作成したgroup1ノードのパラメータを次のように設定します。

Sizeはch("../grid1/sizex")ch("../grid1/sizey") - 0.5です。

Colorノードを作成し、次のように接続します。

作成したcolor1ノードのパラメータを次のように設定します。

Edge Damageノードを作成し、次のように接続します。

Edge DamageノードのEdge Groupにedgedamagegroupを設定しその他の設定をよい感じに適当にします。

Normalノードを作成し接続します。

nullノードを作成し、bottom_part0_hiと名付けて次のように接続します。

作成したbottom_part0のノードを選択し、Shift+Oでネットワークボックスで囲います。

Blastノードを作成し、次のようにrect_multi_split2ノードから接続します。

blast1ノードのパラメータを次のように設定します。

Primitive Wrangleノードを作成し、次のように接続します。

作成したprimitivewrangle1のVEXを次のように記述します。

1
2
3
4
5
for (int i = 1; i < 4; i++) {
int pt = primpoint(geoself(), @primnum, i);
removepoint(geoself(), pt);
}
removeprim(geoself(), @primnum, 0);

1つ目のポイントだけを残して残りを削除しています。

Sortノードを作成し、次のように接続します。

作成したsort1ノードのパラメータを次のように設定します。

Point Wrangleノードを作成し、次のように接続します。

作成したpointwrangle1ノードのVEXを次のように記述します。

1
2
3
4
5
6
7
8
9
10
11
12
float x = ch("../parameters/sizex");
float w = ch("../parameters/gridsizex");
int xcount = floor(((x / 2) - (0.2 + 0.2) - (w / 5)) / (w + w * 2 / 5));
int n = @ptnum % xcount;

if (n % 3 == 0) {
setpointgroup(geoself(), "g0", @ptnum, 1);
} else if (n % 3 == 1) {
setpointgroup(geoself(), "g1", @ptnum, 1);
} else {
setpointgroup(geoself(), "g2", @ptnum, 1);
}

x軸方向の点の数をカウントし、現在の頂点がx軸方向に何番目かを計算しnとしています。 nを3で割ったあまりで頂点をグループに加えています。

x軸方向の分割数が増えた場合に3こずつ繰り返すようになっています。

Blastノードを作成し、次のように接続します。

作成したblast2ノードのパラメータを次のように設定します。

nullノードを作成しpoints_to_copy_0と名付け、次のように接続します。

Blastノードを作成し、次のように接続します。

作成したblast3ノードのパラメータを次のように設定します。

Transformノードを作成し、接続します。

作成したtransform1ノードのパラメータを次のように設定します。

Fuseノードを作成し、次のように接続します。

nullノードを作成しpoints_to_copy_1と名付け、次のように接続します。

Blastノードを作成し、次のように接続します。

作成したblast4ノードのパラメータを次のように設定します。

Transformノードを作成し、接続します。

作成したtransform2ノードのパラメータを次のように設定します。

Fuseノードを作成し、次のように接続します。

nullノードを作成しpoints_to_copy_2と名付け、次のように接続します。

Boxノードを作成します。

作成したbox1ノードのパラメータを次のように設定します。

Point Wrangleノードを作成し、次のように接続します。

作成したpointwrangle2ノードのVEXに次のように記述します。

1
2
3
4
5
6
7
8
float x = ch("../parameters/sizex");
float w = ch("../parameters/gridsizex");
x = x / 2;
x = x - (0.2 + 0.2 + w *2 / 5 + w / 5);
int count = floor((x + w * 2 / 5) / (w + w * 2 / 5));
float width = (x + w * 2 / 5) / count - w * 2 / 5;
v@P.x *= (width + 0.2);
v@P.x -= 0.1;

先ほど作成したRect Trim Off EdgeノードとRect Multi Splitノードと同じ計算をやってgridの横幅を求めてwidthに代入しています。 横幅1のジオメトリのポイントのx座標をwidth + 0.2倍して、-0.1することで、グリッドに大きさを合わせて左右がちょっとはみ出すようにしています。

Editノードを作成し、次のように接続します。

作成したedit1ノードのパラメータを次のように設定します。

Deleteノードを作成し、次のように接続します。

作成したdelete1ノードのパラメータを次のように設定します。

Mirrorノードを作成し、接続します。

作成したmirror2ノードのパラメータを次のように設定します。

Point Wrangleノードを作成し、次のように接続します。

作成したpointwrangle3ノードのVEXを次のように記述します。

1
2
3
4
5
6
7
8
9
vector bbsize = getbbox_size(geoself());

float z = ch("../grid1/sizey");
float w = ch("../parameters/gridsizey");
z = z - (0.5 + 0.5);
int count = floor((z + w / 4) / (w + w / 4));
float width = (z + w / 4) / count - w / 4;

v@P.z *= width / bbsize.z;

バウンディングボックスのサイズと、計算したgridのサイズをもとにz方向の大きさを合わせています。

Labs Axis Align (Beta)ノードを作成し、接続します。

作成したaxis_align1ノードのパラメータを次のように設定します。

Object Mergeノードを作成し次のように配置します。

作成したobject_merge1ノードのパラメータを次のように設定します。

Copy To Pointsノードを作成し、次のように接続します。

Clipノードを作成し次のように接続します。

作成したclip2ノードのパラメータを次のように設定します。

Normalノードを作成し接続します。

nullノードを作成し、bottom_part1_lod1_lod0と名付け、次のように接続します。

Groupノードを作成し、次のように接続します。

作成したgroup2ノードのパラメータを次のように設定します。

Sizeはch("../grid1/sizex")ch("../grid1/sizey")です。

Poly Fillノードを作成し、次のように接続します。

Colorノードを作成し接続します。

作成したcolorノードのパラメータを次のように設定します。

Edge Damageノードを次のように接続します。

接続したedte_damage2ノードの設定を次のようにします。

Normalノードを作成し接続します。

作成したnormal4ノードのパラメータを次のように設定します。

nullノードを作成し、bottom_part1_hiと名付け、次のように接続します。

bottom part1のノードを選択してShift+Oでネットワークボックスに囲います。

Lineノード作成し、次のように配置します。

作成したline1ノードのパラメータを次のように設定します。

Circleノードを作成し、次のように配置します。

作成したcircle1ノードのパラメータを次のように設定します。

Sweepノードを作成し、次のように接続します。

作成したsweep1ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

次にTransformノードを作成し、次のように接続します。

作成したtransform3ノードのパラメータを次のように設定します。

Sweepノードを作成し、次のように接続します。

作成したsweep2ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

次にTransformノードを作成し、次のように接続します。

作成したtransform4ノードのパラメータを次のように設定します。

Sweepノードを作成し、次のように接続します。

作成したsweep3ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

Lineノードを作成し、次のように配置します。

作成したline2ノードのパラメータを次のように設定します。

次にTransformノードを作成し、次のように接続します。

作成したtransform5ノードのパラメータを次のように設定します。

Sweepノードを作成し、次のように接続します。

作成したsweep4ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

bolt_000ノードを作成し、次のように配置します。

作成したbolt_000ノードのパラメータを次のように設定します。

Circleノードを作成し、次のように配置します。

作成したcircle2ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

作成したnormal5ノードのパラメータを次のように設定します。

Copy To Pointsノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform6ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Normalノードをbolt_000の直後に入れます。

Resampleノードを作成し、次のように接続します。

作成したresample1ノードのパラメータを次のように設定します。

Copy To Pointノードを作成し次のように接続します。

Mergeノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform7ノードのパラメータを次のように設定します。

Resampleノードを作成し、次のように接続します。

作成したresample2ノードのパラメータを次のように設定します。

Copy To Pointノードを作成し次のように接続します。

Mergeノードを作成し、次のように接続します。

Resampleノードを作成し、次のように接続します。

作成したresample3ノードのパラメータを次のように設定します。

Copy To Pointノードを作成し次のように接続します。

Mergeノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform8ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor3ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform9ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor4ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform10ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor5ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Object Mergeノードを作成し次のように配置します。

作成したobject_mergeノードのパラメータを次のように設定します。

Copy To Pointsノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

作成したmirrorノードのパラメータを次のように設定します。

Object Mergeノードを作成し次のように配置します。

作成したobject_mergeノードのパラメータを次のように設定します。

Copy To Pointsノードを作成し、次のように接続します。

Mergeノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform11ノードのパラメータを次のように設定します。

nullノードを作成しbottom_part2_hiと名付け、次のように接続をします。

bottom_part2_hiのノードをすべて選択してShift+Oでネットワークボックスに囲います。

bottom_part2_hiのネットワークボックスを選択してCtrl+Cでコピーし、Ctrl+Vで貼り付けます。

貼り付けたネットワークボックス内部の右上のボルトを配置している部分を選択し、Delキーで削除します。

circle4ノードのパラメータを変更します。

sweep5、sweep6、sweep7、sweep8のパラメータを次のように変更します。

color6、color7、color8ノードを削除します。

bottom_part2_hi1ノードの名前をbottom_part2_lod0に変更します。

bottom_part2_lod0のネットワークボックスを選択してCtrl+Cでコピーし、Ctrl+Vで貼り付けます。

貼り付けたボックス内部のcircle5ノードを選択し、パラメータを変更します。

bottom_part2のhiとlod0とlod1のネットワークボックスを選択し、Shift+Oで更にネットワークボックスに囲います。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge8のパラメータを次のように設定します。

nullノードをつなげて、bottom_lod2と名付けます。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge9のパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge10のパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge11のパラメータを次のように設定します。

Mergeノードを作成し、次のようにつなげます。

すっかり忘れていたのですがpart1にミラーを加えます。

nullノードをつなげて、bottom_lod1と名付けます。

次のノードをコピー&ペーストします。

object_merge14のノードのパラメータを変更します。

さらにノードをペーストします。

object_merge15、object_merge16、object_merge17のパラメータを変更します。

Shift+Oで最後の部分をまとめます。

bottom作成部分をShift+Oでさらに囲います。 ネットワークボックスを選択した状態で、Cキーを押して色を選ぶとネットワークボックスに色を与えられます。

橋の天面のモデリング

次は天面を作ります。 今回は通常の道路ではなく、Sci-Fiな感じのパネルで分割された物を作ります。

Gridノードを作成し、次のように配置します。

配置したgrid2ノードのパラメータを次のように設定します。

Sizeはxyそれぞれch("../parameters/sizex") - 0.6ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")です。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude5ノードのパラメータを次のように設定します。

Deleteノードを作成し、次のように接続します。

作成したdelete2ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

nullノードを作成し、top_lod2と名付けます。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge7ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge8ノードのパラメータを次のように設定します。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude6ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

nullノードを作成し、top_lod1と名付けます。

Blastノードを作成し、次のように接続します。

作成したblast5ノードのパラメータを次のように設定します。

Blastノードを作成し、次のように接続します。

作成したblast6ノードのパラメータを次のように設定します。

Labs Lot Subdivision (beta)ノードを作成し、次のように接続します。

作成したlot_subdivision1ノードのパラメータを次のように設定します。

For-Each Primitiveを作成し、次のように接続します。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude7ノードのパラメータを次のように設定します。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude8ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

Blastノードを作成し、次のように接続します。

作成したblast7ノードのパラメータを次のように設定します。

Convert Lineノードを作成し、次のように接続します。

Group Expressionノードを作成し、次のように接続します。

作成したgroupexpression1ノードのパラメータを次のように設定します。

Deleteノードを作成し、次のように接続します。

作成したdelete3ノードのパラメータを次のように設定します。

For-Each Primitiveを作成し、次のように接続します。

Resampleノードを作成し、次のように接続します。

PolyFrameノードを作成し、次のように接続します。

作成したpolyframe1ノードのパラメータを次のように設定します。

Point Wrangleノードを作成し、次のように接続します。

作成したpointwrangle4ノードのVEXを次のように記述します。

1
2
3
if (@ptnum <= 1 || @ptnum > 4) {
removepoint(geoself(), @ptnum, 1);
}

Circleノードを作成し、次のように配置します。

作成したcircle6ノードのパラメータを次のように設定します。

Clipノードを作成し、次のように接続します。

作成したclip3ノードのパラメータを次のように設定します。

Attribute Createノードを作成し、次のように接続します。

作成したattribcreate1ノードのパラメータを次のように設定します。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude9ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform29ノードのパラメータを次のように設定します。

Mirrorノードを作成し、次のように接続します。

作成したmirror11ノードのパラメータを次のように設定します。

Poly Extrudeノードを作成し、次のように接続します。

作成したpolyextrude10ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform30ノードのパラメータを次のように設定します。

Copy To Pointsノードを作成し、次のように接続します。

Booleanノードを作成し、次のように接続します。

作成したboolean1ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Altキーを押しながらコネクションをクリックしてドットを打ち、見やすくします。

nullノードをつなげて、top_lod0と名付けます。

忘れていたNormalノードを次の位置に挿します。

Group Expressionノードを作成し、次のようにつなげます。

作成したgroupexpression2ノードのパラメータを次のように設定します。

Group Promoteノードを作成し、次のように接続します。

作成したgrouppromote1ノードのパラメータを次のように設定します。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel1ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor6Dノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor7ノードのパラメータを次のように設定します。

nullノードをつなげて、top_hiと名付けます。

lod2とlod1とlod0のnullノードを下に引っ張ってきます。

topの各lodのnullノードを選択して、Shict+Oでネットワークボックスに囲います。

topのノードを選択してShift+Oでネットワークボックスに囲います。 Cキーでネットワークボックスに色を付けます。

天面はこれで完成です。

橋の欄干部分のモデリング

欄干部分を作っていきます。

Gridノードを作成し、次のように配置します。

作成したgrid3ノードのパラメータを次のように設定します。

Sizeはch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")ch("../parameters/balustradeheight")、Centerのyはch("sizey") / 2で。。

Transformノードを作成し、次のように接続します。

作成したtransform31ノードのパラメータを次のように設定します。

ch("../parameters/sizex") / 2です。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude11ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude12ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成しbalustrade_part0_lod2と名付け、次のように接続します。

Deleteノードを作成し、次のように接続します。

作成したdelete4ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge9ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge10ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge11ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge12ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude13ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge13ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge14ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge15ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge16ノードのパラメータを次のように設定します。

Rect Multi Splitノードを作成し、次のように接続します。

作成したrect_multi_split4ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude14ノードのパラメータを次のように設定します。

Blastノードを作成し、次のように接続します。

作成したblast8ノードのパラメータを次のように設定します。

Editノードを作成し、次のように配置します。

作成したedit2ノードのパラメータを次のように設定します。

Editノードを作成し、次のように配置します。

作成したedit3ノードのパラメータを次のように設定します。

Editノードを作成し、次のように配置します。

作成したedit4ノードのパラメータを次のように設定します。

y

Editノードを作成し、次のように配置します。

作成したedit5ノードのパラメータを次のように設定します。

]

Transformノードを作成し、次のように接続します。

作成したtransform32ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform33ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude15ノードのパラメータを次のように設定します。

Mirrorノードを作成し、次のように接続します。

作成したmirror13ノードのパラメータを次のように設定します。

Booleanノードを作成し、次のように接続します。

作成したboolean2ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Fuseノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成しbalustrade_part0_lod1と名付け、次のように接続します。

Blastノードを作成し、次のように接続します。

接続したblast9ノードのパラメータを次のように設定します。

Blastノードを作成し、次のように接続します。

接続したblast10ノードのパラメータを次のように設定します。

Rect Multi Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge17ノードのパラメータを次のように設定します。

Blastノードを作成し、次のように接続します。

作成したblast11ノードのパラメータを次のように設定します。

Blastノードを作成し、次のように接続します。

作成したblast12ノードのパラメータを次のように設定します。

Labs Lot Subdivision (Beta)ノードを作成し、次のように接続します。

作成したlot_subdivision2ノードのパラメータを次のように設定します。

For-Each Primitiveノードを作成し、次のように接続します。

PolyExtrudeノードを作成し、次のように接続します。

接続したpolyextrude16ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

接続したpolyextrude17ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Alt+LMBでドットを打ちます。

Mergeノードを作成し、次のように接続します。

Alt+LMBでドットを打ちます。

Fuseノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成しbalustrade_part0_lod0と名付け、次のように接続します。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel2ノードのパラメータを次のように設定します。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel3ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor8ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

作成したnormal27ノードのパラメータを次のように設定します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成しbalustrade_part0_hiと名付け、次のように接続します。

balustrade_part0のノードを選択し、Shift+Oでネットワークボックスに囲います。

Boxノードを作成し、次のように配置します。

作成したbox2ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform34ノードのパラメータを次のように設定します。

Boxノードを作成し、次のように配置します。

作成したbox3ノードのパラメータを次のように設定します。

Booleanノードを作成し、次のように接続します。

作成したbooleanXノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform35ノードのパラメータを次のように設定します。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel4ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor9ノードのパラメータを次のように設定します。

Bolt 000ノードを作成し、次のように配置します。

作成したbolt_001ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor10ノードのパラメータを次のように設定します。

Gridノードを作成し、次のように配置します。

作成したgrid4ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

作成したnormal28ノードのパラメータを次のように設定します。

Copy To Pointsノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform36ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform37ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Mergeノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

作成したnormal29ノードのパラメータを次のように設定します。

Lineノードを作成し、次のように配置します。

作成したline7ノードのパラメータを次のように設定します。

Originのzは-ch("../dist") / 2、Lengthはch("../grid3/sizex") -0.4です。

Transformノードを作成し、次のように接続します。

作成したtransform38ノードのパラメータを次のように設定します。

Translateのxは-ch("../parameters/sizex") / 2 + 0.31です。

Resampleノードを作成し、次のように設定します。

作成したresample11ノードのパラメータを次のように設定します。

Copy To Pointsノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成しbalustrade_part1_hiと名付け、次のように接続します。

balustrade_part1_hiのノードを選択し、Shift+Oでネットワークボックスに囲います。

balustrade_part1_hiのネットワークボックスを選択し、コピーしてペーストします。

ペーストしたノードからcolor11とcolor12ノード、polybevel5ノードを削除します。

Deleteノードを作成し、次のように接続します。

作成したdelete5ノードのパラメータを次のように設定します。

bolt_002ノードのパラメータを次のように変更します。

nullノードの名前をbalustrade_part1_lod0に変更します。

balustrade_part1_lod0のネットワークボックスを選択し、コピー&ペーストします。

次のようにボルトの部分を選択して削除します。

balustrade_part1のノードを全部選択し、Shift+Oでネットワークボックスに囲います。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge18ノードのパラメータを次のように設定します。

nullノードを作成しbalustrade_lod2と名付け、次のように接続します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge19ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge20ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

nullノードを作成しbalustrade_lod1と名付け、次のように接続します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge21ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge22ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

nullノードを作成しbalustrade_lod0と名付け、次のように接続します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge23ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge24ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

nullノードを作成しbalustrade_hiと名付け、次のように接続します。

最後の各LODの出力部分を選択し、Shift+Oでネットワークボックスに囲います。

balustradeのノード全体を選択し、Shift+Oでネットワークボックスに囲います。 Cキーで色を選んでネットワークボックスに色を付けます。

橋の開始端部分のモデリング

Boxノードを作成し、次のように配置します。

Transformノードを作成し、次のように接続します。

作成したtransform48ノードのパラメータを次用に変更します。

Transformノードを作成し、次のように接続します。

作成したtransform49ノードのパラメータを次のように変更します。

Translateのxはch("../parameters/sizex") / 2 - 0.15です。 Translateのzは-(ch(../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2です。 Scaleのxは0.3です。 Scaleのyはch("../parameters/balustradeheight") - 0.25です。 Scaleのzはch("../parameters/startsize")です。

Mirrorノードを作成し、次のように接続します。

Deleteノードを作成し、次のように接続します。

作成したdelete7ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

nullノードを作成し、start_part0_lod2_lod1_lod0と名付け、次のように接続します。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel5ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor11ノードのパラメータを次のように設定します。

VDB from Polygonsノードを作成し、次のように接続します。

作成したvdbfrompolygons1のノードのパラメータを次のように設定します。

VDB Smooth SDFノードを作成し、次のように接続します。

Convertノードを作成し、次のように接続します。

Remeshノードを作成し、次のように接続します。

作成したremesh1ノードのパラメータを次のように設定します。

Peakノードを作成し、次のように接続します。

作成したpeak1ノードのパラメータを次のように設定します。

Moutainノードを作成し、次のように接続します。

mountain1ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor12ノードのパラメータを次のように設定します。

Booleanノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

作成したnormal34ノードのパラメータを次のように設定します。

nullノードを作成し、start_part0_hiと名付け、次のように接続します。

start_part0のノードを選択し、Shift+Oでネットワークボックスに囲います。

Boxノードを作成し、次のように配置します。

作成したbox9ノードのパラメータを次のように設定します。

Sizeのxはch("../parameters/sizex") - 0.6です。 Sizeのyは0.35です。 Sizeのzはch("../parameters/startsize")です。 Centerのyはch("sizey") / 2 + 0.25です。 Centerのzは-ch("../parameters/startsize") / 2です。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel6ノードのパラメータを次のように設定します。

Fuseノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform50ノードのパラメータを次のように設定します。

Translateのzは-(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2です。

Normalノードを作成し、次のように接続します。

nullノードを作成し、start_part1_lod2と名付け、次のように接続します。

Boxノードを作成し、次のように配置します。

作成したbox10ノードのパラメータを次のように設定します。

Sizeのyは0.35です。 Sizeのzはch("../parameters/startsize")です。 Centerのyはch("sizey") / 2です。 Centerのzは-ch("../parameters/startsize") / 2です。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel7ノードのパラメータを次のように設定します。

Fuseノードを作成し、次のように接続します。

Point Wrangleノードを作成し、次のように接続します。

作成したpointwrangle5ノードのVEXに次のように記述します。

1
2
3
4
float x = ch("../parameters/sizex") - 0.6;
int count = floor(x / 1.2);
float width = x / count;
v@P.x *= width;

横幅1.2を基準として橋の横幅に詰め込めるように横幅のスケーリングしています。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel8ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

作成したnormal36ノードのパラメータを次のように設定します。

Attribute Wrangleノードを作成し、次のように接続します。

作成したattribwrangle1ノードのパラメータを次のように設定し、VEXに次のように記述します。

1
2
3
4
5
6
7
8
9
10
11
12
float x = ch("../parameters/sizex") - 0.6;
float y = 0.25;
float z = -(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2;
int count = floor(x / 1.2);
float width = x / count;
for (int i = 0; i < count; i++) {
vector pos;
pos.x = width * i - x / 2;
pos.y = y;
pos.z = z;
addpoint(geoself(), pos);
}

1ピースの横幅と並べるピース数をもとにピースを並べるためのポイントを追加しています。

Copy to Pointsノードを作成し、次のように接続します。

nullノードを作成し、start_part1_lod1_lod0と名付け、次のように接続します。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel9ノードのパラメータを次のように設定します。

VDB from Polygonsノードを作成し、次のように接続します。

作成したvdbfrompolygons2ノードのパラメータを次のように設定します。

Attribute Wrangleノードを作成し、次のように配置します。

作成したattribwrangle2ノードのパラメータを次のように設定し、VEXに次のように記述します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
float height = 0.35;
float baselength = ch("../parameters/startsize");
float x = ch("../parameters/sizex") - 0.6;
int count = floor(x / 1.2);
float width = x / count;

vector pos0, pos1;
pos0.y = height;
pos1.z = -baselength;
vector dir = normalize(pos1 - pos0);

pos0.x = 0;
pos0.y = height;
pos0.z = 0;
pos1.x = width;
pos1.y = height;
pos1.z = 0;
int pt0, pt1;
int prim;
while(pos0.y > 0.08) {
pos0 += dir * 0.15;
pos1 += dir * 0.15;
pt0 = addpoint(geoself(), pos0);
pt1 = addpoint(geoself(), pos1);
prim = addprim(geoself(), "polyline", pt0, pt1);
setprimgroup(geoself(), "g", prim, 1);
}

次の図のようにライン状のprimitiveを配置しています。

PolyWireノードを作成し、次のように接続します。

作成したpolyeire1ノードのパラメータを次のように設定します。

VDB From Polygonsノードを作成し、次のように接続します。

作成したvdbfrompolygons3ノードのパラメータを次のように設定します。

VDB Combineノードを作成し、次のように接続します。

作成したvdbcombine1ノードのパラメータを次のように設定します。

VDB Smooth SDFノードを作成し、次のように接続します。

作成したvdbsmoothsdf2ノードのパラメータを次のように設定します。

Convertノードを作成し、次のように接続します。

Booleanノードを作成し、次のように接続します。

作成したboolean7ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor13ノードのパラメータを次のように設定します。

Copy To Pointsノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

nullノードを作成し、start_part1_hiと名付け、次のように接続します。

start_part1のノードをすべて選択し、Shift+Oでネットワークボックスに囲います。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge25ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge26ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

nullノードを作成し、start_lod2と名付け、次のように接続します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge27ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge28yノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

nullノードを作成し、start_lod1と名付け、次のように接続します。

start_lod1のノードをコピーし、ペースとします。

start_lod3となっているnullノードの名前をstart_lod0にリネームします。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge31ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge32ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

nullノードを作成し、start_hiと名付け、次のように接続します。

最後のObject Merge群をすべて選択し、Shift+Oでネットワークボックスに囲います。

start部分のノードをすべて選択し、Shift+Oでネットワークボックスに囲います。 Cキーで色を選んでネットワークボックスに色を付けます。

橋の終端部分のモデリング

前後反転して、ch("../parameters/startsize")ch("../parameters/endsize")に変更したものを作っていきます。

startのネットワークボックスをコピーし、隣にペーストします。

ペーストしたpart0のboxの下のtransformの値を編集します。

さらにその下のtransformの値を編集します。

Translateのzを-をとって(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2です。 Scaleのzはch("../parameters/endsize")です。

Deleteノードも編集します。

下につながっているnullノードの名前を変更します。

boxのノードのパラメータも変更します。

Sizeのzがch("../parameters/endsize")で、Centerのzがch("../parameters/endsize") / 2です。

polybevelのノードのパラメータも変更します。

transformのノードのパラメータも変更します。

(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2です。

つながっているnullノードの名前を変更します。

box13のノードのパラメータも変更します。

Sizeのzがch("../parameters/endsize")で、Centerのzがch("../parameters/endsize") / 2です。

次のpolybevelのノードのパラメータも変更します。

attribwrangleのノードのVEXを変更します。

1
2
3
4
5
6
7
8
9
10
11
12
13
float x = ch("../parameters/sizex") - 0.6;
float y = 0.25;
-float z = -(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2;
+float z = (ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2;
int count = floor(x / 1.2);
float width = x / count;
for (int i = 0; i < count; i++) {
vector pos;
pos.x = width * i - x / 2;
pos.y = y;
pos.z = z;
addpoint(geoself(), pos);
}

nullノードの名前を変更します。

attribwrangleのノードのVEXを変更します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
float height = 0.35;
-float baselength = ch("../parameters/startsize");
+float baselength = ch("../parameters/endsize");
float x = ch("../parameters/sizex") - 0.6;
int count = floor(x / 1.2);
float width = x / count;

vector pos0, pos1;
pos0.y = height;
-pos1.z = -baselength;
+pos1.z = baselength;
vector dir = normalize(pos1 - pos0);

pos0.x = 0;
pos0.y = height;
pos0.z = 0;
pos1.x = width;
pos1.y = height;
pos1.z = 0;
int pt0, pt1;
int prim;
while(pos0.y > 0.08) {
pos0 += dir * 0.15;
pos1 += dir * 0.15;
pt0 = addpoint(geoself(), pos0);
pt1 = addpoint(geoself(), pos1);
prim = addprim(geoself(), "polyline", pt0, pt1);
setprimgroup(geoself(), "g", prim, 1);
}

nullノードの名前を変更します。

nullノードの名前を変更します。

橋の側面の小物1の作成

次に側面の小物1を作っていきます。

Gridノードを作成し、次のように配置します。

作成したgrid6ノードのパラメータを次のように設定します。

Sizeのxがch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize") - 3.6で、yが0.8です。

Rect Multi Splitノードを作成し、次のように接続します。

作成したrect_multi_split5ノードのパラメータを次のように設定します。

Deleteノードを作成し、次のように接続します。

作成したdelete9ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform54ノードのパラメータを次のように設定します。

Translateのxはch("../parameters/sizex") / 2です。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude18ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform55ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成し、sideprops1_part0_lod1_lod0と名付け、次のように接続します。

nullノードを作成し、sideprops1_part1_rectanglesと名付け、次のように接続します。

Colorノードを作成し、次のように接続します。

作成したcolor17ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor18ノードのパラメータを次のように設定します。

nullノードを作成し、sideprops1_part0_hiと名付け、次のように接続します。

sideprops1_part0のノードをすべて選択し、Shift+Oでネットワークボックスに囲います。

Object Mergeノードを作成し、次のように配置します。

S

作成したobject_merge41ノードのパラメータを次のように設定します。

For-Each Primitiveノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform56ノードのパラメータを次のように設定します。

Pivot Translateのzはcentroid("../foreach_begin4", D_Z)です。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude19ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform57ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

nullノードを作成し、sideprops1_part1_lod1と名付け、次のように接続します。

sideprops1_part1_lod1のノードをすべて選択し、Shift+Oでネットワークボックスに囲います。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge42ノードのパラメータを次のように設定します。

For-Each Primitiveノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform58ノードのパラメータを次のように設定します。

Pivot Translateのzはcentroid("../foreach_begin5", D_Z)です。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude20ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform59ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel15ノードのパラメータを次のように設定します。

Deleteノードを作成し、次のように接続します。

作成したdelete10ノードのパラメータを次のように設定します。

For-Each Primitiveノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform60ノードのパラメータを次のように設定します。

Pivot Translateのxはcentroid("../foreach_begin6", D_X)で、yはcentroid("../foreach_begin6", D_Y)で、zはcentroid("../foreach_begin6", D_Z)です。

Bolt 000ノードを作成し、次のように接続します。

作成したbolt_003ノードのパラメータを次のように設定します。

Copy to Pointsノードを作成し、次のように接続します。

Mergeノードを作成し、次のように接続します。

Normalノードを作成し、接続します。

nullノードを作成し、sideprops1_part1_lod0と名付け、次のように接続します。

sideprops1_part1_lod0のノードをすべて選択し、Shift+Oでネットワークボックスに囲います。

sideprops1_part1_lod0のネットワークボックスをコピーし、ペーストします。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel17ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor19ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor20ノードのパラメータを次のように設定します。

bolt_004のパラメータを次のように変更します。

normal46ノードのパラメータを変更します。

nullノードにsideprops1_part1_hiと名付け、次のように接続します。

sideprops1_part1のノードをすべて選択し、Shift+Oでネットワークボックスに囲います。

nullノードを作成し、sideprops1_lod2と名付け、次のように配置します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge44ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge45ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

nullノードを作成し、sideprops1_lod1と名付け、次のように接続します。

Object Mergeノードを作成し、次のように配置します。

sideprops1_lod1のObject Merge以下をコピーしペーストします。

object_merge47ノードのパラメータを次のように設定します。

nullノードにsideprops1_lod0と名付けます。

sideprops1_lod0のObject Merge以下をコピーしペーストします。

object_merge48ノードのパラメータを次のように設定します。

object_merge49ノードのパラメータを次のように設定します。

nullノードにsideprops1_hiと名付けます。

最後の各lodのnullノードとObject Mergeノードを選択してShift+Oでネットワークボックスに囲います。

sideprops1のノード全体をShift+Oでネットワークボックスに囲います。 Cキーでネットワークボックスに色を付けます。

橋の側面の小物2の作成

次に側面の小物2を作っていきます。

Boxノードを作成し、次のように配置します。

作成したbox14ノードのパラメータを次のように設定します。

Lineノードを作成し、次のように配置します。

作成したline10ノードのパラメータを次のように設定します。

Originのxはch("../parameters/sizex") / 2 - 0.1で、yは0.2で、zは-ch("dist") / 2です。 Lengthはch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize") + 0.2です。

Copy to Pointsノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成し、sideprops2_part0_lod2_lod1_lod0と名付け、次のように接続します。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel18ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

作成したnormal48ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor21ノードのパラメータを次のように設定します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成し、sideprops2_part0_hiと名付け、次のように接続します。

sideprops2_part0のノードをShift+Oでネットワークボックスに囲います。

Bolt 000ノードを作成し、次のように配置します。

作成したbolt_005ノードのパラメータを次のように設定します。

Gridノードを作成し、次のように配置します。

作成したgrid7ノードのパラメータを次のように設定します。

Lineノードを作成し、次のように配置します。

作成したline11ノードのパラメータを次のように設定します。

Originのxはch("../parameters/sizex") / 2 - 0.1で、yは0.2で、zは-ch("dist") / 2です。 Lengthはch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize") + 0.2です。

Copy to Pointsノードを作成し、次のように接続します。

Copy to Pointsノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成し、sideprops2_part1_lod1と名付け、次のように接続します。

Bolt 000ノードを作成し、次のように配置します。

作成したbolt_006ノードのパラメータを次のように設定します。

Copy to Pointsノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成し、sideprops2_part1_lod0と名付け、次のように接続します。

Bolt 000ノードを作成し、次のように配置します。

作成したbolt_007ノードのパラメータを次のように設定します。

Copy to Pointsノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

Colorノードを作成し、次のように接続します。

作成したcolor22ノードのパラメータを次のように設定します。

Mirrorノードを作成し、次のように接続します。

nullノードを作成し、sideprops2_part1_hiと名付け、次のように接続します。

sideprops2_part1のノードをShift+Oでネットワークボックスに囲います。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge50ノードのパラメータを次のように設定します。

nullノードを作成し、sideprops2_lod2と名付け、次のように接続します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge51ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge52ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

nullノードを作成し、sideprops2_lod1と名付け、次のように接続します。

sideprops2_lod1のノードをコピーし、ペーストします。

object_merge54ノードのパラメータを次のように設定します。

nullノードをsideprops2_lod0と名付けます。

sideprops2_lod0のノードをコピーし、ペーストします。

object_merge55ノードのパラメータを次のように設定します。

object_merge56ノードのパラメータを次のように設定します。

nullノードをsideprops2_hiと名付けます。

最後の各LODのObject MergeとMergeノード、nullノードを選択してShift+Oでネットワークボックスに囲います。

sideprops2のノード全体を選択し、Shift+Oでネットワークボックスに囲います。 Cキーでネットワークボックスに色を付けます。

開始側の支柱のモデリング

startの支柱を作っていきます。

Boxノードを作成し、次のように配置します。

作成したbox15ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform64ノードのパラメータを次のように設定します。

Translateのyが0.25で、zが-(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2です。 Scaleのxがch("../parameters/sizex") - 0.3で、yがch("../parameters/sizey") - ch("../parameters/balustradeheight") + 0.25で、zがch("../parameters/startsize")です。

Normalノードを作成し、次のように接続します。

Deleteノードを作成し、次のように接続します。

作成したdelete12ノードのパラメータを次のように設定します。

nullノードを作成し、startprop_lod2と名付け、次のように接続します。

Rect Multi Splitノードを作成し、次のように接続します。

作成したrect_multi_split6ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude22ノードのパラメータを次のように設定します。

Deleteノードを作成し、次のように接続します。

作成したdelete13ノードのパラメータを次のように設定します。

nullノードを作成し、startprop_lod1と名付け、次のように接続します。

Groupノードを作成し、次のように接続します。

接続したgroup3ノードのパラメータを次のように設定します。

Sizeのyがch("../parameters/sizey")で、zがch("../parameters/startsize") + 0.2です。 Centerのxがch("../parameters/sizex") / 2で、yが-ch("../parameters/sizey") / 2 + ch("../parameters/balustradeheight") + 0.1で、zが-(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2 - ch("../parameters/startsize") / 2です。

Groupノードを作成し、次のように接続します。

接続したgroup4ノードのパラメータを次のように設定します。

Sizeのyがch("../parameters/sizey")で、zがch("../parameters/startsize") + 0.2です。 Centerのxが-ch("../parameters/sizex") / 2で、yが-ch("../parameters/sizey") / 2 + ch("../parameters/balustradeheight") + 0.1で、zが-(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2 - ch("../parameters/startsize") / 2です。

Group Combineノードを作成し、次のように接続します。

作成したgroupcombine1ノードのパラメータを次のように設定します。

Deleteノードを作成し、次のように接続します。

作成したdelete14ノードのパラメータを次のように設定します。

Rect Trim Off Edgeノードを作成し、次のように接続します。

作成したrect_trim_off_edge18ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

Blastノードを作成し、次のように接続します。

作成したblast13ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude23ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform65ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

nullノードを作成し、startprop_lod0と名付け、次のように接続します。

Colorノードを作成し、次のように接続します。

作成したcolor23ノードのパラメータを次のように設定します。

PolyBevelノードを作成し、次のように接続します。

作成したpolybevel19ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor24ノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor25ノードのパラメータを次のように設定します。

Blastノードを作成し、次のように接続します。

作成したblast14ノードのパラメータを次のように設定します。

For-Each Primitiveノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform66ノードのパラメータを次のように設定します。

Pivot Translateのyはcentroid("../foreach_begin9", D_Y)です。

Addノードを作成し、次のように接続します。

作成したadd1ノードのパラメータを次のように設定します。

y

Resampleノードを作成し、次のように接続します。

作成したresample14ノードのパラメータを次のように設定します。

Fuseノードを作成し、次のように接続します。

Sortノードを作成し、次のように接続します。

作成したsort2ノードのパラメータを次のように設定します。

Sortノードを作成し、次のように接続します。

作成したsortZノードのパラメータを次のように設定します。

Group by Rangeノードを作成し、次のように接続します。

作成したgrouprange1ノードのパラメータを次のように設定します。

Group Promoteノードを作成し、次のように接続します。

作成したgrouppromote2ノードのパラメータを次のように設定します。

Attribute Createノードを作成し、次のように接続します。

作成したattribcreate2ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude24ノードのパラメータを次のように設定します。

Group Combineノードを作成し、次のように接続します。

作成したgroupcombine2ノードのパラメータを次のように設定します。

Equal All But extrudeFrontです。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude25ノードのパラメータを次のように設定します。

Deleteノードを作成し、次のように接続します。

作成したdelete15ノードのパラメータを次のように設定します。

PolyWireノードを作成し、次のように接続します。

さくせいしたpolywireXノードのパラメータを次のように設定します。

Colorノードを作成し、次のように接続します。

作成したcolor26ノードのパラメータを次のように設定します。

Booleanノードを作成し、次のように接続します。

作成したboolean10ノードのパラメータを次のように設定します。

Normalノードを作成し、次のように接続します。

作成したnormal54ノードのパラメータを次のように設定します。

Mergeノードを次のように接続します。

nullノードを作成し、startprop_hiと名付け、次のように接続します。

startpropのnullノードを下の方に引っ張ってきます。

nullノードを選択し、Shift+Oでネットワークボックスに囲います。

startpropのノード全体を選択し、Shift+Oでネットワークボックスに囲います。 Cキーでネットワークボックスに色を付けます。

終端側の支柱のモデリング

startpropを前後反転してstartsizeをendsizeに差し替えたものを作成していきます。

startpropのネットワークボックスをコピーしてペーストします。

box16ノードのパラメータを次のように変更します。

transform68ノードのパラメータを次のように変更します。

Translateのzが(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2です。 Scaleのzがch("../parameters/endsize")です。

delete17ノードのパラメータを次のように設定します。

rect_multi_split7ノードのパラメータを次のように設定します。

group6ノードのパラメータを次のように設定します。

Sizeのzがch("../parameters/endsize") + 0.2です。 Centerのzが(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2 + ch("../parameters/endsize") / 2です。

group5ノードのパラメータを次のように設定します。

Sizeのzがch("../parameters/endsize") + 0.2です。 Centerのzが(ch("../parameters/sizez") - ch("../parameters/startsize") - ch("../parameters/endsize")) / 2 + ch("../parameters/endsize") / 2です。

rect_trim_off_edge19ノードのパラメータを次のように設定します。

transform67ノードのパラメータを次のように設定します。

nullノードの名前を次のように変更します。

モデルの結合

最後に全てをまとめていきます。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge57ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge58ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge59ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge60ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge61ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge62ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge63ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

すっかり忘れていたのですが、Normalノードを作成し、bottom_part0_lod2の前に差し込みます。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge64ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Switchノードを作成し、次のように接続します。

作成したswitch1ノードのパラメータを次のように設定します。

Object Mergeノードを作成し、次のように配置します。

作成したobject_merge65ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Switchノードを作成し、次のように接続します。

作成したswitch2ノードのパラメータを次のように設定します。

Groupノードを作成し、次のように接続します。

作成したgroup7ノードのパラメータを次のように設定します。

指定した角度より大きく曲がっているエッジをUVのシームとしています。

UV Flattenノードを作成し、次のように接続します。

作成したuvflatten1ノードのパラメータを次のように設定します。

UV Layoutノードを作成し、次のように接続します。

作成したuvlayout1ノードのパラメータを次のように設定します。

Switchノードを作成し、次のように接続します。

作成したswitch3ノードのパラメータを次のように設定します。

Divideノードを作成し、次のように接続します。

作成したdivide1ノードのパラメータを次のように接続します。

nullノードを作成し、lod2と名付け、次のように接続します。

Shift+Oでネットワークボックスに囲います。

lod2のネットワークをコピーしペーストします。

Object Mergeのlod2を読み込んでいる部分をlod1に変更します。

最後のnullノードの名前をlod1へ変更します。

lod1のネットワークをコピーしペーストします。

Object Mergeのlod1を読み込んでいる部分をlod0に変更します。

startpropとendpropにDeleteノードを入れ忘れていたので入れます。

それぞれパラメータを次のように設定します。

最後のnullノードの名前をlod0へ変更します。

なんか想定よりもポリゴン数が多いと思ったら、topのノードにミスを発見したので今から修正を行います。

次のようにMergeノードを一つ足してつなぎ直します。

lod0にbooleanをしたものが入らないようにします。

lod0のネットワークをコピーしペーストします。

ハイポリにUVは必要ないため、UV計算をしているノードを削除します。

Object Mergeのlod0を読み込んでいる部分をhiに変更します。

最後のnullノードの名前をhiへ変更します。

Switchノードを作成し、次のように接続します。

作成したswitch12ノードのパラメータを次のように設定します。

Labs Axis Align (Beta)ノードを作成し、次のように接続します。

作成したaxis_align2ノードのパラメータを次のように設定します。

Transformノードを作成し、次のように接続します。

作成したtransform70ノードのパラメータを次のように設定します。

Translateのxはch("../parameters/centerx")で、yはch("../parameters/centery")で、zはch("../parameters/centerz")です。

nullノードを作成し、OUTPUTと名付け、次のように接続し、レンダーフラグをオンにします。

Shift+Oでネットワークボックスに囲います。 Cキーでネットワークボックスに色を付けます。


sideprops1のmirrorを忘れていたので追加していきいます。

HDA化する

組み込みのboxノードなどと同じように、作成した橋のノードもsopレベルとgeometryレベルの両方に用意します。

まずはsopレベルのノードを作成します。

ノード全体を選択して、Shift+Cでノードをサブネットに格納します。

ネットワーク内部に入ると何故か余計なOutputノードが生成されているので削除します。

subnetの名前をbridge_000とします。

今後、他の橋を作るかもしれないので番号を後ろにつけておきました。

Edit Parameter Interfaceを実行します。

最初からあるラベルは非表示にします。

Edit Parameter Interfaceのウィンドウを開いたまま、bridge_000ノードの内部に入ります。

nullに集約しておいたパラメータを全部ドラッグ&ドロップしてパラメータに追加します。

Acceptします。

各種パラメータがサブネット上に現れます。

bridge_000ノードを右クリックしてCreate Digital Asset…を選択します。

名前などを適切に設定し、Acceptを押します。

その後開くEdit Operator Type PropertiesウィンドウでTabキーのパスを指定します。

ハンドルを設定します。

次の図のCreate HandleからBoundingBoxを選択します。

centerx、centery、centerz、sizex、sizey、sizez、uniform_scaleにそれぞれパラメータを次のように割り当てます。

Acceptします。

bridge_000のノードを選択した状態で、シーンビュー上でEnterキーを押すとハンドルが出てきて、それで操作できるようになります。

つぎにgeometryレベルのノードを作成します。

新しく/obj階層でGeometryノードを作成し、bridge_000_geoと名付けます。

bridge_000_geoのノードの内部に入って、Bridge 000ノードを新たに作成します。

/obj階層に戻って、bridge_000_geoノードのEdit Parameter Interfaceを実行します。

フォルダを追加し、Bridge 000と名付けます。

bridge_000_geoノード内部に入り、bridge_000ノードからパラメータをドラッグ&ドロップします。

Acceptします。

bridge_000_geoノードにBridge 000のタブが増えてコントロールできるようになりました。

bridge_000_geoノードを右クリックしてCreate Digital Asset…を実行します。

適当に名前を決めてAcceptします。

場合によっては警告が出るかもしれませんがとりあえずNo Changesします。

先程のsopレベルのノードのときと同様にしてTABキーのパスとHandleを設定します。

Acceptすると警告が出るかもしれませんがNo Changesで。

これでHDAの作成は完了です。


作成した.hiplcファイルです。


引き続き、Unityに持ち込むためのシーンの構築とテクスチャの作成に移りますが、Apprenticeの方はテクスチャ作成用に必要となる頂点カラー付きのモデルを出力する手段がないと思うのでここまでです。 お疲れさまでした。 Apprenticeでもobj書き出しなどはできた気がするのでそういったことを試してみても良いかもしれません。

Indie以上の方は続きへと進みます。

シーンを作成し配置してfbx出力をする

新しいHoudiniのシーンを開きます。

まずは橋を配置する周辺のオブジェクトを作成します。

geoノードを作成します。backgroundと名付けます。

Boxノードを作成し配置します。

作成したbox1ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude1ノードのパラメータを次のように設定します。

PolyExtrudeノードを作成し、次のように接続します。

作成したpolyextrude2ノードのパラメータを次のように設定します。

Mirrorノードを作成し、次のように接続します。

Gridノードを作成し、次のように配置します。

作成したgrid1ノードのパラメータを次のように設定します。

Mergeノードを作成し、次のように接続します。

Normalノードを作成し、次のように接続します。

Transformノードを作成し、次のように接続します。

作成したtransform1ノードのパラメータを次のように設定します。

これで背景は完成です。 ひとつ上の/obj階層に戻ります。

Bridge 000のジオメトリを作成します。

bridge_000_geo1を選択した状態でシーンビューでエンターキーを押し、ハンドルを出して良い感じの大きさに調節します。

Generate UVのチェックを入れておきます。

fbxを出力していきます。 /out階層に移動します。

Filmbox FBXノードを作成し、output_background_fbxと名付けます。

作成したoutput_background_fbxノードのパラメータを次のように設定します。

シーンのhipファイルを適当な場所に保存します。

その後、Sace to Diskを実行するとfbxが保存されています。

同様にして各LODのbridgeを出力してもよいのですが、せっかくなのでPDG/TOPsを使ってみることにします。

Filmbox FBXノードを作成し、output_bridge_fbxと名付けます。

作成したoutput_bridge_fbxノードのパラメータを次のように設定します。

@lodnameはTOPsから与えるものです。

/tasks階層に移動します。

topnet1の名前をoutput_fbxと変更します。

output_fbxの内部に入ります。

Wedgeノードを作成します。

作成したwedge1ノードのパラメータを次のように設定します。

1つ目のTarget Parameterは/obj/itsuki_bridge_000_geo1/lodです。

ROP Fetchノードを作成し、次のように接続します。

作成したropfetch1ノードのパラメータを次のように設定します。

もう一つROP Fetchノードを作成質疑のように配置します。

作成したropfetch2ノードのパラメータを次のように設定します。

Wait for Allノードを作成し、次のように接続し、Outputフラグを立てます。

TasksのGenerate Static Work Itemsを実行してみます。

staticなタスクのドットが表示されました。

TasksのCook Output Nodeを実行します。

Cookが終わるとすべてのLODのfbxが出力されています。

今回はLOD違いを出すためにTOPsを利用しましたが、パラメータ違いのバリエーションを出力して確認したい場合などに便利な機能ですね。


このシーンとTOPsの.hiplcファイルはこちらです。

Substance PainterでのLOD0のテクスチャの作成

次はテクスチャの作成に移ります。 今回は出力したfbxに対してSubstance Painterでテクスチャを作ります。

頑張ればSubstance Designerでテクスチャ作成のノードを作ればフルプロシージャルにテクスチャまで行けそうな気もしますが、今回はSubstance Painterで手作業でテクスチャを作成します。 Substance Painterのパーティクルブラシを使いたいので……。 Substance Designerを使ったフルプロシージャルのマテリアルの構築は読者への課題とするということで。

newしてLOD0のモデルをSubstance Painterで読み込みます。

HDRPのMaskMapのためにTEXTURE SET SETTINGSからBlending maskを追加しておきます。 今回は使いませんが……。

Bake Mesh Mapsを実行します。

Output Sizeを適当に変更し、high Definition Meshsにハイポリのfbxを指定します。

ベイクしようとしたら次のようにエラーを起こしてしまいました。

不正なメッシュが混ざっているとこういう事になりがちです。 ベベルが爆発していたりnon manifoldが含まれていたりなどなど。

normalにnanが含まれている可能性があるので、次のようなVertex Wrangleのノードを作って接続して調べてみます。

1
2
3
vector n = v@N;
int flag = isnan(n.x) || isnan(n.y) || isnan(n.z);
setdetailattrib(geoself(), "NaN", flag, "max");

Geometry SpreadSheetのDetailを見てみるとNanが1になっていてNormalにnanが含まれていることがわかります。

../bottom_hiのObject MergeにつなぐとNaNなNormalは含まれていないようです。

top_hiのノードにはNaNなNormalが含まれているようでした。

このようにしてノードをつなぎ直していくと、polybevel1が問題だったことがわかりました。

polybevel1ノードのパラメータを次のように修正します。

PolyBevel、爆発しやすいので嫌になっちゃいますね。

hdaを変更したら、ノードを右クリックからSave Node Typeを実行します。

橋を配置したシーンファイルを開き、output_fbxのタスクをDirty Allしてfbxを消去してから実行します。

もう一度、Substance Painterのプロジェクトを作り直します。

再度、ハイポリのベイクを行います。

ベイク時にAverage Normalsのチェックを外したほうが良い感じに焼けました。

無事にベイクができました。


マテリアルを割り当てていきます。

コンクリートのマテリアルを適当に選んっでレイヤーにドラッグ&ドロップします。

スケールを8倍にします。

Color Selectionなマスクを追加します。

コンクリートにしたい部分を選択します。

コンクリートのダメージ部分に割り当てるマテリアルを追加します。

こちらもColor Selectionマスクを追加します。

同様にして次々とマテリアルを割り当てていきます。

フォルダを追加します。

フォルダにプラスチックのマテリアルを2個割り当てました。

プラスチックの色を黄色と黒にします。

上川のプラスチックにblackマスクを追加します。

マスクを選択した状態でadd fillを追加します。

AlphasからLine Stripesをドラッグ&ドロップします。

StripeのHeightを1にします。

Scaleを16にしました。

フォルダにColor Selection Maskを追加します。

Fillレイヤーを追加します。

colorとroughだけを出力し、適当に暗い値にします。

BaseColorとRoughのレイヤー合成モードをMultiplyにします。

Fillレイヤーにブラックマスクを追加し、add paintします。

ParticlesのLeaksを使って塗っていきます。

Smart Maskなどを使って汚しを加えていきます。

次の記事のとおりに、HDRP用のテクスチャとLOD1、LOD2のベイクで使うテクスチャを出力します。

UnityのHDRP向けのLOD対応背景アセットのテクスチャを作る | 測度ゼロの抹茶チョコ

Substance DesignerでLOD1、LOD2のテクスチャの作成

次の記事を参考に、LOD1とLOD2のテクスチャを作成します。

UnityのHDRP向けのLOD対応背景アセットのテクスチャを作る | 測度ゼロの抹茶チョコ

UnityのHDRPで表示する

プロジェクトの作成

Unityの新しいHDRPのプロジェクトを作成します。

Package Managerを開いてUpdate to 7.1.7をクリックします。

Project SettingsのEdtirからEnter Play Mode Settingsのオプションをオンにします。 これでだいぶプレイモードへ入るのが早くなります。

fbxのインポートとLODの設定

fbxとテクスチャをUnity上にインポートします。

何故かHoudiniからエクスポートしたfbxをUnityで読み込むと100分の1のスケールになっているので、インポートしたfbxのscaleを100に変更します。

インポートしたNormalとBent NormalマップのTexture Typeを Normal Mapに変更します。

インポートしたMask MapのsRGBのチェックを外します。

Materialを作成します。

マテリアルにテクスチャを割り当てていきます。

bridge_000_LOD0の上で右クリックしてCreateからPrefab Variantを作成します。

作成したVariantのマテリアルを作成したマテリアルに差し替えます。

VariantのTransformをrevertします。

同様にしてLOD1とLOD2のVariantも作成します。

シーンに空のゲームオブジェクトを配置します。

作成したGameObjectの名前をbridge_000に変更します。

bridge_000の子に、作成したVariant3種を配置します。

bridge_000にLOD Groupコンポーネントをアタッチします。

ドラッグ&ドロップして各LODにモデルを割り当てます。

bridge_000をプロジェクトビューにドラッグ&ドロップしてprefab化します。

シーンの設定

Settings/HDRenderPipelineAssetを選択します。

Screen Space ReflectionやScreen Space Shadowなどを有効にします。

新しいシーンを作成します。

Global Volumeを作成します。

newしてプロファイルを作成します。

Overrideを追加してExposure、Ambient Occlusionを設定します。

もう一つGloval Volumeを作成します。

Sky and Fog Volumeと名付けます。 newして新しいプロファイルを作成します。

Add OverrideしてVisual Environment、Fog、Gradient Skyを追加し、適当に設定します。

もう一つGloval Volumeを作成します。

Post Process Volumeと名付けます。 newして新しいプロファイルを作成します。

Add Overrideしてポストプロセスを適当に設定します。

backgroundとbridge_000のprefabを配置します。

Main Cameraの位置を調整します。

Main CameraにSimpleCameraControllerを追加します。

Main Cameraのアンチエイリアスを設定します。

スポットライトを適当に配置します。

Areaライトを配置してみます。

プレイモードに入って右ドラッグとwasdキーで移動して見ることができます。

リアルタイムレイトレのセットアップをする

リアルタイムレイトレーシングに対応したグラフィックカードを利用している場合はリアルタイムレイトレのセットアップをできます。

Window/Render PilelineからHD Render Pipeline Wizardを開いてHDRP + DXRからFix Allを実行します。

エディタをリスタートするように促されます。

リスタートするとエラーが出ていますが気にせず進めます。

HD RenderPiplineAssetから、Realtime Raytracigを有効にします。

Global Volumeから各種レイトレを有効にしていきます。

ライトの設定から影のレイトレの設定も行えます。


一通り設定してみたところ、こんな感じになりました。

おわりに

とても長い記事なりましたが、読んでくださった方はお疲れさまでした。

スクショを大量に撮って貼り付けるのに疲れてしまって、文章の推敲ができていなかったり、VEXなどのプログラム部分の細かい解説などがつけられていません……。 何かわからないことがあったら私のTwitterアカウントまでリプなどをいただければ時間のあるときにお返事できると思います。