要访问 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() 中的报表数据
您可以按如下方式访问当前处理的形状的报表变量数组,其中 asset 是报表变量的名称:
model.getReports()['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 = "%d\t" % count;
text += "%s\t" % asset;
text += "%.3f\t%.3f\t%.3f\t" % (reports['xpos'][index],reports['ypos'][index], reports['zpos'][index])
text += "%.3f\t%.3f\t%.3f\t" % (reports['xrot'][index],reports['yrot'][index], reports['zrot'][index])
text += "%.3f\t%.3f\t%.3f\n" % (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 = "nr\tasset\txpos\typos\tzpos\txrot\tyrot\tzrot\txscale\tyscale\tzscale\n"
## 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 | ... |
... |