本着從示例中學習使用規則建模的目的,學習一下CityEngine中的教程。前幾個教程是熟悉軟件以及如何使用規則的,第六個教程是開始使用規則建模,並給建築物貼紋理的。因此一邊學習教程6中的步驟,一邊查看其中創建規則的CGA具體語法,希望我們都能從教程中有很多收獲。前提要了解如何創建規則和應用規則。
本次學習的教程為Tutorial_06_Basic_Shape_Grammar__2011_1,其中包含四部分,分別為:1.構建簡單建築物;2.為簡單建築物貼紋理;3.添加LOD;4.建築物屬性隨機變化。本節學習該教程中的第一部分。
本節學習最終要構建一個如下圖的建築物,該建築物有地面一樓和其他樓層,一樓的正面有一個入口的門,其他窗口都使用的是一個提前做好的OBJ模型。
下面開始創建規則進行建模:
為了更好的理解規則,我們自己創建一個新的規則,按照教程中的語句進行規則的書寫。
1. 在規則文件的最開始處定義建築的屬性(也可以放在規則文件的其他位置)。在CGA文件中,這些屬性將對整個規則文件產生作用。這些屬性將顯示在屬性查看器(Inspector)中,可通過屬性查看器修改這些屬性。
attr groundfloor_height = 4 //地面一樓的高度 attr floor_height = 3.5 //其他樓層的高度 attr tile_width = 3 //將樓面按塊划分的寬度 attr height = 11 //樓高 attr wallColor = "#fefefe" //牆面顏色
2. 教程中構建的窗戶是使用的一個已經建好的窗戶模型window.obj,這個文件存放在assets文件夾中,使用之前也要先定義出來。
window_asset = "facades/window.obj" //指定obj文件
3. 下面我們定義第一條規則為Lot. 在屬性檢查器中,該規則被指定為開始規則。大量的模型是使用拉伸操作創建而來的:
//對shape使用height中定義的高度進行拉伸,並命名為Building Lot --> extrude(height) Building
拉伸之后如下圖:
4. 可以通過應用comp()將Building分解為多個面, 生成了正面(FrontFacade)、多個側面(SideFacade)和一個頂面(Roof)
Building-->
comp(f){ front : FrontFacade | side : SideFacade | top: Roof}
5. 分解完成之后,就開始開始對這些面進行外觀造型。典型的外觀造型流程如下:1,將面分解為樓層(Floors)。2,將樓層分解為塊(Tile),每一塊通常由牆面和窗口構成。這樣的細分過程在CGA要素語法的實現過程如下圖:
//下面的FrontFacade規則將正面沿y軸方向,分割為兩大部分,第一部分高度為groundfloor_height的地面一層Groundfloor,剩余的以floor_height高度進行重復分割(以*符號標記),分割為多個Floor。
FrontFacade --> split(y){ groundfloor_height : Groundfloor | { ~floor_height: Floor }* }
正面分割之后如下圖:
6. 細分側面:
SideFacade -->
split(y){ groundfloor_height: Floor | { ~floor_height: Floor }* }
SideFacade規則將側面沿y軸方向分割也分為兩大部分,這兩部分使用的都是是相同的Floor對象,因此側面這兩大部分看起來都應該是一樣的。只有高度不一樣,高度不一樣主要是為了與正前面的樓層高度保持一致。
側面分割之后如下圖,三個側面都是一致的:
7. 繼續對Floor對象進行細化:
//先給每層樓在x軸方向的兩端畫出寬度為1的牆面(Wall),剩余的部分以tile_width為寬度重復分割(Tile)
Floor --> split(x){ 1: Wall | { ~tile_width: Tile }* | 1 : Wall }
如下圖:
8. 最后對正面的地面一樓進行細化:
//同樣先在x軸方向的兩端畫出寬度為1的牆面(Wall),按照tile_width划分為多個Tile,並按照tile_width划分出一個入口EntranceTile。 Groundfloor -->split(x){ 1: Wall
|{ ~tile_width: Tile }*
| ~ tile_width: EntranceTile | 1: Wall }
結果如下圖:
9. 下面對Tile進行定義:
//先對Tile在x軸方向中間划分出寬度為2的一部分(對這部分再按y軸方向先划分一個高度為分別為1和1.5的wall和window,剩余的高度也定為wall),然后兩邊分別划分為寬度大概為1的wall Tile -->
split(x){ ~1 : Wall
| 2 : split(y){ 1: Wall | 1.5: Window | ~1: Wall }
| ~1 : Wall }
結果如下:
10. 對EntranceTile進行定義:
EntranceTile -->
split(x){ ~1 : SolidWall
| 2 : split(y){ 2.5: Door | ~2: SolidWall }
| ~1 : SolidWall }
先對入口在x軸方向划分寬度為2的一部分(這部分在y軸方向先划分2.5高度的Door,剩余的大約高度2定為SolidWall.),然后兩邊各為大約1米的Solidwall。
11. 最后對前面定義的Window,Door,Wall和SolidWall寫具體的規則。
Window -->
s('1,'1,0.4)
t(0,0,-0.25)
i(window_asset)
Door -->
s('1,'1,0.1)
t(0,0,-0.5)
i("builtin:cube")
Wall -->
color(wallColor)
SolidWall -->
color(wallColor)
s('1,'1,0.4)
t(0,0,-0.4)
i("builtin:cube:notex")
這里解釋一下上面出現的幾個命令:
① s('1,'1,0.4):
命令:s(float xSize, float ySize, float zSize)
作用設置形狀的尺寸。
eg1: s(5,5,5) 表示將三個方向的值設為絕對值5
eg2: s('0.5,'1,'1.5) 等同於 s(0.5*scope.sx,scope.sy,1.5*scope.sz),如果加上'符號,括號內的值在0-1之間,表示設置xyz的值為原先的多少倍。
②t(0,0,-0.25)
平移:t(tx, ty, tz)
③i(window_asset)或者i("builtin:cube:notex")
對象替換:i(geometryPath)
CityEngine有內置的素材可以直接使用,分為Geometry Assets和Textures。
Geometry Assets:
builtin:cube—有節點的單位立方體,帶有紋理圖層的紋理坐標系
builtin:cube:notex—單位立方體,不帶有紋理坐標系
Textures:
builtin:default—表示16×16黑白方格相間的紋理
builtin:uvtest.png—使用CE標准的測試紋理
最終效果:
到此我們完成了簡單建築物的構建,學習了構建流程,如何拉伸、分解面、分割Tile等。規則可以一步步嘗試,也可以替換成其他顏色或將obj替換為其他模型。如下圖: