チュートリアル データは、[Help] メニュー → [Download Tutorials and Examples…] を選択し、[CityEngine Tutorial] からダウンロードできます。
このチュートリアルでは、ファサード構造の作成、アセットの挿入、建物へのテクスチャの追加など、写真から建物をモデリングする方法を学習します。また、複雑な CGA のテクニックについても学習します。
演習 |
---|
・Part 1 :ファサードの構造をモデリング |
・Part 2 :ファサード アセットの挿入 |
・Part 3 :ファサードのテクスチャを作成 |
以下のワークフローでは、実際の写真からファサードを再作成するための CGA ルール セットを記述する方法を示します
このセッションでは、CGA ルールでファサードの基本構造を作成します。ルール セットの拡張を進めながら、写真をより詳細に分析し、CGA ルールでプリモデルされたアセットをどのように使用できるかを学習します。
ルール ファイルを作成するために、以下の手順を行います。
新しい CGA ルール ファイルが作成され、[CGA Editor] ウィンドウが起動します。CityEngine の現在のバージョンの記述以外は空の状態です。
これから建物の作成を始めます。まず押し出し操作によりマス モデルを作成します。建物の height 属性を使用します。
attr height = 24
Lot --> extrude(height)
Building
Building -->
comp(f) { front : Frontfacade }
上記のファサードの写真を見ると、以下の画像のように、異なるタイプのフロアを分析することができます
attr groundfloor_height = 5.5
attr floor_height = 4.5
Frontfacade -->
split(y) { groundfloor_height : Floor(split.index) // 地上フロア
| floor_height : Floor(split.index) // 第一フロア (二階)
| floor_height : Floor(split.index) // 第二フロア (三階)
| { ~floor_height : Floor(split.index) }* // 中間階
| floor_height : Floor(999) // 最上階、インデックスは999
| 0.5 : s('1, '1, 0.3) LedgeAsset } // 屋根直下のトップレッジ
前面のファサードは水平方向に分割されて、各フロアに floor_height (フロアの高さ) の属性が設定されます。Floor 形状はフロアのインデックスである split.index によってパラメータで制御されます。このパラメータはサブ ルールに渡され、特定のフロアに対して何のエレメントを作成するかを決定します。
最上階の場合、フロア インデックスは 999 に設定されます。これにより、このフロアを識別することができます。また、中層階は繰り返し分割されているため、建物は異なる高さに動的に適応し、中層階で残りの垂直スペースを埋めることができます。
なお、[CGA Editor] ウィンドウには、未定義の Floor ルールと LedgeAsset ルールに対する警告が表示されます。チュートリアルの後半で、このルールを参照するため問題ありません。
Ctrl + S キーを押し、ルールを保存します。
[Navigator] ウィンドウの facade_01.cga ルールを [3D View] ウィンドウの区画の上にドラッグします。 これによって、はじめてファサードが生成されます。
Z キーを押すと、ファサードの正面に移動できます。
ルールを割り当てて別の方法でモデルを生成するには、[Inspector] ウィンドウで [Assign] をクリックし、facade_01.cga ルールを選択して [Generate models of selected shapes] ボタンをクリックします (Ctrl+G キーを押します)。
現在、フロアはレッジとタイルの形状に分割されています。
Floor(floorindex) -->
case floorindex == 0 :
Subfloor(floorindex)
case floorindex == 2 :
split(y) { ~1 : Subfloor(floorindex)
| 0.5 : TopLedge }
else :
split(y) { 1 : BottomLedge(floorindex)
| ~1 : Subfloor(floorindex)
| 0.5 : TopLedge }
フロア インデックスは、異なるフロアの特定のレッジを処理するために使用します。
地上階 (floorindex 0) にはレッジはないため、タイルのみを呼び出します。
二番目のフロア (Floor 2) については、窓領域がフロアの一番下の高さから開始されるため、ボトム レッジはありません。このフロアのバルコニーは後のステップで作成します。
それ以外のフロアにはボトム レッジ、タイルおよびトップ レッジ領域があります。
サブフロアは各フロアの左右端に位置する小さな壁領域とそれらの間の繰り返しタイルで構成されています。
attr tile_width = 3.1
Subfloor(floorindex) -->
split(x){ 0.5 : Wall(1)
| { ~tile_width : Tile(floorindex) }*
| 0.5 : Wall(1) }
これにより、フロアが繰り返しのタイルと両側の壁に水平に分割されます。
attr wallColor = "#ffffff"
Wall(walltype) -->
case walltype == 1 :
color(wallColor)
case walltype == 2 :
color(wallColor)
else :
color(wallColor)
パラメータ化された Wall 形状を追加しました。これは後のステップでファサードにテクスチャを貼り付ける際に重要です。ファサードの写真を見ると、3 つの異なる壁のタイプがあることが分かります。
暗いブロックのダート テクスチャ
明るいブロックのダート テクスチャ
ダート テクスチャのみ。これは主にブロック構造を持たないファサード アセットに対して必要となります。
上記の Wall ルールの壁スタイルは、同一の出力を生成します。前述したように、後のステップで壁のタイプごとに異なるテクスチャを追加することで変更されます。
このファサードのタイルは均質になっています。ここで地上フロアのタイルとそれより上の階のタイルを区別する必要があります。
attr door_width = 2.1
attr window_width = 1.4
Tile(floorindex) -->
case floorindex == 0 :
split(x){ ~1 : SolidWall
| door_width : DoorTile
| ~1 : SolidWall }
else :
split(x){ ~1 : Wall(getWalltype(floorindex))
| window_width : WindowTile(floorindex)
| ~1 : Wall(getWalltype(floorindex)) }
地上フロアのタイルでは、Wall 形状の代わりに SolidWall 形状が追加されます。これは、地上フロアのドアがファサードからめり込んだ状態になっているために必要になります。ドアと壁の間に穴ができるのを防ぐために、特定の厚さを持った立体を挿入することにより、壁エレメントを作ります。この厚さは後の Door ルールでも使用するため、これを定数変数 wall_inset として定義します。
複数回使用される値を宣言しておくと、同じ値が別のルールで使用されることを確認できることにもなり、便利です。
const wall_inset = 0.4
SolidWall -->
s('1, '1, wall_inset)
t(0, 0, -wall_inset)
i("builtin:cube:notex")
Wall(1)
getWalltype(floorindex) =
case floorindex == 0 : 1
case floorindex == 1 : 1
else : 2
ファサードの写真を見ると、地上フロアおよび一番目のフロア (二階) は暗いテクスチャ、それ以外には明るいテクスチャとなっているのが分かります。getWallstyle 関数はフロア インデックスを対応する壁のタイプに割り当てます。
FacadeModeling_02.cej シーンと facade_02.cga ルール ファイルを開いて、この時点でシーンとルールがどのようになっているか確認できます。
次にファサードで事前にモデル化されたアセットを使用する方法を学習します。
現在モデリングしているファサードの写真を見ると、以下の項目についてアセットが必要であることが分かります。
窓: 窓エレメントとして使用
丸い窓上部: 窓上部の装飾
三角の窓上部: 窓上部の装飾
半円弧: 地上フロアのアーチとして使用
レッジ: すべてのレッジとして使用
モディリオン: 窓や地上フロアのアーチの装飾として使用
これらのアセットはすでにチュートリアル プロジェクトの asset フォルダーに含まれています。これらのアセットをプレビューするには、[Navigator] ウィンドウで目的のアセットを選択して右クリックし、[File Preview] を選択します。
以下の行をルール ファイルの属性の宣言の下にアセットへの参照を追加します。
const window_asset = "facades/elem.window.frame.obj"
const round_wintop_asset = "facades/round_windowtop.obj"
const tri_wintop_asset = "facades/triangle_windowtop.obj"
const halfarc_asset = "facades/arc_thin.obj"
const ledge_asset =
"facades/ledge.03.twopart_lessprojection.obj"
const modillion_asset =
"facades/ledge_modillion.03.for_cornice_ledge_closed.lod0.obj"
窓を追加をするために以下の手順を行います。
WindowTile(floorindex) -->
Window
Window -->
s('1,'1,0.2) t(0,0,-0.2)
t(0,0,0.02)
[ i(window_asset) Wall(0) ]
Glass
ファサードの写真をもう一度見みると、フロアによって異なる窓 (または窓のエレメント) があることに気づきます。
WindowTile(floorindex) -->
case floorindex == 1 || floorindex == 999 :
Window
case floorindex == 2 :
Window
t(0, '1, 0)
WindowOrnamentRound
else :
Window
WindowLedge
t(0, '1, 0)
WindowOrnamentTriangle
第一フロア (二階) と最上階には特別な装飾はないため、Window 形状のみが呼び出されます。
第二フロア (三階) には新しい形状 WindowOrnamentRound を追加します。このエレメントは窓の上の境界線に配置されるため、現在のスコープを y 軸方向に '1 移動します。
他の窓タイル (中間階) には、WindowLedge 形状と WindowOrnamentTriangle 装飾が追加されます。
最終的なアセットを直接使用せずに、最初に代用となる立方体を挿入します。
実際のアセットのサイズをより設定し易くなります。この場合、組み込みの立方体 アセットを使用できます。
WindowOrnamentTriangle -->
s('1.7, 1.2, 0.3)
center(x)
i("builtin:cube")
color("#ff0000")
WindowOrnamentRound -->
s('1.7, 1.2, 0.4)
center(x)
i("builtin:cube")
color("#00ff00")
WindowLedge -->
s('1.5, 0.2, 0.1)
t(0, -0.2, 0)
center(x)
i("builtin:cube")
color("#0000ff")
代用となる立方体を実際のアセットと交換するために、以下の手順を実行します。
WindowOrnamentTriangle -->
s('1.7, 1.2, 0.3)
center(x)
i(tri_wintop_asset)
Wall(0)
WindowOrnamentRound -->
s('1.7, 1.2, 0.4)
center(x)
i(round_wintop_asset)
Wall(0)
WindowLedge -->
s('1.5, 0.2, 0.1)
t(0, -0.2, 0)
center(x)
i("builtin:cube")
Wall(0)
WindowOrnamentRound -->
s('1.7, 1.2, 0.4)
center(x)
i(round_wintop_asset)
Wall(0)
split(x) { ~1 : WindowMod
| window_width : NIL
| ~1 : WindowMod }
WindowMod -->
s(0.2, '1.3, '0.6)
t(0, '-1, 0)
center(x)
i(modillion_asset)
Wall(0)
y 方向に相対的な負の移動 ('-1) を適用すると、アセットの上面が装飾の下面に揃えられることに注意してください。
5. ルール ファイルを保存し、モデルを生成します。
ドア タイルは垂直方向に分割されて、ドア、アーチおよび上部エリアに分割されます。
続いて、以下のルールを Window ルールの下に追加します。
DoorTile -->
split(y) { ~1 : Door
| scope.sx/2 : Arcs
| 0.5 : Arctop }
Arctop -->
Wall(1)
s(0.5, '1, 0.3)
center(x)
i(modillion_asset)
Wall(1)
Arcs -->
s('1, '1, wall_inset)
t(0, 0, -wall_inset)
Doortop
i("builtin:cube")
split(x) { ~1 : ArcAsset
| ~1 : r(scopeCenter,0,0,-90) ArcAsset }
ArcAsset -->
i(halfarc_asset)
Wall(1)
Doortop -->
Wall(0)
Door -->
t(0,0,-wall_inset)
Wall(0)
Door ルールでは、ドアは壁からセット バックしています。
5. ルール ファイルを保存し、モデルを生成します。
トップ レッジにはシンプルな壁のストライプを使用し、ボトム レッジにはレッジ アセットを挿入して他のフロアとの区別がつくようにする必要があります。
TopLedge -->
WallStripe
BottomLedge(floorindex) -->
case floorindex == 1 :
split(y) { ~1 : Wall(0)
| ~1 : s('1, '1, 0.2) LedgeAsset }
case floorindex == 999 :
split(y) { ~1 : WallStripe
| ~1 : s('1, '1, 0.2) LedgeAsset }
else : WallStripe
WallStripe -->
split(x) { 0.5 : Wall(1)
| ~1 : Wall(2)
| 0.5 : Wall(1) }
LedgeAsset -->
i(ledge_asset)
Wall(0)
今度は、バルコニーの作成をしていきます。
case floorindex == 2 :
split(y) { ~1 : Subfloor(floorindex) Balcony
| 0.5 : TopLedge }
Balcony -->
s('1, 2, 1)
t(0, -0.3, 0)
i("builtin:cube")
color("#99ff55")
a. バルコニーを BalconyBeams、BalconyFloor、および RailingBox エレメントに分割して、Balcony ルールの緑色を置き換えます。
Balcony -->
s('1, 2, 1)
t(0, -0.3, 0)
i("builtin:cube")
split(y) { 0.2 : BalconyBeams
| 0.3 : BalconyFloor
| 1 : RailingBox }
b. ルール ファイルを保存し、モデルを生成します。
BalconyBeams -->
split(x) { ~0.4 : s(0.2, '1, '0.9) center(x) Wall(0) }*
BalconyFloor 形状は Wall ルールのみを定義します。
BalconyFloor --> Wall(0)
RailingBox -->
comp(f) { front : Rail | left : Rail | right : Rail }
Rail -->
s('1.1, '1, 0.1)
t(0, 0, -0.1)
center(x)
i("builtin:cube")
Wall(0)
これで、ジオメトリ アセットが挿入された最終モデルが完成しました。ルールを様々な区画に適用したり、[Inspector] ウィンドウにあるユーザー属性を変更してファサードのデザインを変えることができます。
最終結果については、FacadeModeling_03.cej シーンと facade_03.cga ルールを開くことで確認できます。
次のセクションでは、ファサードにテクスチャを適用する方法を学習します。
次に、ファサードにテクスチャを適用します。
テクスチャ アセットを作成するには、以下の手順を実行します。
const wall_tex = "facades/textures/brickwall.jpg"
const wall2_tex = "facades/textures/brickwall_bright.jpg"
const dirt_tex = "facades/textures/dirtmap.15.tif"
const doortop_tex = "facades/textures/doortoptex.jpg"
randomWindowTex = fileRandom("*facades/textures/window.*.jpg")
randomDoorTex = fileRandom("*facades/textures/doortex.*.jpg")
CGA を使用したテクスチャリングは、以下の 3 つの手順で行われます。
setupProjection () - UV 座標空間を定義します。
set (material.map) またはtexture () - テクスチャ ファイルを設定します。
projectUV () - UV 座標を適用します。
レンガのテクスチャとダート マップという 2 つのテクスチャ レイヤーをファサードに追加します。ファサード全体で一貫したテクスチャ座標を維持するには、ファサード ルールに UV 設定を追加する必要があります。テクスチャ設定を事前にテストするために、新しい中間的なルール FrontfacadeTex を追加します。
Building -->
comp(f) { front : FrontfacadeTex }
FrontfacadeTex -->
setupProjection(0, scope.xy, 2.25, 1.5, 0, 0, 1)
texture("builtin:uvtest.png")
projectUV(0)
setupProjection (0,scope.xy,2.25,1.5,0,0,1) は、テクスチャ チャネル 0 (カラー チャネル) のテクスチャ座標を定義します。UV 座標はスコープの x、y 平面に沿って投影され、x 方向には 2.25 単位ごと、y 方向には 1.5 単位ごとに繰り返されます。texture () 操作は set (material.map) のショートカットです。この場合、カラー マップを builtin:uvtest.png に設定します。これは、UV 座標をすばやく確認するためのテクスチャです。最後に、チャンネル 0 の UV 座標をベイクし、UV 座標を適用します。
FrontfacadeTex -->
setupProjection(0, scope.xy, 2.25, 1.5, 0, 0, 1)
texture("builtin:uvtest.png")
projectUV(0)
setupProjection(2, scope.xy, '1, '1)
set(material.dirtmap, ("builtin:uvtest.png"))
projectUV(2)
このテクスチャはファサード全体に広がる必要があるため、ファサードの寸法である UV 設定には相対演算子 ‘1 と ‘1 を使用します。
FrontfacadeTex -->
setupProjection(0, scope.xy, 2.25, 1.5, 0, 0, 1)
texture(wall_tex)
projectUV(0)
setupProjection(2, scope.xy, '1, '1)
set(material.dirtmap, dirt_tex)
projectUV(2)
UV 座標はファサードに適しています。
FrontfacadeTex -->
setupProjection(0, scope.xy, 2.25, 1.5, 0, 0, 1)
setupProjection(2, scope.xy, '1, '1)
Frontfacade
Frontfacade ルールでは、後続のエレメントに対して UV 座標が正しく設定されるようになりました。
詳細については、Texturing: Essential knowledge の CGA reference を参照してください。
ワークフローの前半で、walltype パラメータを Wall ルールに追加しました。これを使用して、壁のタイプごとに異なるテクスチャを割り当てます。
Wall(walltype) -->
// dark bricks with dirt
case walltype == 1 :
color(wallColor)
texture(wall_tex)
set(material.dirtmap, dirt_tex)
projectUV(0) projectUV(2)
// bright bricks with dirt
case walltype == 2 :
color(wallColor)
texture(wall2_tex)
set(material.dirtmap, dirt_tex)
projectUV(0) projectUV(2)
// dirt only
else :
color(wallColor)
set(material.dirtmap, dirt_tex)
projectUV(2)
すべての壁エレメントは、いずれかのタイプの壁でテクスチャされます。
窓アセットの場合、一連の窓テクスチャを使用してガラス板に色を付けるため、ガラス形状全体にわたるように UV 座標を設定する必要があります。これを行うには、x 方向と y 方向の両方に ‘1 を使用します。テクスチャ操作では、前に定義した randomWindowTex 関数を呼び出すことによって、ランダムなガラスのテクスチャが選択されます。
Glass -->
setupProjection(0, scope.xy, '1, '1)
projectUV(0)
texture(randomWindowTex)
Glass -->
setupProjection(0, scope.xy, '1, '1)
projectUV(0)
texture(randomWindowTex)
set(material.specular.r, 1)
set(material.specular.g, 1)
set(material.specular.b, 1)
set(material.shininess, 4)
ドア面は窓ガラスと同じテクスチャになっています。Doortop ルールと Door ルールを以下のように置き換えます。
Doortop -->
setupProjection(0, scope.xy, '1, '1)
texture(doortop_tex)
projectUV(0)
Door -->
t(0, 0, -wall_inset)
setupProjection(0, scope.xy, '1, '1)
texture(randomDoorTex)
projectUV(0)
FacadeModeling_04.cej シーンと facade_04.cga ルールを開いて、最終結果を確認します。
このチュートリアルでは、以下の方法を学習しました。
CGA 形状文法の詳細については、 Rule-based modeling tutorial、および Rule-based modeling と CGA modeling のヘルプ トピックを参照してください。