要访问 ArcGIS CityEngine 中的教程工程,请启动 CityEngine,然后在主菜单中单击帮助 > 下载教程和示例。 在选择教程或示例后,系统会自动下载工程并将其添加到 CityEngine 工作空间。
本教程介绍了 CityEngine 的 CGA 形状语法的基础知识。 您将分析并扩展完成的规则文件,其中包含创建基本建筑物的所有步骤。
有关 CGA 形状语法的详细信息,请参阅基于规则的建模教程以及基于规则的建模和 CGA 建模帮助主题。
为简单建筑物建模
要构建具有典型立面的简单建筑物,请完成以下步骤:
- 在导航器窗口中展开 Tutorial_06_Basic_Shape_Grammar 教程文件夹。
- 打开 scenes 文件夹中的 SimpleBuilding_01.cej 场景以查看以下建筑物:
- 在视窗中选择地块(或已生成的模型),然后在检查器窗口中查看信息。
您将发现此处显示了两个重要参数:
- 规则文件 - 包含到 /rules/simpleBuilding_01.cga 规则文件的链接。 触发生成时运行此规则文件。
- 初始规则 - 定义在规则文件中运行的第一个规则。 在本例中,初始规则为 Lot 规则。
- 通过在检查器窗口中单击规则文件链接,或者在 Navigator 窗口中双击 simpleBuilding_01.cga 文件,以在 CGA 编辑器中打开文件,从而打开 CGA 规则文件。
在接下来的部分中,您将探索必要的属性、资产和规则以创建简单的建筑物。
建筑物属性
建筑物属性通常在规则文件的开头定义(尽管可将其放在规则文件中的任意位置)。 这些属性可用于整个规则集,并显示在检查器窗口的 CGA 属性映射区域不分中规则文件和初始规则定义下方。也可以在 CGA 编辑器窗口外部对这些属性的值进行设置和修改。
以下是用于定义建筑物的属性:
attr groundfloor_height = 4
attr floor_height = 3.5
attr tile_width = 4
attr height = 11
地块规则
该建筑物的创建从现在开始。 Lot 规则是在检查器窗口中分配的第一条规则。 可以使用拉伸操作创建体量模型:
Lot -->
extrude(height)
Building
建筑物规则
可以通过应用组件分割将体量模型分割为其立面:
Building -->
comp(f) { front : Frontfacade | side : Sidefacade | top: Roof }
此规则通过应用组件分割将建筑物形状或体量模型分割为其立面。 此操作将产生一个正面形状(通常是带有入口的主前立面),多个侧面形状(例如立面)和一个屋顶形状。
现在可以对立面进行建模。 在经典的立面建模工作流中,可将立面分割为楼层,然后将楼层进一步分割为称为切片(楼层细分)的元素。 切片通常由墙壁和窗口元素组成。 此细分方案可应用于 CGA 形状语法,如下所示:
Frontfacade 规则
Frontfacade 规则将前立面分割成高度为 4 米的底层形状,并重复(使用重复运算符 [*])高度约为 3.5 米的高层形状:
Frontfacade -->
split(y) { groundfloor_height : Groundfloor
| { ~floor_height : Floor}* }
~ 运算符保证不限建筑物的实际高度,始终会创建足够数量的较高楼层。 底层的外观通常与其他楼层不同,尤其是前立面。 底层的不同不仅是由于存在入口,而且还通常由于楼层高度尺寸、窗口外观、颜色等不同所导致。
Sidefacade 规则
Sidefacade 规则将侧立面分割为楼层形状。 为了确保楼层高度与前立面同步,将以同样的方式进行细分分割:
Sidefacade -->
split(y) { groundfloor_height : Floor
| { ~floor_height : Floor}* }
Roof 规则
Roof 规则用于将屋顶形状向内偏移 0.4 米并稍微降低其高度,以创建平坦屋顶:
Roof -->
offset(-0.4, inside)
t(0, 0, -0.2)
楼层规则
Floor 规则是将楼层细分为宽度大约为 3 米的切片的典型示例。 为了使楼层设计更加有趣,您将在每侧分割一个宽度为 1 米的墙壁元素:
Floor -->
split(x) { 0.5 : SolidWall
| { ~tile_width : Tile }*
| 0.5 : SolidWall }
Groundfloor 规则
Groundfloor 规则使用类似的细分分割来细化一楼形状,不同之处在于入口位于右侧:
Groundfloor -->
split(x) { 0.5 : SolidWall
| { ~tile_width : Tile }*
| ~tile_width : EntranceTile
| 0.5 : SolidWall }
下图首先显示了不含分割的已拉伸体量模型,然后显示了带有楼层和切片分割的模型:
切片规则
定义初始立面结构后,即可进一步对 Tile 规则进行建模:
Tile -->
split(x) { 1 : SolidWall
| ~1.5 : split(y) { 0.4 : SolidWall | ~1.5 : Window | 0.4: SolidWall }
| 1 : SolidWall }
Tile 规则可通过沿 x 轴和 y 轴分割(使用嵌套分割)定义切片的外观。 在此设计中,墙壁元素是浮动的(带有 ~),墙壁具有固定宽度 1 米,窗户上方和下方的高度均为 0.4 米。
EntranceTile 规则
EntranceTile 规则以类似于切片形状的方式定义入口形状(但是底部没有墙壁):
EntranceTile -->
split(x) { ~1 : SolidWall
| 2.5 : split(y) { 3 : Door | ~2 : SolidWall }
| ~1 : SolidWall }
SolidWall、Window 和 Door 规则
SolidWall、Window 和 Door 规则用于向立面添加一定的深度和复杂性:
SolidWall -->
s('1, '1, -0.4)
primitiveCube()
Window -->
t(0, 0, -0.2)
split(y) { 0.1 : Frame
| ~1 : split(x) { 0.1 : Frame | { ~1 : Glass | 0.1 : Frame }* }
| 0.1 : Frame }
Door -->
t(0, 0, -0.4)
split(y) { ~1 : split(x) { 0.15 : Frame
| ~1 : Panel
| 0.05 : Frame
| ~1 : Panel
| 0.15 : Frame }
| 0.15 : Frame }
通过 s(x,y,z) 操作,可以在 SolidWall 规则中设置范围的大小。 由于使用了相对坐标,范围的宽度和高度不受影响:当前范围的 x 和 y 尺寸按一 ('1) 比例缩放,不会发生变化。 z 尺寸设置为 -0.4 米,导致墙壁厚度为 0.4 米(向内指向)。 primitiveCube() 运算会创建填充当前形状范围的立方体体积。
对于 Window 和 Door 规则,当前形状通过 t(x,y,z) 运算在 z 方向上分别平移 -0.2 米和 -0.4 米。 这样,窗户会向立面内退缩 0.2 米,门在墙壁末端退缩 0.4 米。 然后沿 x 和 y 方向分割形状,以创建窗框和玻璃和面板部分。
请注意,CGA 编辑器窗口将显示一条警告,指示未定义 Frame、Glass 和 Panel 规则。 忽略该警告,您将在下一章中添加这些规则。
将所有这些规则组合在一起,您将得到最终的无纹理建筑物:
在下一节中,您将学习如何向建筑物添加纹理和颜色。
向建筑物添加纹理和颜色
现在,您将向建筑物添加纹理和颜色,方法为在规则文件的顶部定义所用的纹理和颜色。 将从 assets 文件夹中加载纹理。
- 如果未打开 SimpleBuilding_01.cej 场景,请打开该场景。
- 双击 simpleBuilding_01.cga 规则文件以将其打开。
- 在规则文件的属性下方添加以下新行:
// textures & colors const wall_tex = "facades/brick_white_02.jpg" const dirt_tex = "dirtmaps/dirtmap_04.jpg" const roof_tex = "roofs/flat_01.jpg" const window_color = "#85acd6" const frame_color = "#444444" const door_color = "#666666"
纹理和颜色均定义为常量,因此不会在检查器窗口中显示为规则属性。
- 将 setupProjection() 命令添加至 Frontfacade 和 Sidefacade 规则:
Frontfacade --> setupProjection(0, scope.xy, 1.5, 1.5, 0, 0, 1) setupProjection(2, scope.xy, scope.sx, scope.sy) split(y) { groundfloor_height : Groundfloor | { ~floor_height : Floor}* } Sidefacade --> setupProjection(0, scope.xy, 1.5, 1.5, 0, 0, 1) setupProjection(2, scope.xy, scope.sx, scope.sy) split(y) { groundfloor_height : Floor | { ~floor_height : Floor}* }
setupProjection() 命令为立面上的颜色(通道 0)和脏蚀贴图(通道 2)准备 UV 坐标投影,投影到范围的 xy 平面上;因此,将 scope.xy 设置为第二个参数。
砖块纹理(通道 0)将在 x 轴和 y 轴上每 1.5 米重复一次。 脏蚀贴图(通道 2)将覆盖整个立面并使用 scope.sx 和 scope.sy 作为大小参数。
- 编辑 Sidefacade 规则下方的 Roof 规则:
Roof --> offset(-0.4, inside) t(0, 0, -0.2) setupProjection(0, scope.xy, scope.sx, scope.sy) texture(roof_tex) projectUV(0)
Roof 规则将使用 UV 坐标以覆盖整个楼层表面,设置楼层纹理,并将纹理坐标应用于几何。
保持建筑物形状选中,然后在 CGA 编辑器窗口中,每次编辑后进行保存 (Ctrl+S) 并生成 (Ctrl+G),以查看更改。
- 使用额外的组件分割编辑 SolidWall 规则,然后直接在其后面添加新的 Wall 规则:
SolidWall --> s('1, '1, -0.4) primitiveCube() comp(f) { side : Wall | all : setupProjection(0, scope.xy, 1.5, 1.5, 0, '1) Wall } Wall --> texture(wall_tex) set(material.dirtmap, dirt_tex) projectUV(0) projectUV(2)
组件分割用于将墙壁的侧面与顶部和底部部分分离。 这样可以将其他 setupProjection() 用于这些部分,以正确缩放和对齐纹理。
在 Wall 规则中,颜色和脏蚀通道的纹理均设置为之前定义的常量。 还需要在这两个通道上投影 UV。
- 在 Window 规则后面添加 Glass 和 Frame 规则:
Glass --> color(window_color) set(material.specular.r, 0.5) set(material.specular.g, 0.5) set(material.specular.b, 0.5) set(material.reflectivity, 0.5) set(material.shininess, 50) set(material.opacity, 0.9) Frame --> color(frame_color)
color() 运算会将窗户和窗框颜色分别设置为蓝色和深灰色。 然后设置不同的材料属性,以使窗户看起来更加真实。
- 在 Door 规则后面添加 Panel 规则:
Panel --> color(door_color)
在此最终步骤中,将门板颜色设置为比门框更浅的灰色。
打开 simpleBuilding_02.cga 规则以查看完成的规则。
下图显示了最终的建筑物模型:
同一模型的特写视图:
下图显示了适用于任意体量模型的规则设置:
添加细节层次
在本部分中,您将向建筑物中添加简单细节层次 (LOD) 机制。 您将减少模型的复杂程度(面计数),这有助于创建较大面积的建筑物。
要添加新的 LOD 属性,请完成以下步骤:
- 打开 SimpleBuilding_02.cej 场景。
- 打开 simpleBuilding_02.cga 文件。
- 在其他属性下方添加新的 LOD 属性:
@Enum(0,1) attr LOD = 1
您将定义以下 LOD:
- LOD 0 - 细节层次低,复杂程度低
- LOD 1 - 细节层次高,复杂程度高
您刚刚建模的建筑物将为高分辨率模型。
检查当前模型,您会发现可以主要在窗口资产上保存面。 您将使用纹理平面代替复杂的窗口资产。 接下来,您将创建模型的低分辨率版本。
可利用 @Enum(0,1) 注记将检查器窗口中此属性的选项限制为 0 和 1。 - 在 Roof 规则中,将现有代码置于 LOD > 0: 下方,并将纹理部分复制到 else 下方:
Roof --> case LOD > 0: offset(-0.4, inside) t(0, 0, -0.2) setupProjection(0, scope.xy, scope.sx, scope.sy) texture(roof_tex) projectUV(0) else: setupProjection(0, scope.xy, scope.sx, scope.sy) texture(roof_tex) projectUV(0)
您已向 Roof 规则添加了一个条件:如果 LOD 值大于 0(高分辨率),请使用偏移和较低的屋顶形状。 如果 LOD 属性为 0,仅使用基于初始组件分割的简单平面形状。
- 对于 Window 规则,保留两种情况的分割,但是仅在 LOD > 0 时应用嵌入:
Window --> case LOD > 0: t(0, 0, -0.2) split(y) { 0.1 : Frame | ~1 : split(x) { 0.1 : Frame | { ~1 : Glass | 0.1 : Frame }* } | 0.1 : Frame } else: split(y) { 0.1 : Frame | ~1 : split(x) { 0.1 : Frame | { ~1 : Glass | 0.1 : Frame }* } | 0.1 : Frame }
- 对 Door 规则执行相同的操作:当 LOD > 0 时不进行嵌入:
Door --> case LOD > 0: t(0, 0, -0.4) split(y) { ~1 : split(x) { 0.15 : Frame | ~1 : Panel | 0.05 : Frame | ~1 : Panel | 0.15 : Frame } | 0.15 : Frame } else: split(y) { ~1 : split(x) { 0.15 : Frame | ~1 : Panel | 0.05 : Frame | ~1 : Panel | 0.15 : Frame } | 0.15 : Frame }
- 对于 SolidWall 规则,由于您已移除窗户和门的嵌入,因此不再需要实体元素:
SolidWall --> case LOD > 0: s('1, '1, -0.4) primitiveCube() comp(f) { side : Wall | all : setupProjection(0, scope.xy, 1.5, 1.5, 0, '1) Wall } else: Wall
保存、生成,并查看检查器窗口中的属性。 此处显示了新的 LOD 属性。
- 将 LOD 值更改为 0。
源值将从规则更改为您提供的值。 建筑物模型随即生成,其中 LOD 值设置为 0。
- 按 5 将模型更改为无纹理或着色。
按 d-d 以显示信息显示栏,其中显示了面计数。 如果 LOD 值设置为 0,则模型将从 2347 个面减少为 816 个面。
在下一部分中,您将向建筑物添加随机变化。
向属性添加随机变化
最后,您将通过定义随机属性向已生成的建筑物添加变化:
- 打开 SimpleBuilding_03.cej 场景。
- 打开您刚刚创建的规则,或者双击 simpleBuilding_03.cga 文件。
- 使用以下内容,向建筑物属性添加变化:
attr groundfloor_height = rand(4,7) attr floor_height = rand(3.5,5) attr tile_width = rand(3,6) attr height = rand(11,25)
这将添加宽度在 3 到 6 米之间的随机切片,高度在 11 到 25 米之间的随机建筑物,以及高度随机的楼层。
- 随机化纹理资产和窗户颜色:
const wall_tex = fileRandom("facades/*.jpg") const dirt_tex = fileRandom("dirtmaps/*.jpg") const roof_tex = fileRandom("roofs/*.jpg") const window_color = 33% : "#85acd6" 33% : "#96acb3" else : "#999999"
使用 fileRandom() 函数时,将从墙壁、尘土和屋顶纹理的对应资产子文件夹中选择随机纹理。
对于窗户颜色,使用随机函数定义三种颜色而不是一种。
- 要在地块中添加空间和变化,使用 setback 运算修改 Lot 规则:
Lot --> setback(rand(2, 6)) { all = color("#f0f0f0") Ground. | remainder : extrude(height) Building }
这样,将地块设置为向内缩进 2 到 6 米;将外部地面形状上色成浅灰色,然后基于内部形状生成建筑物。
- 由于您将生成大量建筑物,因此请将规则中的默认 LOD 属性值从 1 更改为 0 并保存该规则:
attr LOD = 0
- 在 Scene Editor 窗口中选择 Streetnetwork 图层。
- 单击生成工具 (Ctrl+G) 以生成建筑物:
打开 SimpleBuilding_04.cej 场景以查看具有随机属性的最终建筑物。
在本教程中,您学习了如何执行以下操作:
- 创建生成简单建筑物所需的 CityEngine CGA 语法元素。
- 向属性添加纹理、颜色、不同的细节层次以及随机性,从而使建筑物具有多样性。
要继续学习 CityEngine,请参阅完整的 CityEngine 教程目录。