教程 6:基本形状语法

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

为简单建筑物建模

本教程介绍了 CityEngine 的 CGA 形状语法的基础知识。 您将分析完成的规则文件,其中包含创建基本建筑物的所有步骤。

基本建筑物

教程设置

  1. 将 Tutorial_06_Basic_Shape_Grammar 工程导入 CityEngine 工作空间。
  2. 打开 Tutorial_06_Basic_Shape_Grammar/scenes/01_SimpleBuilding.cej 场景。

简单建筑物

您将构建具有典型立面的简单建筑物。 本部分的结果如下图所示:

具有典型立面的简单建筑物

  1. 在 3D 视窗中选择地块(或已生成的模型),然后在检查器窗口(如果未打开,请单击窗口 > 检查器将其打开)中查看信息。
    检查器窗口的屏幕截屏
  2. 此处有两个重要的参数:
    • 规则文件 - 包含到 rules/simpleBuilding.01.cga 规则文件的链接。 触发生成时执行此规则文件。
    • 初始规则 - 定义在规则文件中执行的第一个规则。 在这种情况下,初始规则是地块。

  3. 通过在检查器中单击规则文件链接,或者在导航器中双击 rules/simpleBuilding.01.cga 文件,以在 CGA 编辑器中打开文件,从而打开 CGA 规则文件。

简单建筑物简单建筑物规则设置

建筑物属性

建筑物属性通常在规则文件的开头定义(尽管可将其放在规则文件中的任意位置)。 这些属性可用于整个规则设置,并显示在检查器的 CGA 属性映射区域中。在此区域内,也可以在 CGA 语法编辑器外部对这些属性的值进行设置和修改。

attr groundfloor_height	= 4
attr floor_height 		= 3.5
attr tile_width 		= 3
attr height 			= 11 
attr wallColor		= "#fefefe"

窗口资产

此处定义了用于创建简单建筑物的窗口资产。 实际资产将从导航器中工程的资产文件夹进行加载。

// geometries
window_asset	 = "facades/window.obj"

地块规则

该建筑物的实际创建从现在开始。 第一条规则称为地块。 记住检查器中分配的初始规则。 使用拉伸操作创建质量模型,如下所示:

Lot -->
    extrude(height) Building

建筑物规则

通常在此步骤中,可以通过应用组件分割将质量模型分割为其立面。

Building --> 
    comp(f){ front : FrontFacade | side : SideFacade | top: Roof}

该规则通过应用组件分割将名为 Building(质量模型)的形状分割为其表面。 此操作将产生一个正面形状(通常是带有入口的主前立面),几个侧面形状(例如立面)和一个屋顶形状。

现在可以对立面进行建模。 典型的立面建模工作流如下:首先,可以将立面分解为楼层。 接下来,将楼层进一步细分为称为切块(楼层细分)的元素。 切片通常由墙壁和窗口元素组成。 此细分方案可应用于 CGA 形状语法,如下所示:

细分方案

FrontFacade 规则

FrontFacade 规则将前立面分割成高度为 4 的 groundfloor 形状,并重复(使用重复运算符 [*])高度约为 3.5 的 upperfloor 形状。 波形运算符 (~) 保证不限建筑物的实际高度,始终会创建足够数量的较高楼层。 底层的外观通常与其他楼层不同,尤其是前立面。 它们的不同不仅是由于存在入口,而且还通常由楼层高度尺寸、窗口外观、颜色等不同所导致。

FrontFacade -->
    split(y){ groundfloor_height : Groundfloor |
	{ ~floor_height: Floor }* }

SideFacade 规则

SideFacade 规则将侧立面分割为楼层形状。 为了确保楼层高度与前立面同步,将以同样的方式进行细分分割。

SideFacade -->     
    split(y){ groundfloor_height: Floor | { ~floor_height: Floor }* }

楼层规则

楼层规则是将楼层细分为宽度大约为 3 的切片的典型示例。 为了使楼层设计更加有趣,您将在每一侧分割一个宽度为 1 的墙壁元素。

Floor -->
    split(x){ 1: Wall 
            | { ~tile_width: Tile }* 
            | 1 : Wall }

Groundfloor 规则

Groundfloor 规则使用类似的细分分割来细化 groundfloor 形状,不同之处在于入口位于右侧。 下图首先描述了拉伸质量模型,然后描述分解成楼层和切片的过程。

拉伸质量模型
相同模型分解为楼层和切片

Groundfloor -->
    split(x){ 1: Wall 
	    |{ ~tile_width: Tile }* 
	    | ~tilewidth: EntranceTile 
	    | 1: Wall }

切片规则

定义初始立面结构后,即可对切片进行建模。

Tile -->
    split(x){ ~1 : Wall
            |  2 : split(y){ ~1: Wall | 1.5: Window | ~1: Wall }
            | ~1 : Wall }

切片规则可通过沿 x 轴和 y 轴分割(使用嵌套分割)定义切片的外观。 在此设计中,墙壁元素是浮动的(带有波形符),并且窗口的固定大小为 2 英寸宽和 1.5 英寸高。

EntranceTile 规则

EntranceTile 规则以类似于切片形状的方式定义入口形状(但显然,底部没有墙壁)。

EntranceTile -->
    split(x){ ~1 : SolidWall
            |  2 : split(y){ 2.5: Door | ~2: SolidWall }
            | ~1 : 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")

通过操作 t(x,y,z) 在 z 方向上将当前形状平移 -0.25。 这样,窗口和纹理就向立面退缩 0.25 米。 接下来,插入操作 i(objectname) 将资产插入当前范围。 如果尺寸设置与窗口或门规则不同,则会自动调整尺寸,否则将使用给定的尺寸。 通过操作 s(x,y,z),可以在墙壁规则中设置范围的大小。 由于使用了相对坐标,范围的宽度和高度不受影响:当前范围的 x 和 y 尺寸按一 ('1) 比例缩放,不会发生变化。 z 尺寸设置为 -0.4,导致墙壁厚度为 0.4 米(向内指向)。

将所有这些规则组合在一起,您将得到最终的无纹理简单建筑物:

最终的无纹理简单建筑物

在下一部分中,您将学习如何在简单的建筑物中添加纹理。

对简单建筑物进行纹理处理

在本部分中,您将学习如何将纹理应用于简单建筑物的窗口和墙壁元素。

教程设置

  1. 如果尚未打开 Tutorial_06_Basic_Shape_Grammar/scenes/01_SimpleBuilding.cej 场景,请打开该场景。
  2. 打开规则文件。 使用刚创建的规则,或在导航器中双击 Tutorial_06_Basic_Shape_Grammar/rules/simpleBuilding.01.cga 文件以打开 CGA 规则编辑器。

纹理声明

与资产一样,您将在规则文件顶部定义要使用的纹理。 纹理将从资产文件夹加载。

  1. 在 window_asset 声明下面的规则文件中添加以下新行。
  2. // textures
    frontdoor_tex   = "facades/textures/shopdoor.tif"
    wall_tex        = "facades/textures/brickwall.jpg"
    dirt_tex        = "facades/textures/dirtmap.15.tif"
    roof_tex        = "roofs/roof.tif"
    在工程的 assets/facade 文件夹中准备了九种不同的窗口纹理。 步骤 2 中的函数将返回资产文件夹中九个窗口纹理之一,而不是将所有九个纹理名称都列为单一资产。
  3. 将以下行添加到规则文件:
  4. randomWindowTexture = fileRandom("facades/textures/window.*.tif")
  5. 将 setupProjection() 命令添加到 Frontfacade 和 Sidefacade 规则中:
  6. Frontfacade -->
    	setupProjection(0, scope.xy, 1.5, 1, 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, 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 轴上每 1.5 米重复一次,在 Y 轴上每 1 米重复一次,而脏蚀贴图(通道 2)将覆盖整个立面并使用 scope.sx 和 scope.sy 作为大小参数。
  7. 添加新楼层规则。
  8. Roof --> 
    	setupProjection(0, scope.xy, scope.sx, scope.sy)	
    	texture(roof_tex)
    	projectUV(0)
    楼层规则将使用 UV 坐标以覆盖整个楼层表面,设置楼层纹理,并将纹理坐标应用于几何。
  9. 将 texture() 命令添加到后续规则中。
  10. Window -->
    	s('1,'1,0.4)
    	t(0,0,-0.25)
    	texture(randomWindowTexture)
    	i(window_asset)  
    
    Door -->
    	s('1,'1,0.1)
    	t(0,0,-0.5)
    	texture(frontdoor_tex)  
    	i("builtin:cube")
    对于窗口和门元素,只需将色彩映射表设置为所需的纹理。 对于窗口,请使用带有随机索引的 getWindowTex() 函数来获取九个窗口纹理之一。
  11. Wall 和 SolidWall 使用在立面规则中准备的 UV。 除了选择颜色通道和脏蚀通道的纹理外,还需要在这两个通道上投影 UV。
  12. Wall -->
    	color(wallColor)
    	texture(wall_tex)  
    	set(material.dirtmap, dirt_tex)
    	projectUV(0) projectUV(2)
    
    SolidWall -->
    	color(wallColor)
    	s('1,'1,0.4) 
    	t(0,0,-0.4) 
    	texture(wall_tex)  
    	set(material.dirtmap, dirt_tex)
    	i("builtin:cube:notex")	
    	projectUV(0) projectUV(2)
    下图显示了最终的建筑物模型:
    最终的建筑物模型
    相同模型的特写视图:
    最终建筑物模型的特写视图
    下图显示了适用于任意质量模型的规则设置:
    适用于任意质量模型的规则设置

添加细节层次

在本部分中,您将向简单建筑物中添加简单细节层次 (LOD) 机制。 您将减少模型的复杂程度(面计数),这有助于创建较大面积的简单建筑物。

教程设置

  1. 如果尚未打开 Tutorial_06_Basic_Shape_Grammar/scenes/02_SimpleBuilding.cej 场景,请打开该场景。
  2. 打开规则文件。 使用刚创建的规则,或在导航器中双击 Tutorial_06_Basic_Shape_Grammar/rules/simpleBuilding.02.cga 文件以打开 CGA 规则编辑器。

添加属性的细节层次

将新的属性 LOD 添加到 .cga 文件中的现有属性。

attr LOD = 1

在此示例中,您将定义以下两个细节层次:

  • LOD 0 - 细节层次低,复杂程度低
  • LOD 1 - 细节层次高,复杂程度高

您已建模的简单建筑物将成为高分辨率模型。 现在,只需几个步骤即可创建一个低分辨率版本。

检查当前模型,您会发现可以主要在窗口资产上保存面。 您将使用纹理平面代替复杂的窗口资产。

  1. 在窗口规则中,在开头添加行 case LOD > 0:,并在 else 参数中添加行 texture(randomWindowTexture。 应如下所示:
  2. Window -->
    	case LOD > 0 : 
    	  s('1,'1,0.4)
    	  t(0,0,-0.25)
    	  texture(randomWindowTexture)
    	  i(window_asset)  
    	else :		
    	  setupProjection(0,scope.xy,scope.sx,scope.sy)	
    	  texture(randomWindowTexture)	
    	  projectUV(0)
    您向窗口规则添加了一个条件:如果 LOD 值大于 0(高分辨率),请使用旧版高分辨率窗口资产。 否则(LOD 等于 0),请勿加载窗口资产,而要使用立面中的简单平面。
  3. 与门规则类似:加载简单平面而非立方体。
  4. Door -->
    	case LOD > 0 :
      s('1,'1,0.1)
    	 t(0,0,-0.5)
      texture(frontdoor_tex)
       i("builtin:cube")
    	else :
    	 setupProjection(0,scope.xy,scope.sx,scope.sy)	
    	 texture(frontdoor_tex) 
    	 projectUV(0)
  5. 现在处理 SolidWall 元素。 由于您已移除门的嵌入,因此不再需要实体元素。
  6. SolidWall -->
    	case LOD > 0 :
    	    color(wallColor)
    	    s('1,'1,0.4) 
    	    t(0,0,-0.4) 
    	    texture(wall_tex)  
    	    set(material.dirtmap, dirt_tex)
    	    i("builtin:cube:notex")	
    	    projectUV(0) projectUV(2)
        else :
    	    Wall
  7. 选择建筑物后,检查检查器的属性字段。 此处列出了新的 LOD 属性。 将该值更改为 0。
  8. 源字段从规则更改为值。 这意味着在下一次生成建筑物上,规则文件中的 LOD 值将由检查器中的值 0 设置。
    以下屏幕截图显示了 LOD = 0 时检查器中的新 LOD 属性:
    检查器的屏幕截图显示属性
  9. LOD = 0 时,生成建筑物以获取下图所示的低级版本:
    建筑物的低级分辨率图像
  10. 使用阴影上的线框(按 6)和无纹理上的线框(按 5)显示模型,差异清晰可见。 按 d-d 在包含面计数的视窗顶部显示抬头显示平视显示器。 模型从 3699 面减少到 475 面。
    模型的面减少
  11. 在下一部分中,您将为简单建筑物添加随机变化。

建筑物属性的随机变化

本部分说明如何通过定义随机属性来为生成的建筑物添加变化。

教程设置

  1. 如果尚未打开 Tutorial_06_Basic_Shape_Grammar/scenes/03_SimpleBuilding.cej 场景,请打开该场景。
  2. 打开规则文件。 使用刚创建的规则,或在导航器中双击 Tutorial_06_Basic_Shape_Grammar/rules/simpleBuilding.03.cga 文件以打开 CGA 规则编辑器。

添加随机属性

  1. 您将为三个建筑物属性添加变化:随机切片宽度在 2.5 到 6 米之间,随机建筑物高度在 8 到 35 米之间,以及为每个建筑物随机选择三种颜色。
  2. attr tile_width	= rand(2.5, 6)
    attr height		= rand(8, 35) 
    attr wallColor	= 33%  :  "#ffffff"
                      	  33%  :  "#999999"
                          else :  "#444444"
  3. 由于将生成大量建筑物,因此将默认 LOD 值从 1 更改为 0。
  4. attr LOD = 0
  5. 选择 Lots 2 图层。
  6. 通过单击形状 > 生成生成建筑物。
    生成的建筑物
    生成的建筑物