要访问 CityEngine 中的教程,请单击帮助 > 下载教程和示例…。 在选择教程或示例后,系统会自动下载工程并将其添加到工作空间。
本教程介绍了如何将 CGA 报表变量与基于 Python 的导出器结合使用。 您将报告场景中所分布实例的信息,并使用该信息在简单的文本文件中生成实例地图。
有关详细信息,请参阅基于脚本的导出。
实例化建筑物的报表信息
在第一部分中,您将使用现有的 CGA 文件在场景中分布实例化建筑物,同时添加报表变量,以准备用于基于脚本导出器的实例的附加信息。
本教程要求用户具备 CGA 形状语法的基础知识以及编写 API 脚本的基础知识。
使用基于脚本的导出器
基于脚本的导出器从根本上来说是一个通过导出触发的 CGA 生成过程。 在导出设置中设置并在导出/生成过程中运行的 Python 脚本可以在生成过程中和生成后处理每个模型。
在此示例中,您将执行以下操作:
- 准备报告所需值的 CGA 命令。
- 查询在 CGA 规则中为每个生成的模型报告的值。
- 生成所有模型后,使用已采集的报表值编写一个文本文件。
目标
您希望编写一个包含必要数据的文本文件,以便能够在任意后续应用程序中加载分布式建筑物实例。
应针对每个实例写入以下值:
- 资产标识符
- 3 轴中的位置
- 3 轴中的旋转
- 3 轴中的缩放
采用以下形式:
nr | asset | xpos | xrot | xscale |
---|---|---|---|---|
0 |
scifi_building_9.obj |
-529.4803009 |
0 |
1.051229466 |
1 |
scifi_building_17.obj |
236.6141357 |
0 |
0.933861537 |
2 |
scifi_building_5.obj |
499.4240112 |
0 |
1.256899709 |
教程设置
- 将 Tutorial_12_Scripted_Report_Export 教程下载到您的 CityEngine 工作空间。
- 打开 Tutorial_12_Scripted_Report_Export/scenes/reportInstances_01.cej 场景。
在外部 CGA 文件中准备通用报表规则
尽管您可以将所有必要的报表命令直接添加到 CGA 文件 instance_city_01.cga 中,但您将使用通用报表规则来编写一个外部 CGA 文件。 这样,您将能够对任意 CGA 文件使用报表规则。
- 创建新规则文件文件 > 新建… > CityEngine > CGA 规则文件。
- 然后将其命名为 instanceReporting.cga。
创建新的 InstanceReport 规则。 您需要在具备规则参数资产后方可报告资产标识符。
InstanceReport(asset) -->
报告变换数据
资产标识符
您可以报告规则参数资产。
## report asset identifier
report("asset", asset)
缩放
在大多数情况下,我们需要一个与原始资产大小相对应的范围。 因此,您不能仅报告范围大小,而是需要将其除以资产大小。 可以使用 assetInfo() 命令来查询原始资产大小。 assetInfo(asset, “sx”) 将查询 x 轴上的大小。
因此,该范围的报表命令为:
## report scale values relative to asset
report("xscale", scope.sx/assetInfo(asset, "sx"))
report("yscale", scope.sy/assetInfo(asset, "sy"))
report("zscale", scope.sz/assetInfo(asset, "sz"))
旋转
您希望报告世界坐标中的旋转,因此需要使用以下 convert() 命令在 CityEngine 中转换枢轴旋转:
## report rotation in world coords
report("xrot", convert(x, pivot, world, orient, 0,0,0))
report("yrot", convert(y, pivot, world, orient, 0,0,0))
report("zrot", convert(z, pivot, world, orient, 0,0,0))
位置
位置是最为棘手的部分。 为了能够在后续应用程序中正确地实例化您的资产,请务必注意所用资产的枢轴和位置。 在我们的案例中,资产的枢轴位于地平面的中心,并且位于世界原点上。 有关说明,请参阅下面的 Maya 屏幕截图:
因此,在报告位置之前,您将通过以下方式修改资产范围:将范围缩放为一个很小的“针”,并以 x 和 z 作为中心。 这样,您即可确保所报告的位置与 Maya 中资产的枢轴相对应。
## scale and center scope
s(0.0001,'1,0.0001) center(xz)
同样,需要将该位置转换为世界坐标:
## report position in world coords
report("xpos", convert(x, scope, world, pos, 0,0,0))
report("ypos", convert(y, scope, world, pos, 0,0,0))
report("zpos", convert(z, scope, world, pos, 0,0,0))
现在,您已经报告了全部的所需值。 为了确保视窗中不会显示不需要的几何,您将在报表规则的末尾添加一个 NIL 命令。 最终报表规则:
InstanceReport(asset) -->
## report instance ID
report("asset", asset)
## report scale values relative to asset
report("xscale", scope.sx/assetInfo(asset, "sx"))
report("yscale", scope.sy/assetInfo(asset, "sy"))
report("zscale", scope.sz/assetInfo(asset, "sz"))
## report rotation in world coords
report("xrot", convert(x, pivot, world, orient, 0,0,0))
report("yrot", convert(y, pivot, world, orient, 0,0,0))
report("zrot", convert(z, pivot, world, orient, 0,0,0))
## scale and center scope
s(0.001,'1,0.001) center(xz)
## report position in world coords
report("xpos", convert(x, scope, world, pos, 0,0,0))
report("ypos", convert(y, scope, world, pos, 0,0,0))
report("zpos", convert(z, scope, world, pos, 0,0,0))
NIL
使用报表规则
让我们返回原始 CGA 规则文件,并使用准备好的报表规则。 在文件 instance_city_01.cga 的开头添加以下行,以导入准备好的 ID 为 instanceReporting 的报表规则文件。
import instanceReporting:"instanceReporting.cga"
现在,您只需将 InstanceReport 规则添加到构建规则的末尾即可。 此外,请确保在插入命令之后添加叶子规则 Asset.,以确保生成资产。
Building(asset) -->
s('1,0,'1)
i(asset) Asset.
instanceReporting.InstanceReport(asset)
现在请生成一个建筑物,并查看检查器的“报表”窗格,其外观应类似于以下内容:
导出脚本
现在,您将使用基于脚本的导出器来处理准备好的报表数据。 为此,您需要创建一个新的 Python 脚本来帮助完成这项工作。 有关详细信息,请参阅基于脚本的导出。
Python 脚本导出模板
- 根据模板文件 > 新建… > Python > Python 模块创建一个新的 python 导出脚本。
- 选择工程的脚本文件夹,将其命名为 exportInstances 并将模块:导出(报告)选作模板。
模板脚本中包含四个函数。 您只需要 finishModel() 和 finishExport(),所以请将其他两个函数删除。
访问 finishModel() 中的报表数据
可以通过以下方式访问当前已处理形状的报表变量数组:
model.getReports()['asset']
其中 asset 是报表变量的名称。
并非所有生成的形状上都具有实例(例如空的地面形状或街道形状),因此您首先需要使用报表变量之一,即 ‘asset’ 来检查是否存在报表数据:
if(model.getReports().has_key('asset')):
如果仔细查看所生成建筑物的 CGA 规则,您会注意到某些形状包含多个实例。 因此,您需要通过首先获取 ‘asset’ 数组的长度来循环每个形状的所有已报告数据集。 作为第一个测试,您会将报表数据数组打印到控制台:
l = len(model.getReports()['asset'])
for i in range(0,l):
print model.getReports()
运行基于脚本的导出器
- 选择一个小型的建筑物或地块形状集
- 启动基于脚本的导出器:文件 > 导出… > CityEngine > 导出所选形状的模型,然后选择基于脚本的导出器 (Python)
- 在其他选项选项卡中,浏览到导出脚本 exportInstances.py 并通过单击完成来运行导出器。
Python 控制台输出应读取以下类似形式的内容:
{'zpos': [-362.6108093261719], 'yrot': [-69.42008209228516], 'asset': ... {'zpos': [-362.6108093261719], 'yrot': [-69.42008209228516], 'asset': ... {'zpos': [-412.1033630371094], 'yrot': [165.30718994140625], 'asset': ... ...
注:
可以通过菜单窗口 > 显示控制台来打开 Python 输出控制台。
通过工具条上的控制台切换下拉菜单选择输出控制台。
添加全局
现在,您不再将数据打印到控制台,而是添加了一个用于处理和采集报表值的新函数 processInstance()。 另外,您(在完成模型函数之外)添加了两个全局变量,用于采集数据和追踪实例计数:
# Globals
gInstanceData = "" # global string that collects all data to be written
gInstanceCount = 0 # global count to enumerate all instances
finishModel() 函数
已完成的函数 finishModel():
# Called for each initial shape after generation.
def finishModel(exportContextOID, initialShapeOID, modelOID):
global gInstanceData, gInstanceCount
model = Model(modelOID)
if(model.getReports().has_key('asset')): # only write t3d entry if report data available
# there might be more than one asset per model, therefore loop
l = len(model.getReports()['asset'])
for i in range(0,l):
instanceData = processInstance(model.getReports(),gInstanceCount, i-1)
gInstanceData = gInstanceData+instanceData
gInstanceCount = gInstanceCount+1
processInstance() 函数
此函数仅以制表符分隔的字符串形式返回所有报表变量:
# Collect the instance information in a tab-separated string
def processInstance(reports, count, index):
## remove path from asset string
asset = reports['asset'][index]
asset = asset.rpartition("/")[2]
## prepare the string for the instance map
text = "%dt" % count;
text += "%st" % asset;
text += "%.3ft%.3ft%.3ft" % (reports['xpos'][index],reports['ypos'][index], reports['zpos'][index])
text += "%.3ft%.3ft%.3ft" % (reports['xrot'][index],reports['yrot'][index], reports['zrot'][index])
text += "%.3ft%.3ft%.3fn" % (reports['xscale'][index], reports['yscale'][index], reports['zscale'][index])
return text
finishExport() 函数
所有形状的生成均完成后,系统将调用此函数。 您将在此处定义包含实例地图的文本文件的文件名,然后调用 writeFile() 函数:
# Called after all initial shapes are generated.
def finishExport(exportContextOID):
global gInstanceData, gInstanceCount
## path of the output file
file = ce.toFSPath("models")+"/instanceMap.txt"
## write collected data to file
writeFile(file, gInstanceData)
print str(gInstanceCount)+"instances written to "+file +"n"
writeFile() 函数
…添加标题信息并将所采集的报表字符串写入磁盘:
# combining data (header and content) and writing file
def writeFile(file, content):
## prepare the head string
head = "nrtassettxpostypostzpostxrottyrottzrottxscaletyscaletzscalen"
## combine header and content
content = head + content
## write data to the file
report = open(file, "w")
report.write(content)
report.close()
运行最终脚本
- 选择一个建筑物或地块形状集。
- 启动基于脚本的导出器:文件 > 导出… > CityEngine > 导出所选形状的模型,然后选择基于脚本的导出器 (Python)。
- 在其他选项选项卡中,浏览到导出脚本 exportInstances.py 并通过单击完成来运行导出器。
生成的文件 instanceMap.txt 随即保存在当前工程的模型目录中。
nr asset xpos xrot xscale 0
scifi_building_9.obj
-529.4803009
0
1.051229466
1
scifi_building_17.obj
236.6141357
0
0.933861537
2
scifi_building_5.obj
499.4240112
0
1.256899709
您能够以任意方式处理所报告的数据,而不必编写以制表符分隔的文本文件:例如可以为 Maya 编写用于创建实例的 Mel 脚本,将位置信息写入数据库或编写基于 ascii 的自定义格式。
其他元素
由于有了通用报表规则,您现在可以轻松地使用其他实例元素来扩展 CGA 规则集,以便用于报告和导出。
- 将 instance_city_02.cga 规则分配至场景中的所有形状。
- 生成一些街道形状
该规则文件包含了街道上的未来弧元素。
打开 CGA 规则文件 instance_city_02.cga。
使用报表规则
为了将桥梁实例也导出到 instanceMap,只需将 InstanceReport 规则添加到 Bridge 规则即可。
Bridge -->
s(1,8,scope.sz+3.2) center(xz)
i(bridge_asset)
s(calcHeight2(scope.sx),calcHeight2(scope.sy),'1)
Bridge.
instanceReporting.InstanceReport(bridge_asset)
nr | asset | xpos | … |
---|---|---|---|
0 |
bridge3.obj |
-363.586952209 |
… |
1 |
bridge3.obj |
-313.587295532 |
… |
… |