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

本教程介绍了如何将 CGA 报表变量与基于 Python 的导出器结合使用。 您将报告场景中所分布实例的信息,并使用该信息在简单的文本文件中生成实例地图。

有关详细信息,请参阅基于脚本的导出

GUID-0ABBFA13-C90D-4C3F-AD23-800425355FAC-web

实例化建筑物的报表信息

在第一部分中,您将使用现有的 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

 

 

教程设置

  1. 将 Tutorial_12_Scripted_Report_Export 教程下载到您的 CityEngine 工作空间。
  2. 打开 Tutorial_12_Scripted_Report_Export/scenes/reportInstances_01.cej 场景。

在外部 CGA 文件中准备通用报表规则

尽管您可以将所有必要的报表命令直接添加到 CGA 文件 instance_city_01.cga 中,但您将使用通用报表规则来编写一个外部 CGA 文件。 这样,您将能够对任意 CGA 文件使用报表规则。

  1. 创建新规则文件文件 > 新建… > CityEngine > CGA 规则文件
  2. 然后将其命名为 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 屏幕截图:

GUID-ABCC7E6E-6687-4CE1-9C5B-5486646FBF6F-web

因此,在报告位置之前,您将通过以下方式修改资产范围:将范围缩放为一个很小的“针”,并以 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)

现在请生成一个建筑物,并查看检查器的“报表”窗格,其外观应类似于以下内容:

GUID-633E1235-B475-4722-BE63-430FAF3BBEDC-web

 

导出脚本

现在,您将使用基于脚本的导出器来处理准备好的报表数据。 为此,您需要创建一个新的 Python 脚本来帮助完成这项工作。 有关详细信息,请参阅基于脚本的导出

Python 脚本导出模板

  1. 根据模板文件 > 新建… > Python > Python 模块创建一个新的 python 导出脚本。
  2. 选择工程的脚本文件夹,将其命名为 exportInstances 并将模块:导出(报告)选作模板。
    GUID-9D3AB2EC-0F16-4F88-AD60-D485CA05F3D5-web

模板脚本中包含四个函数。 您只需要 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()

运行基于脚本的导出器

  1. 选择一个小型的建筑物或地块形状集
  2. 启动基于脚本的导出器:文件 > 导出… > CityEngine > 导出所选形状的模型,然后选择基于脚本的导出器 (Python)
  3. 其他选项选项卡中,浏览到导出脚本 exportInstances.py 并通过单击完成来运行导出器。
    GUID-E0554A0D-2EFA-4CE0-AA52-5845DCB48F51-web

    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()

运行最终脚本

  1. 选择一个建筑物或地块形状集。
  2. 启动基于脚本的导出器:文件 > 导出… > CityEngine > 导出所选形状的模型,然后选择基于脚本的导出器 (Python)
  3. 其他选项选项卡中,浏览到导出脚本 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 规则分配至场景中的所有形状。
  • 生成一些街道形状

该规则文件包含了街道上的未来弧元素。

GUID-6F29925C-88EF-4D55-B02F-00462A1D2475-web
GUID-35823839-A8C1-400A-A381-936830ECAEFE-web

打开 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