教程 9:高级形状语法

要访问 ArcGIS CityEngine 中的教程工程,请打开 CityEngine,然后在主菜单中单击帮助 > 下载教程和示例。 在选择教程或示例后,系统会自动下载工程并将其添加到 CityEngine 工作空间。

使用样式关键字 Red 的建筑物

在本教程中,您将学习如何分析建筑物立面图像,并将立面组件转换为 CGA。 您将探索如何创建一组 CGA 规则,以根据以下真实图像重新创建建筑物:

将使用 CGA 重新创建的建筑物照片

您将注意到本示例中切片和窗口布局的复杂模式,并且您将使用一些高级 CGA 机制(例如嵌套重复分割和参数传递)来创建建筑物。

有关 CGA 形状语法的详细信息,请参阅基于规则的建模教程以及基于规则的建模CGA 建模帮助主题。

探索建筑物

首先,通过执行以下操作,使用以上立面图像的 CGA 版本打开该场景:

  1. Navigator 窗口中展开 Tutorial_09_Advnced_Shape_Grammar 教程文件夹。
  2. 打开 scenes 文件夹中的 Complex Patterns.cej 场景。

    当系统询问您“是否要重新生成这些模型?”时,请单击以显示建筑物:

已生成建筑物的 CGA 透视图

定义立面布局

规划新的 CGA 规则时,在开始编写规则之前,勾勒出粗略的布局并定义一些形状名称十分有帮助。

执行立面分析

首先,在分析立面时,您将看到立面主要由三种楼层类型组成:顶层、地面和上层。 较低的楼层由包含窗口的切片构成,而顶层仅包含窗口元素。 其他所有较低的楼层都是相同的,因此您将传递带有 Floor 形状的索引 (floorIndex) 参数,以便为特定楼层创建正确的外观(切片和窗口对齐)。

由于切片的模式,您将定义一个中间的 DoubleTile 形状,其中包含两个 Tile 形状,对楼层模式进行编码后,这将非常有用。

复杂的模式方案

定义子形状

接下来,您将在切片中定义详细的子形状。 它由两个主要部分组成:MilkGlassWindow 形状。 Window 形状包含顶部的 Blind 和一个嵌入的 Subwindow 形状。 这些元素的位置取决于切片在楼层上的水平位置,因此您需要将此位置索引 (tileIndex ) 存储为 Tile 形状的参数,以便能够正确放置子形状结构。

切片中详细的子形状

在 CGA 中创建建筑物体积

定义立面布局后,即可开始在 CGA 中创建建筑物。

添加属性、变量和资产

第一步是创建一个新规则,然后在规则文件的开头定义属性。 将在整个规则集中使用这些属性,并且可以在场景中对其进行修改,方法是使用检查器窗口调整属性和参数。 要开始创建规则,请执行以下操作:

  1. 单击新建 > CityEngine > CGA 规则文件
  2. 单击下一步
  3. 将该规则命名为 myComplexPatterns.cga
  4. 单击完成

    系统随即创建一个新的 CGA 文件,并显示 CGA 编辑器窗口。 除了版本号之外,此为空文件。

  5. 在底部添加以下用户属性和一个注记为 @StartRule 的空规则:

    // User Attribute 
    
    @Group("Building", 1) @Range(min=5, max=40, restricted=false) @Distance
    attr buildingH = 27             // building height
    
    @Group("Facade", 2) @Range(min=3, max=6, restricted=false) @Distance
    attr floorH = 3.5               // floor height
    @Range(min=3, max=6, restricted=false) @Distance
    attr groundfloorH = floorH+1    // groundfloor height
    @Range(min=1, max=4, stepsize=1, restricted=false)
    attr nSymmetries = 2
    @Range(min=0.1, max=1, restricted=false) @Distance
    attr borderwallW = 0.3          // width of border wall stripe
    @Range(min=0.1, max=0.8, restricted=false) @Distance
    attr ledgeH = 0.3               // ledge height
    
    @Group("Window",3) @Range(min=1, max=5, restricted=false) @Distance
    attr windowW = 2.5              // window width
    @Range(min=1, max=5, restricted=false) @Distance
    attr milkGlassW = windowW/2     // milkglass blend width
    @Range(min=0.1, max=2.5, restricted=false) @Distance
    attr blindH = 0.8               // blind height
    @Range(min=0.01, max=0.5, restricted=false) @Distance
    attr frameW = 0.07              // frame width
    
    @Group("Balcony",4) @Range(min=3, max=6, restricted=false) @Distance
    attr balconyDepth = 2
    
    @Group("Colors",5)
    @Color
    attr brightblue = "#86b1c7" 
    @Color
    attr darkblue   = "#33556c"
    @Color
    attr red        = "#5c3f40"
    @Color
    attr grey       ="#6b7785"
    @Color
    attr white      = "#ffffff"
    
    @StartRule
    Lot --> BuildingVolume

  6. Ctrl+S 以保存规则文件。
  7. 选择模型并为其分配 myComplexPatterns.cga 规则。

    请注意,诸如 @Group@Range 等注记已添加至属性中,用于控制其在检查器窗口中的外观。

    包含形状 Lot 1011 的规则的检查器窗口

  8. @StartRule 上方添加附加变量和资产:

    tileW = windowW + milkGlassW	// total tile width
    const barDiameter = 0.04
    
    // assets
    const cyl_v 	    = "primitives/cylinder.vert.8.notop.tex.obj"
    const cyl_h 	    = "primitives/cylinder.hor.8.notop.tex.obj"
    const window_tex    = "facade/windows/1_glass_2_blue.tif"
    const milkGlass_tex = "facade/windows/blend_tex.png"

拉伸建筑物

该建筑物的实际创建从现在开始。 要拉伸建筑物,请执行以下操作:

  1. 可以使用 extrude 操作创建体量模型。 将顶层与主体分割,然后再次分割以创建退缩阳台:

    BuildingVolume -->
    	extrude(buildingH)
    	split(y) { ~1     : MainPart
    	         | floorH : UpperPart }
    
    UpperPart -->
    	split(z) { ~1           : TopFloor 
    	         | balconyDepth : Balcony }

  2. 添加组件分割以将其应用于不同的体积部分,以便区分正面、侧面和顶面。 由此将触发 FacadeWallRoof 规则:

    MainPart -->
    	comp(f) { front : Facade
    	        | side  : Wall
    	        | top   : Roof. } 
    
    TopFloor -->
    	comp(f) { front : Floor(-1)
    	        | side  : Wall
    	        | top   : Roof. }

  3. 使用组件分割以调用 Railing 规则,将扶手放置在正面、左侧和右侧:

    Balcony -->
    	s(scope.sx-2*borderwallW, 1.1, scope.sz-borderwallW)
    	center(x)
    	comp(f) { front : Railing 
    	        | left  : Railing 
    	        | right : Railing }

    已设置阳台的尺寸。 接下来,您将向建筑物添加扶手。

  4. 保存规则。

    确保已在视窗中选择建筑物。

  5. 单击生成 生成 (Ctrl+G) 以生成建筑物:

    体积建模后的粗略建筑物形状

添加楼层

要进一步细分正立面,请执行以下操作:

  1. 将立面分割为底层和重复的上层:

    Facade -->
    	split(y) { ~groundfloorH : Floor( split.index )
    	         | { ~floorH     : Floor( split.index ) }* }

    首次分割借助重复分割 {...}* 将立面细分为底层部分和一组较高的楼层。 分割大小高度的波形符号 (~)(例如 ~groundfloorH)支持使用灵活高度,并确保匹配的楼层在立面上没有孔洞。 通过传递 split.index(代表楼层索引)作为参数,您之后可以触发特定楼层要素。

  2. 对于每个楼层,通过在 x 方向进行简单的分割,可以在两侧创建狭窄的墙壁区域:

    Floor(floorIndex) -->
    	split(x) { borderwallW : Wall
    	         | ~1          : FloorSub(floorIndex)
    	         | borderwallW : Wall }

  3. 根据以下要求,可以使用水平分割命令为每个楼层添加特殊水平元素:

    • 较高的楼层仅有顶部窗台。
    • 顶层没有其他元素,可以直接触发 TileRow 形状。
    • 再次分配楼层索引作为 TileRow 形状的参数,因为您将在稍后的规则中再次使用该楼层索引。

    FloorSub(floorIndex) -->
    	case floorIndex == 0:
    		split(y) { 1      : Wall
    		         | ~1     : TileRow(floorIndex)
    		         | ledgeH : Wall }
    	case floorIndex > 0:
    		split(y) { ~1     : TileRow(floorIndex)
    		         | ledgeH : Ledge }
    	else:
    		TileRow(floorIndex)

  4. 保存规则并生成建筑物:

    楼层和窗台分割的立面

添加切片

现在您要将楼层分割为切片。 对于顶层而言,没有特殊的模式,仅包含重复的窗口元素。 要稍后处理这些切片,请使用 -1 参数对其进行标记。

  1. 要为主要楼层创建特殊的重复模式,请创建 DoubleTile 中间形状:

    TileRow(floorIndex) -->
    	case floorIndex == -1:
    		split(x) { ~windowW : Tile(-1) }*
    	else: 
    		split(x) { ~tileW*nSymmetries : DoubleTile(floorIndex, split.index) }*

    要在后面的步骤中正确地对齐窗口元素,您将需要楼层和切片索引 (split.index),其将作为参数传递。

  2. 添加两个具有重复分割的规则以获得 MilkGlassTile 形状的不同位置:

    DoubleTile(floorIndex, tileIndex) -->
    	case tileIndex%2 + floorIndex%2 == 1:
    		split(x) { ~milkGlassW : MilkGlass 
    		         | ~windowW    : Tile(tileIndex) }*
    	else:
    		split(x) { ~windowW    : Tile(tileIndex)
    		         | ~milkGlassW : MilkGlass }*

    楼层和切片索引的组合确定了双切片内窗户的对齐方式。

  3. 为将来的窗口纹理设置纹理坐标:

    Tile(tileIndex) -->
    	setupProjection(0, scope.xy, scope.sx, scope.sy)
    	split(x) { frameW : Frame Bracing 
    	         | ~1     : split(y) { frameW : Frame 
    	                             | ~1     : Window(tileIndex)
    	                             | frameW : Frame 
    	                             | blindH : Blind 
    	                             | frameW : Frame } 
    	         | frameW : Frame Bracing }

    然后将整个 Tile 形状水平分割为窗框和中间部分。 再次分割中心部分,这次是垂直分割为框架、窗口、框架、百叶窗和框架元素。

  4. 保存并生成:

    建筑物被分割为窗框和垂直中心部分,形成框架、窗口,百叶窗和支撑

添加窗口

要向建筑物添加窗口,请执行以下操作:

  1. 对于 Window 形状,DoubleTile 的切片索引用于确定子窗口的位置。

    Window(tileIndex) -->

  2. 在窗口的左半部分放置右对齐子窗口:

    case tileIndex%nSymmetries >= 1:
    		split(x) { ~1     : Subwindow("right")
    		         | frameW : Frame
    		         | ~1     : Glass }

  3. 在窗口的右半部分放置左对齐子窗口:

    case tileIndex%nSymmetries >= 0:
    		split(x) { ~1     : Glass
    		         | frameW : Frame
    		         | ~1     : Subwindow("left") }

  4. 使用代表顶层窗口的 -1 切片索引以创建不含子窗口的窗口。

    else:
    		split(x) { ~1     : Glass
    		         | frameW : Frame
    		         | ~1     : Glass }

  5. 使用左参数和右参数,将 RedWindow 放置在正确的位置:

    Subwindow(align) -->
    	case align == "left": 
    		split(x) { ~3 : RedWindow 
    		         | ~2 : Glass }
    	else: 
    		split(x) { ~2 : Glass
    		         | ~3 : RedWindow }

  6. 添加规则,为 RedWindow 形状创建框架和玻璃元素:

    RedWindow -->
    	split(x) { frameW : RedFrame 
    	         | ~1     : split(y) { frameW  : RedFrame
    	                             | ~1      : RedGlass
    	                             | frameW  : RedFrame }
    	         | frameW : RedFrame }
    
    RedGlass -->
    	split(y) { ~1       : Glass
    	         | frameW/2 : t(0,0,-frameW) Frame
    	         | ~1       : t(0,0,-frameW) Glass }

  7. 保存并生成:

    RedWindow 形状的详细窗口几何

添加材料

要将颜色和纹理应用于建筑物,请执行以下操作:

  1. 定义立面元素的颜色、拉伸和平移:

    Wall -->
    	color(darkblue)
    
    Blind -->
    	color(grey)
    
    Frame -->
    	extrude(frameW)
    	color(white)
    
    RedFrame --> 
    	t(0, 0, -frameW)
    	extrude(frameW*4)
    	color(red)

  2. 对当前形状几何应用纹理坐标,并分配纹理和颜色:

    Glass --> 
    	projectUV(0)
    	texture(window_tex)
    	color(white)
    	set(material.specular.r, 0.4)
    	set(material.specular.g, 0.4)
    	set(material.specular.b, 0.4)
    	set(material.shininess, 4)
    	set(material.reflectivity, 0.3)
    	
    MilkGlass --> 
    	s('1, '1, frameW*1.2)
    	primitiveCube
    	color(brightblue)
    	setupProjection(0, scope.xy, scope.sx, scope.sy, 0, 0, 0)
    	texture(milkGlass_tex)
    	projectUV(0)
    	set(material.specular.r, 0.7)
    	set(material.specular.g, 0.7)
    	set(material.specular.b, 0.7)
    	set(material.shininess, 20)
    	set(material.reflectivity, 0.05)

  3. 保存并生成:

    应用材料规则后的彩色和纹理模型

添加详细信息

最后,要向元素添加细节,请执行以下操作:

  1. 通过添加后墙元素、具有深度的立方体和第二个作为盖板的薄立方体来优化楼层窗台:

    Ledge -->
    	Wall
    	[ s('1, '0.9, 0.2) primitiveCube Wall ]
    	t(0, -0.1, 0.2)
    	s('1, scope.sy+0.1, 0.03)
    	primitiveCube
    	Wall

  2. 通过使用浮动分割宽度进行重复分割,垂直条块可均匀分布:

    Railing --> 
    	[ t(0,scope.sy-barDiameter/2,0) HBar ]
    	set(trim.vertical, false)
    	split(x) { ~tileW/3 : VBar }*

    插入了水平条块以创建扶手的水平部分。 通过禁用垂直修剪,可以防止垂直角条块被切割。

  3. 插入圆柱资产以创建垂直条块和水平条块:

    VBar -->
    	s(barDiameter, '1, barDiameter)
    	t(0, 0, -barDiameter)
    	i(cyl_v)
    	color(white)
    
    HBar -->
    	s('1, barDiameter, barDiameter)
    	t(0, 0, -barDiameter)
    	i(cyl_h)
    	color(white)

  4. 窗口的支撑由顶部和底部固定装置以及中间的垂直条块组成。 对于固定装置,插入一个立方体,并且 VBar 将触发圆柱资产:

    Bracing --> 
    	s(barDiameter, '1, 0.15)
    	center(x) 
    	primitiveCube
    	split(y) { 0.01 : Wall
    	         | ~1   : t(0, 0, 0.15) VBar
    	         | 0.01 : Wall }

  5. 保存并生成:

    包含细节元素的最终模型

    添加了细节元素(包括窗台、窗撑和扶手)的最终模型:

现在您已经有了最终模型,请将规则应用于不同的地块形状,或者尝试使用检查器窗口中的用户属性来修改立面设计。

添加样式

您可以使用样式关键字来定义用于重新定义某些属性的新样式。

  1. 在规则文件底部,通过重新定义颜色属性向模型添加样式:

    @Description("A Variation in Red")
    style Red_Color_Theme
    attr brightblue = "#FF8080"
    attr darkblue 	= "#D20000"
    attr grey 	= "#ECCACA"
    attr red 	= "#361B1B"

  2. 保存规则文件。
  3. 检查器窗口中,单击样式管理器下拉菜单中的 Red_Color_Theme

    样式管理器中应用的 Red_Color_Theme

    已应用 Red_Color_Theme 样式:

    使用样式关键字 Red 的建筑物

    要查看最终的规则文件,请打开 complexpatterns_01.cga 规则。

坎德勒大楼

坎德勒大楼是 CGA 如何通过程序创建逼真的建筑物的一个很好的示例。 要探索 CGA,请执行以下操作:

  1. 打开 Candler Building.cej 场景。
  2. 双击导航窗口中的 Candler Building.cga 文件,然后探索用于创建坎德勒大楼的 CGA 规则。

坎德勒大楼

巴台农神庙

最后,要探索巴台农神庙,请执行以下操作:

  1. 打开 Parthenon.cej 场景。
  2. 再次双击 parthenon.cga 文件以查看巴台农神庙背后的规则:

巴台农神庙

在本教程中,您学习了如何执行以下操作:

  • 获取并分析图像,并将其拆分为 CGA 组件。
  • 添加元素,如窗户、瓷砖和材料。
  • 探索更复杂的高级形状语法示例。

要继续学习 CityEngine,请参阅完整的 CityEngine 教程目录