要访问教程CityEngine中,单击 帮助>下载教程和例子…。选择教程或示例后,项目会自动下载并添加到您的工作区。
复杂的立面图案
本教程展示了如何根据图片对建筑物进行建模,并介绍了一些更复杂的 CGA 技术。
教程设置
如果 ComplexPatterns.cej 场景尚未打开,请打开它。
生成建筑物
本教程介绍了如何创建一组 CGA 规则,以使用纯 CGA 从真实世界的照片中重新创建建筑物。您要建模的立面如下图所示。由于本示例中的磁贴和窗口布局的复杂模式,您需要使用一些高级 CGA 机制,例如嵌套重复拆分和参数传递。
生成建筑的GCA视角:
要提前生成建筑物:
- 在 3D 视口中选择批次之一。
- 单击顶部工具栏中的生成按钮。
立面分析
在规划新的 CGA 规则时,在开始编写规则之前先勾勒出粗略的布局并定义一些形状名称会很有帮助。
您将建模的立面主要由三种楼层类型组成:顶部、地面和上部。较低的楼层由包含窗户的瓷砖制成,而顶层仅包含窗户元素。每隔一个较低的楼层都是相同的,因此您将传递带有 Floor 形状的索引(floorIndex)以创建特定楼层的正确外观(瓷砖和窗口对齐)。
由于瓷砖的图案,您将定义一个中间的 DoubleTile 形状,其中包含两个瓷砖形状,一旦您对地板图案进行编码,这将很有帮助。
接下来,您将在磁贴中定义详细的子形状。它由两个主要部分组成:MilkGlass 和 Window 形状。窗口形状包含顶部的 Blind 和嵌入的子窗口形状。这些元素的位置取决于瓷砖在地板上的水平位置,因此您需要将此位置索引(称为tileIndex)存储为瓷砖形状的参数,以便能够正确放置子形状结构。
在导航器中双击complexpatterns_01.cga文件以打开 CGA 编辑器并查看创建外观的规则。
属性、变量和资产
属性在规则文件的开头定义。这些属性用于整个规则集,并且可以通过CGA 语法编辑器外部的Windows > Inspector进行修改。
// 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"
诸如@Group 或@Range 之类的注释被添加到属性中以控制它们在检查器中的外观。
其他变量和资产在以下块中定义:
tileW = windowW + milkGlassW // total tile width
const barDiameter = 0.04
// assets
const cyl_v = "general/primitives/cylinder.vert.8.notop.tex.obj"
const cyl_h = "general/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"
建筑的实际创建现在开始。首先,使用拉伸操作创建质量模型。顶层与主要部分分开并再次分开以创建后退阳台。
Lot -->
extrude(buildingH) // Extrude the building
split(y){ ~1: MainPart | floorH: UpperPart } // Split top floor from lower floors
// Create a set-back by splitting in the direction of the building depth
UpperPart -->
split(z){ ~1: TopFloor | balconyDepth: Balcony }
然后将组件拆分应用于不同的体积部分,以区分正面、侧面和顶面,并触发立面、墙壁和屋顶规则。
// Create a facade on the front face, walls on the side faces, and a roof on the top face
MainPart -->
comp(f){ front: Facade | side: Wall | top: Roof. }
// Create a floor (marked with -1 as top floor) on the front face,
walls on the side and roof on the top face
TopFloor -->
comp(f){ front: Floor(-1) | side: Wall | top: Roof. }
阳台的尺寸已设定。栏杆将放置在当前形状的面上,因此您将使用组件拆分来获取栏杆规则的前、左和右面。
// Set balcony height to 0.7 meters (railing height)
Balcony -->
s(scope.sx-2*borderwallW,0.7,scope.sz-borderwallW)
center(x)
comp(f){ front: Railing | left: Railing | right: Railing }
体积建模后的粗略建筑形状:
立面和地板
您现在将进一步细分前立面。第一个拆分在重复拆分{…}* 的帮助下将立面细分为底层部分和一组上层。分割尺寸之前的波浪号 (~)(例如,~ groundfloorH)允许灵活的高度并确保匹配的地板在立面上没有孔。通过将split.index (代表楼层索引)作为参数传递,您可以稍后触发特定楼层功能。
// Split the facade into a groundfloor and repeated upper floors
Facade -->
split(y){ ~groundfloorH: Floor(split.index)
// (all floors are marked with their split index, which represents the floor number)
| { ~floorH: Floor(split.index) }* }
每层楼的左右边界都有一个狭窄的墙壁区域。您将通过在 x 方向上进行简单拆分来创建它。
// create a narrow wall element on both sides of every floor.
Floor(floorIndex) -->
//the floorIndex parameter is passed on to be used later
split(x){borderwallW: Wall | ~1: FloorSub(floorIndex) | borderwallW: Wall }
根据楼层索引,现在使用水平分割命令为每个楼层创建特殊的水平元素:
- 较高楼层仅设有顶部壁架。
- 顶层没有额外的元素,直接触发 TileRow 形状。
- 您将在稍后的规则中再次使用楼层索引,以便再次将其作为 TileRow 形状的参数进行评估。
FloorSub(floorIndex) -->
case floorIndex == 0: // ground floor with index 0.
split(y){ 1: Wall | ~1: TileRow(floorIndex) | ledgeH: Wall}
case floorIndex > 0: // upper floors
split(y){ ~1: TileRow(floorIndex) | ledgeH: Ledge }
else: TileRow(floorIndex) // topfloor with index -1.
带有地板和壁架分割的立面:
瓷砖
现在,您将把地板分成瓷砖。对于顶层来说,相对容易;没有特殊的模式,只是重复窗口元素。为了稍后处理这些图块,您可以使用参数 -1 来标记它们。
要为主要楼层创建特殊的重复图案,您将创建一个名为DoubleTile的中间形状。要在后面的步骤中正确对齐窗口元素,您需要地板和瓷砖索引 ( split.index ),您将它们作为参数传递。
TileRow(floorIndex) -->
case floorIndex == -1:
split(x){ ~windowW: Tile(-1) }*
// Repeating shape Tiles on the top floor, marked again with -1
else:
split(x){ ~tileW*nSymmetries: DoubleTile(floorIndex,split.index) }*
// the floor is subdivided into regular DoubleTile shapes,
// the floor index is passed as parameter
地板和瓷砖索引的组合决定了窗户的对齐方式。因此,您有两个规则,它们以不同的 MilkGlass 和 Tile 形状的顺序重复拆分。
DoubleTile(floorIndex,tileIndex) -->
case tileIndex%2 + floorIndex%2 == 1:
// windows are right-aligned
split(x){ ~milkGlassW: MilkGlass | ~windowW: Tile(tileIndex) }*
else:
// windows are left-aligned
split(x){ ~windowW: Tile(tileIndex) | ~milkGlassW: MilkGlass }*
您将首先为未来的窗口纹理设置纹理坐标。然后将整个 Tile 形状水平拆分为窗框和中心部分。中心部分再次拆分,这次垂直分为框架、窗口、框架、百叶窗和框架。
Tile(tileIndex) -->
setupProjection(0,scope.xy,scope.sx,scope.sy)
// Set up the texture coordinates for the windows
split(x){ frameW: Frame Bracing
// This triggers the window frame as well as the bracing on the left side of the window
// the center window is split into Frame, Window, Frame, Blind and Frame from bottom to top
| ~1: split(y){ frameW : Frame
| ~1 : Window(tileIndex)
| frameW : Frame
| blindH : Blind
// frame and bracing on the window's right side
| frameW : Frame }
| frameW: Frame Bracing }
视窗
对于 Window 形状,DoubleTile 的 tile 索引用于确定子窗口的位置。
Window (tileIndex) -->
放置在窗口左半部分的右对齐子窗口。
case tileIndex%nSymmetries >= 1: // the Subwindows are aligned depending
// on the DoubleTile position
split(x){ ~1 : Subwindow("right")
| frameW : Frame
| ~1 : Glass } // right-aligned in the left half of the window
放置在窗口右半部分的左对齐子窗口。
case tileIndex%nSymmetries >= 0:
split(x){ ~1: Glass
| frameW: Frame
// left-aligned in the right half of the window
| ~1: Subwindow("left") }
代表顶层窗户的瓷砖索引 -1 现在用于创建没有子窗户的窗户。
else:
split(x){ ~1: Glass | frameW: Frame | ~1: Glass}
使用 left 和 right 参数,RedWindow 被放置在正确的位置。
Subwindow(align) -->
case align == "left":
split(x){~3: RedWindow | ~2: Glass} // Put the RedWindow to the left
else:
split(x){~2: Glass | ~3: RedWindow } // And to the right otherwise
以下规则为 RedWindow 形状创建框架和玻璃元素:
RedWindow -->
split(x){ frameW: RedFrame // left...
| ~1: split(y){ frameW: RedFrame
| ~1: RedGlass
| frameW: RedFrame } // ... bottom, top ...
| frameW: RedFrame } // ... and right frame
RedGlass -->
split(y){ ~1: Glass
| frameW/2: t(0,0,-frameW) Frame
| ~1: t(0,0,-frameW) Glass }
RedWindow 形状的详细窗口几何形状:
材料
添加颜色和纹理。
Wall --> color(darkblue)
Blind --> color(grey)
Frame -->
extrude(frameW) color(white) // extrude the frame to the front
RedFrame -->
t(0,0,-frameW) extrude(frameW*4) color(red)
Glass -->
projectUV(0) // apply texture coordinates to current shape geometry
texture(window_tex) color(white) // and assign texture and color
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) i("builtin:cube")
color(brightblue)
setupProjection(0, scope.xy, scope.sx, scope.sy)
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)
应用材质规则后的彩色和纹理模型:
细节元素
您将通过添加一个后墙元素、一个给它一些深度的立方体和第二个用作盖板的薄立方体来改进地板壁架。
Ledge -->
Wall
[ s('1,'0.9,0.2) i("builtin:cube") Wall ]
t(0,-0.1,0.2) s('1,scope.sy+0.1,0.03) i("builtin:cube") Wall
插入单杠以创建栏杆的水平部分。通过禁用垂直修剪,可以防止切割以下垂直角钢。
垂直条在具有浮动分割宽度的重复分割的帮助下均匀分布。
Railing -->
[ t(0,scope.sy-barDiameter/2,0) HBar ]
set(trim.vertical, false)
split(x){ ~tileW/3: VBar }*
插入圆柱体资产以创建垂直和水平条。
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)
窗户的支撑由顶部和底部安装件以及中间的垂直杆组成。对于安装,插入一个立方体,然后 VBar 再次触发圆柱体资产。
Bracing -->
s(barDiameter,'1,0.15) center(x) i("builtin:cube")
split(y){ 0.01: Wall | ~1: t(0,0,0.15) VBar | 0.01: Wall }
添加了包括壁架、窗撑和栏杆在内的细节元素的最终模型:
现在您有了最终的模型,继续将规则应用于不同的地块形状,或者在 Inspector 中试验用户属性以修改您的外观设计。
不同的风格
使用 style 关键字,定义了一个新的样式,重新定义了一些属性。在这种情况下,您将通过重新定义颜色属性来创建颜色变化。
@Description("A Variation in Red")
style Red_Color_Theme
attr brightblue = "#FF8080"
attr darkblue = "#D20000"
attr grey = "#ECCACA"
attr red = "#361B1B"
应用了 Red_Color_Theme 样式:
下面的 Candler 和 Parthenon CityEngine场景是很好的例子,向您展示了 CGA 的不同可能性。
烛光大厦
- 打开 Candler Building.cej场景。
- 在导航器中双击Candler Building.cga文件,并探索创建 Candler Building 的 CGA 规则。
帕特农神庙
- 打开Parthenon.cej场景。
- 再次双击parthenon.cga 文件以查看 Parthenon 神庙背后的规则。