City Engine CGA 规则包
City Engine CGA 规则包
CityEngine的目录结构
工程中的目录结构如下:
- Assets —— 存放模型的零件与纹理图片
- Data —— 存放道路或地块数据(.shp、.osm、.dxf等)
- Images —— 存放场景快照
- Maps —— 存放地图图层来源的影像,(.jpg、.img、.tif等)
- Models —— 导出的3D模型存放位置
- Rules —— 存放规则文件 .cga
- Scenes —— 存放场景文件 .cej
- Scripts —— 存放脚本文件
https://www.esri.com/en-us/arcgis/products/arcgis-cityengine/resources
https://doc.arcgis.com/en/cityengine/latest/help/cityengine-help-intro.htm
基本规则
1、在cga编辑器中,alt + / 有智能提示
2、基本规则
- attr height = 250 —— 定义属性
- extrude(height)、extrude(axisWorld, height) —— 拉伸
- comp(f){top: Roof | side: Facede} —— 面分割
- comp(e) —— 边分割
- comp(v) —— 点分割
- color(1, 0, 0) 或 color("#69431a") —— 颜色
3、返回值,返回值在cga中不以等号形式返回。 而是在语句之后添加新的变量名用以承接
4、CityEngine中只支持投影坐标系
5、CityEngine的规则包区分大小写
6、CityEngine 2019 中坐标方向使用左手坐标系,Y轴向上(垂直方向为Y)
7、CGA的注释使用 # 、// 、/* */
8、CGA的变量定义用 attr、常量定义用 const
开始编写
第一行使用:
Lot -->
Lot 并不具有特殊含义,只是一个比较通用的表达,表示当前的规则文件被拖动到的那个形状上。也可用别的名称代替。
Lot也可被理解为 initial shape,即初始化图形,代表图形要被接下来的一系列规则所修改
简单的拉伸建筑
1、画一个简单的面
2、编写规则,把面拉起来
Lot-->
extrude(200)
将规则文件拖到圆上
选中物体后,可以看到规则中的高度
创建变量动态修改高度
方法
attr height = 20
写于Lot之上
控制GUI界面中Rule的高度变化范围
1、未控制前高度可以随意改动
@Range(200, 500)
attr height = 200
Lot-->
extrude(height)
拆分建筑六面
面分割使用 comp(f){},关键字 top、side表示屋顶和侧面, top: roof 表示将建筑物整体分割,且顶部赋值至变量 roof
@Range(200, 500)
attr height = 200
Lot-->
extrude(height) bld
bld-->
comp(f) { top : roof | side : wall }
建筑物贴图
1、设置贴图的坐标系
setupProjection(uvset, prjAxesSelector, texWidth, texHeight)
- uvset —— 要被贴图的元素的索引值,[0, 9] 的整数
- prjAxesSelector —— 设置有效的方向轴,有效参数有:scope.xy, scope.xz, scope.yx, scope.yz, scope.zx, scope.zy
- texWidth —— 宽度方向上的贴图比例,即贴图大小与建筑大小的对应。设置为 '1 则自适应以一张贴图贴满整个面
- texHeight —— 高度方向上的贴图比例,即贴图大小与建筑大小的对应。设置为 '1 则自适应以一张贴图贴满整个面
如:
@Range(200, 500)
attr height = 200
Lot-->
extrude(height) bld
bld-->
comp(f) { top : roof | side : wall }
roof-->
setupProjection(0, scope.xy, '1, '1)
projectUV(0)
texture("/ESRI.lib/assets/Roofs/Flat/flatRoof_12.jpg")
wall -->
color(1, 0, 0)
建筑分层
1、基本步骤:
拉伸建筑物 --> 调用 split(y) 进行建筑分层
# 限定数值范围是 [20, 50]
@Range(20, 50)
# 申明变量 height,其值为 20
attr height = rand(20, 50)
# 规则开始运行
Lot-->
# 以 height 作为值拉伸数据,且拉伸后的数据命名为 bld
extrude(height) bld
# 对拉伸后的 bld 进行处理
bld-->
# 建筑分层
split(y) { 4 : floors }
2、注意事项:
- CityEngine中 y 轴向上
- 按照上述的规则仅可获取建筑物的第一层,若要获取所有层需要在 split(y) { 4 : floors } 改为 split(y) { 4 : floors }*,此处的 * 代表循环执行
# 限定数值范围是 [20, 50]
@Range(20, 50)
# 申明变量 height,其值为 20
attr height = rand(20, 50)
# 规则开始运行
Lot-->
# 以 height 作为值拉伸数据,且拉伸后的数据命名为 bld
extrude(height) bld
# 对拉伸后的 bld 进行处理
bld-->
# 建筑分层
split(y) { 4 : floors }*
3、分层时容易出现的另外一个问题 —— 由于建筑高度非层高的整数倍,最顶部的一层无法达到分层高度
解决:通过 cga 规则的求均值来更改每一层的拆分高度
# 限定数值范围是 [20, 50]
@Range(20, 50)
# 申明变量 height,其值为 20
attr height = rand(20, 50)
# 规则开始运行
Lot-->
# 以 height 作为值拉伸数据,且拉伸后的数据命名为 bld
extrude(height) bld
# 对拉伸后的 bld 进行处理
bld-->
# 建筑分层
split(y) { ~4 : floors }*
使用均值分层前
使用均值分层后
shape的理解
含义:CityEngine 中的 shape 并非指 .shp 的 shape file 文件,而是指其字面意思 —— 图形。这里的图形是广义图形,既包括二维图形也包括三维图形
属性:
- ShapeSymbol —— 规则名称
- Parameters —— 参数
- Attribute —— 模型的构成与形状
- Geometry —— 几何对象,包含纹理、颜色、图形
- Scope —— 外界矩形盒
- Pivot —— 模型坐标系
常用的函数
数据处理函数
函数 | 参数含义 | 效果 |
---|---|---|
comp(f){top: roof | side: walls} | 关键字 top、side表示屋顶和侧面 top: roof 表示将建筑物整体分割,且顶部赋值至变量 roof 支持的关键字:top、side、left、right、font、back、bottom… | f — 拆分建筑物顶部和侧部 e — 拆分边 v — 节点分割 fe — 面上的边 g — 组分割 m — 材质分割 h — 洞分割 |
setupProjection(uvset, axes, width, height) | uvset — 被操作的 uv 层的索引值,取值 [0, 5] 指代材质属性 axes — 指定原点及哪些轴被指定为 u轴 或者 v轴 width — 贴图的宽度,支持 ~ 和 `(按照百分比去贴) height — 贴图的高度,支持 ~ 和 ` | 初始化基准坐标系统与 uv 集的投影矩阵,用于设置图片贴图的矩阵 |
projectUV(uvset) | uvset — 被操作的 uv 层的索引值,取值 [0, 5] 指代材质属性 彩色贴图具有 uvset0、凹凸贴图具有 uvset1、污垢贴图具有 uvset2 | 创建纹理图片坐标系 |
texture(“picture_url”) | 略 | 指定并执行具体贴图 |
split(axes) { length : new_name } | axes — 轴向(x, y, z) length — 该轴向上要切割的长度 | 用于切分模型,仅执行一次 |
split(axes) { length : new_name }* | 同上 | 用于切分模型,循环执行,直至超出模型范围 |
i(“the_utl_of_3dmodel”) | 模型地址 | 用三维模型(一般是obj)替换现有的模型结构 |
roofGable(height, length, width) | height — 屋顶的高度 length— 建筑长边的挑檐长度 width — 建筑短边的挑檐长度 | 尖顶房屋(带额头的大中分) |
roofHip(height, outlength) | height — 屋顶的高度 outlength — 延伸出来的屋檐长度 | 尖顶房屋(有刘海的西瓜头) |
roofPyramid() | 屋顶样式控制 | |
roofShed(height) | height — 屋顶的高度 | 斜坡屋顶 |
shapeL() | 分割房屋边界 | |
shapeU() | 分割房屋边界 | |
shapeO() | 分割房屋边界 | |
Scatter() | 种植树木 | |
split(){}的复杂用法:
- 常规分割和重复分割组合使用 —— split(y){2: ground | {~3: floors}* }
- 隔一层删除一层(在spilit(){}的变量命名中使用NIL) —— split(x){ {~0.75: xx | ~1: NIL}* | ~0.5: xx }
数据处理函数
函数 | 参数含义 | 效果 |
---|---|---|
rand(min, max) | 最小最大值 | 获取值域范围的一个随机值 |
重要常量
- NIL —— 删除此部分(对谁调用就删除谁)
- innerRect —— 将 Shape 转化为内接矩形,建立规则的房屋(如对三角形的地块,构建矩形房屋会被裁剪成三角形。如果使用 innerRect 就可将地块的形状,以其内接矩形作为规则应用的区域)
实例
CGA 的高级用法
以百分比划分区域,并分类进行规则引用
描述:如将一块区域按照 20%, 80% 进行随机划分,20% 种树 80% 建造房屋,此时可用如下语法
Lot-->
# 将20%的区域划分给变量 planttree
20%: planttree
# 将其余的划分给变量 building
else: building
各样的屋顶
尖顶房屋
@range(20, 50)
attr height = rand(20, 50)
Lot-->
extrude(height) bld
bld-->
comp(f){top: roof | side: walls}
roof-->
# 尖顶房屋
roofHip(30, 2.5)
辅助工具
Model Hierachy
功能:用于可视化的显示 cga 规则文件的流程
打开方式: Window —— Show Model Hierachy
CityEngine实例
导出为带属性的 slpk
原始数据具有 5 个属性(OBJECTID、name、x、y、height),若直接从 cityengine 导出为 slpk 则全部属性都会丢失,通过如下方式保留其属性
1、导入 gdb 中三维数据
2、编写 cga 以保留属性version "2019.0" attr OBJECTID=1 attr height=1 attr name="" attr x=1 attr y=1 @StartRule Lot --> report("height", geometry.height) report("name", name) report("OBJECTID", OBJECTID) report("x", x) report("y", y)
3、全选所有的三维模型,并应用 inspector 中应用规则文件
4、导出为 slpk 文件