要访问 ArcGIS CityEngine 中的教程工程,请打开 CityEngine,然后在主菜单中单击帮助 > 下载教程和示例。 在选择教程或示例后,系统会自动下载工程并将其添加到 CityEngine 工作空间。
在本教程中,您将学习如何使用 L 形和 U 形建筑物进行体量建模,如何将高度和退缩尺度变化应用于宗地,并最终生成包含纹理的外观多样的场景。
有关 CGA 形状语法的详细信息,请参阅基于规则的建模教程以及基于规则的建模和 CGA 建模帮助主题。
添加 L 和 U 形状
首先,您将使用 CGA 创建建筑物的 L 和 U 体量模型,这些是城市建筑物的常见类型。
创建规则文件
要创建规则文件,请执行以下操作:
添加 L 形状
首先,您将使用简单的 L 形状体量模型。
- 向 myMass_01.cga 规则添加以下内容:
attr height = rand(30, 60) attr wingWidth = rand(10, 20) Lot --> LShape LShape --> shapeL(wingWidth, wingWidth) { shape : LFootprint } LFootprint --> extrude(height) Mass LotInner --> OpenSpace
LShape 规则将创建 L 形状的覆盖区,尺寸范围在 10 到 20 米之间。 LFootprint 规则可将 L 形状拉伸到其高度。
LotInner 将应用 OpenSpace,将地块形状保持原样。
接下来,您需要将规则应用于地块。 - 按 Ctrl+S 以保存规则文件。
- 此刻,您不需要街道来创建模型,因此单击可见性设置 ,并取消选择图形网络 (F10) 以隐藏街道。
- 要选择所有地块,请在 Scene Editor 窗口中右键单击 Streetnetwork 图层中的 Blocks 子图层,然后单击选择对象。
- 要将 myMass_01.cga 规则分配给地块,请执行以下操作:
- 确保已选择检查器窗口中的地块选项卡。
- 在规则文件旁边,单击检查器窗口中的分配。
- 单击分配规则文件对话框中的 myMass_01.cga 规则。
- 单击选择工具 (Q) 以在视窗窗口中选择一些地块。
- 单击生成 (Ctrl+G):
仅显示 L 形体量模型可以运行,但使用不同模型形状的混合可能效果更好。 接下来,您需要将体量模型添加更多变化。
向 L 形状添加变化
当前的 L 形状侧翼始终位于主体量的左侧。 使用 rotateScope 操作,可以将 L 形放置在右侧。
- 使用概率运算符 % 更改 LShape 规则,以优化 L 形状,使其侧翼位于左侧或右侧。
LShape --> 50% : shapeL(wingWidth, wingWidth) { shape : LFootprint } else : rotateScope(0, 90, 0) shapeL(wingWidth, wingWidth) { shape : LFootprint }
- 使用 convexify 操作,您可以将 L 形状分割为两翼,并更改两翼的高度。 您将再次编辑 LFootprint 规则,来使用随机概率来添加变化:
LFootprint --> 75% : extrude(height) Mass else : convexify comp(f) { 0 : extrude(height) Mass | all : extrude(height*0.7) Mass }
- 保存规则文件并生成:
现在,侧翼出现在左侧和右侧,并且高度有所不同。 现在,您将添加其他形状类型。
添加 U 形状
要添加 U 形状,请执行以下操作:
- 在起始 Lot 规则中调用 UShape 规则,而非 LShape 规则:
Lot --> UShape
- 类似地,使用 shapeU 操作,并在 Lot 规则下方添加 UShape 和 UFootprint 规则:
UShape --> shapeU(wingWidth, wingWidth*0.7, wingWidth*0.7) { shape : UFootprint } UFootprint --> extrude(height) Mass
- 保存并生成:
- 接下来,通过将某些 U 形随机旋转 180 度来添加一些变化:
UShape --> 80% : rotateScope(0, 180, 0) shapeU(wingWidth, wingWidth*0.7, wingWidth* 0.7) { shape : UFootprint } else : shapeU(wingWidth, wingWidth*0.7, wingWidth*0.7) { shape : UFootprint }
- 保存并生成:
可以看出,U 形状并非在所有地块上都适用。 在下一部分中,您将组合 L 形状和 U 形状。
L 和 U 形状组合
组合 L 形状和 U 形状并添加一些高度分布方面的变化。
- 为了更好地控制建筑物的高度,您将向 height 属性添加条件,即仅大面积地块才能建造高层建筑物:
attr height = case geometry.area < 1000 : rand(20, 50) else : rand(50, 150)
- 在 Lot 规则中,调用 LUShape,而非 Ushape,并添加一个新规则 LUShape,来控制在哪些地块上创建哪种形状类型:
Lot --> LUShape LUShape --> case scope.sx > scope.sz : 60% : UShape else : LShape else : LShape
U 形状最适用于宽度大于深度的地块,或使用 CGA 语法翻译的地块,其中 scope.sx 大于 scope.sz。 在所有其他情况下,您将仅触发 L 形状。
- 保存,并在这次选择更多形状以创建更多的建筑物群。
- 生成建筑物:
- L 形状和 U 形状都不适用于非矩形地块。 下一个 case 语句确保 UShape 和 LShape 模型仅在近似矩形地块(公差为 15 度)上创建。 否则,您将调用新的覆盖区规则:
LUShape --> case geometry.isRectangular(15) : case scope.sx > scope.sz : 60% : UShape else : LShape else : LShape else : BasicFootprint
- 由于已拉伸地块形状相对于 L 形状和 U 形状过大,因此需要向 BasicFootprint 规则添加负偏移。 由此可在各个建筑物之间留出更多空间。 将其放置于 LFootprint 规则之后:
BasicFootprint --> offset(-5, inside) extrude(height) Mass
- 保存并生成:
要查看当前场景的外观,需打开 01_MassModeling_.cej 场景而不保存。 当提示重新生成模型时,单击是。
在下一部分中,您将学习如何在形状语法中使用递归进行体量建模。
使用递归进行体量建模
现在,您将使用递归形状语法调用对重复的建筑物元素进行建模。
塔形状
- 创建一个名为 myMass_02.cga 的新规则文件。
- 向新规则文件添加以下内容:
height = case geometry.area > 1000 : rand(50, 200) else: rand(20, 50) Lot --> Tower Tower --> extrude(height) Envelope Envelope --> RecursiveSetbacks
height 函数返回建筑物高度的随机值。 Lot 起始规则调用 Tower 规则,用于将覆盖区拉伸到塔形包络。 Envelope 规则调用递归规则。
- 对于以下递归规则,您需要三个附加变量:lowHeight、scale 和 floorheight,并需要将它们放在高度函数之后。
lowHeight = 50% : 0.4 else : 0.6 attr scale = rand(0.75, 0.9) attr floorheight = rand(4, 5)
由于对于建筑物而言,scale 需要保持不变,因此您需要将其定义为一个属性。 这是因为与函数不同,属性只在生成过程开始时计算一次。
- 在 Envelope 规则后面添加 RecursiveSetbacks 规则:
RecursiveSetbacks --> case scope.sy > 2*floorheight : split(y) { 'lowHeight : Mass | ~1 : Setback } else : s('1, floorheight, '1) Mass
只要体量高于两层楼,RecursiveSetbacks 规则就会将其分割为相对高度为 lowHeight 的较低部分体量。 其余较高部分将生成 Setback 形状。
如果 RecursiveSetbacks 形状小于两层楼,则其余部分的高度将设置为 floorheight,并生成 Mass 形状。
- 添加 Setback 规则,该规则将对形状进行缩放并居中,然后递归调用 RecursiveSetbacks 规则。
Setback --> s('scale, '1, 'scale) center(xz) RecursiveSetbacks
- 保存规则文件。
- 选择场景中的所有地块,并在检查器窗口中分配 myMass_2.cga 规则文件。
上一规则中的简单建筑物群被更改为带有退缩尺度的塔:
圆形
您可以使用外部圆柱资产创建递归塔的圆形版本。
- 修改 Envelope 规则:
Envelope --> case geometry.isRectangular(20) : 20% : i("cyl.obj") RecursiveSetbacks else : RecursiveSetbacks else : RecursiveSetbacks
在全部 20% 的塔中,您将插入圆柱资产,而非使用隐式立方体作为基础形状。
- 保存并生成:
02_MassModeling.cej 场景显示了当前场景的外观。
在下一部分中,您将使用退缩尺度来修改宗地。
使宗地适应退缩尺度
对地块形状应用退缩尺度。
街道退缩尺度
要应用街道退缩尺度,请执行以下操作:
- 创建一个名为 myMass_03.cga 的新规则。
- 向新规则文件添加以下内容:
attr height = case geometry.area > 1000 : rand(50, 200) else : rand(20, 50) attr distanceStreet = 20% : 0 else : rand(3, 6) Lot --> Parcel LotInner --> OpenSpace Parcel --> setback(distanceStreet) { street.front : OpenSpace | remainder : Footprint } Footprint --> extrude(height) OpenSpace --> color("#77ff77")
Parcel 规则会对地块的所有街道两侧应用退缩,并将该区域转至 OpenSpace 规则。 远离街道两侧的内部部分将转至 Footprint 规则,并将拉伸到随机高度。
street.front 选择器评估 streetWidth 形状对象属性,将为从块创建的动态地块形状自动设置这些属性。 这些属性可能不存在于手动创建的形状上。
- 保存规则并选择所有地块。
- 在主菜单中,单击形状 > 删除模型,删除所有生成的模型。
- 将 myMass_03.cga 规则分配给所有地块。
- 仅选择一个地块并生成:您可以看到街道退缩尺度应用于所选地块。
- 选择其他地块并再次生成:
注意建筑物从街道的退缩尺度,但它们之间没有开放空间。
建筑物距离
现在,您将添加类似的退缩尺度来控制建筑物之间的距离。
- 在 distanceStreet 属性下方添加 distanceBuildings 属性:
attr distanceBuildings = 30% : 0 else : rand(4, 8)
- 修改 Parcel 规则以在剩余部分调用 SubParcel 规则,并在其后添加新的 SubParcel 规则:
Parcel --> setback(distanceStreet) { street.front : OpenSpace | remainder : SubParcel } SubParcel --> setback(distanceBuildings/2) { !street.front : OpenSpace | remainder : Footprint }
在 SubParcel 规则中,您再次应用退缩,但这次应用于非面向街道的边缘。
- 保存并生成。
- 在检查器窗口中选择要探索的模型。
可以调整 distanceBuildings 和 distanceStreet 规则参数以更改退缩距离。 可以在单个或多个模型上设置这些值。
要重置为规则文件中的默认随机值,请单击任一参数值旁的下拉菜单,然后单击规则默认值。
- 选择所有地块并生成:
如果您希望查看带有退缩宗地的建筑物示例,则可以打开 03_MassModeling.cej 场景。
在下一部分中,您将组合前一部分中的体量模型和退缩宗地。
合并体量和退缩宗地
接下来,将体量模型与退缩宗地相结合。
导入 LU 形状和塔的体量规则
- 确保 myMass_03.cga 窗口处于活动状态,并将其另存为 myMass_04.cga。
- 在版本说明之后,将以下两项导入内容添加到规则文件的顶部:
import lushapes : "myMass_01.cga" import towers : "myMass_02.cga"
导入的规则文件中的所有规则、属性和函数现在可用于当前规则文件。
- 修改 Footprint 规则:
Footprint --> case geometry.isRectangular(15): 25% : towers.Tower else : lushapes.LUShape else: 25% : towers.Tower else : lushapes.BasicFootprint
Footprint 规则不再只是简单的拉伸,而是生成您在前面步骤中创建的更高级的体量模型。 case 语句中的 geometry.isRectangular 函数可确保仅在基本为矩形的形状上生成 LUShapes。
- 保存规则文件。
- 选择所有地块并分配 myMass_04.cga 规则文件:
可以查看具有退缩尺度的所有地块,以及不同高度的方塔和圆塔的混合。
04_MassModeling.cej 场景显示了带有退缩尺度的建筑物和塔。
在下一部分中,您将为体量模型添加纹理立面。
添加纹理立面
要添加纹理立面,请执行以下操作:
- 将 myMass_04.cga 规则文件另存为 myMass_05.cga。
- 在属性下方添加一个 const 函数,该函数从您的 12 个立面纹理贴片中随机选择一个:
const randomFacadeTexture = fileRandom("*facade_textures/f*.tif")
- 接下来,添加 floorHeight 属性:
attr floorheight = rand(4,5)
- 要正确地将纹理切片映射到立面上,需要定义两个函数,用于计算当前体谅的实际楼层高度和切片宽度:
actualFloorHeight = case scope.sy >= floorheight : scope.sy/rint(scope.sy/floorheight) else : scope.sy actualTileWidth = case scope.sx >= 2 : scope.sx/rint(scope.sx/4) else : scope.sx
借助这些函数,您可以确保在立面的边缘没有切掉任何纹理切片。
- 在规则文件底部添加一个 Mass 规则,使用组件分割从体量模型中获取立面组件:
Mass --> comp(f){ side : Facade | top : Roof. }
- 接下来,指示导入的规则使用此 Mass 规则:
towers.Mass --> Mass lushapes.Mass --> Mass
- 最后,在 Facade 规则中,根据实际情况在立面上设置 UV 坐标,使用 randomFacadeTexture 函数定义纹理文件,并投影 UV:
Facade --> setupProjection(0, scope.xy, 8*actualTileWidth, 8*actualFloorHeight) texture(randomFacadeTexture) projectUV(0)
- 保存规则文件。
- 选择所有地块并将 myMass_05.cga 规则分配给地块。
- 生成建筑物。
现在,模型具有随机纹理的立面。
打开 05_MassModeling.cej 场景以查看最终的纹理建筑物。
在本教程中,您学习了如何执行以下操作:
- 使用 L 形和 U 形建筑物生成体量建模。
- 对宗地应用距离和退缩变化。
- 创建具有多样化形状、高度和纹理的建筑物。
要继续学习 CityEngine,请参阅完整的 CityEngine 教程目录。