CityEngine中文实例

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Tutorial_06_Basic_Shape_Grammar__2011_1
1.构建简单建筑物;
2.为简单建筑物贴纹理;
3.添加LOD;
4.建筑物属性随机变化。

一、构建简单建筑物
本节学习最终要构建一个如下图的建筑物,该建筑物有地面一楼和其他楼层,一楼的正面有一个入口的门,其他窗口都使用的是一个提前做好的OBJ模型。

下面开始创建规则进行建模:
为了更好的理解规则,我们自己创建一个新的规则,按照教程中的语句进行规则的书写。

1. 在规则文件的最开始处定义建筑的属性(也可以放在规则文件的其他位置)。

在CGA文件中,这些属性将对整个规则文件产生作用。

这些属性将显示在属性查看器(Inspector)中,可通过属性查看器修改这些属性。

attr groundfloor_height = 4 //地面一楼的高度
attr floor_height = 3.5 //其他楼层的高度
attr tile_width = 3 //将楼面按块划分的宽度
attr height = 11 //楼高
attr wallColor = "#fefefe" //墙面颜色
2. 教程中构建的窗户是使用的一个已经建好的窗户模型window.obj,这个文件存放在assets文件夹中,使用之前也要先定义出来。

window_asset = "facades/window.obj" //指定obj文件
3. 下面我们定义第一条规则为Lot. 在属性检查器中,该规则被指定为开始规则。

大量的模型是使用拉伸操作创建而来的:
//对shape使用height中定义的高度进行拉伸,并命名为Building
Lot -->
extrude(height) Building
拉伸之后如下图:
4. 可以通过应用comp()将Building分解为多个面, 生成了正面(FrontFacade)、多个侧面(SideFacade)和一个顶面(Roof)
Building-->
comp(f){ front : FrontFacade | side : SideFacade | top: Roof}
5. 分解完成之后,就开始开始对这些面进行外观造型。

典型的外观造型流程如下:1,将面分解为楼层(Floors)。

2,将楼层分解为块(Tile),每一块通常由墙面和窗口构成。

这样的细分过程在CGA要素语法的实现过程如下图:
//下面的FrontFacade规则将正面沿y轴方向,分割为两大部分,第一部分高度为groundfloor_height的地面一层Groundfloor,剩余的以floor_height高度进行重复分割(以*符号标记),分割为多个Floor。

FrontFacade -->
split(y){ groundfloor_height : Groundfloor | { ~floor_height:
Floor }* }
正面分割之后如下图:
6. 细分侧面:
SideFacade -->
split(y){ groundfloor_height: Floor | { ~floor_height: Floor }* }
SideFacade规则将侧面沿y轴方向分割也分为两大部分,这两部分使用的都是是相同的Floor对象,因此侧面这两大部分看起来都应该是一样的。

只有高度不一样,高度不一样主要是为了与正前面的楼层高度保持一致。

侧面分割之后如下图,三个侧面都是一致的:
7. 继续对Floor对象进行细化:
//先给每层楼在x轴方向的两端画出宽度为1的墙面(Wall),剩余的部分以tile_width 为宽度重复分割(Tile)
Floor -->
split(x){ 1: Wall
| { ~tile_width: Tile }*
| 1 : Wall }
如下图:
8. 最后对正面的地面一楼进行细化:
//同样先在x轴方向的两端画出宽度为1的墙面(Wall),按照tile_width划分为多个Tile,并按照tile_width划分出一个入口EntranceTile。

Groundfloor -->split(x){ 1: Wall
|{ ~tile_width: Tile }*
| ~ tile_width: EntranceTile
| 1: Wall }
结果如下图:
9. 下面对Tile进行定义:
//先对Tile在x轴方向中间划分出宽度为2的一部分(对这部分再按y轴方向先划分一个高度为分别为1和1.5的wall和window,剩余的高度也定为wall),然后两边分别划分为宽度大概为1的wall
Tile -->
split(x){ ~1 : Wall
| 2 : split(y){ 1: Wall | 1.5: Window | ~1: Wall }
| ~1 : Wall }
结果如下:
10. 对EntranceTile进行定义:
EntranceTile -->
split(x){ ~1 : SolidWall
| 2 : split(y){ 2.5: Door | ~2: SolidWall }
| ~1 : SolidWall }
先对入口在x轴方向划分宽度为2的一部分(这部分在y轴方向先划分2.5高度的Door,剩余的大约高度2定为SolidWall.),然后两边各为大约1米的Solidwall。

11. 最后对前面定义的Window,Door,Wall和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")
这里解释一下上面出现的几个命令:
① s('1,'1,0.4):
命令:s(float xSize, float ySize, float zSize)
作用设置形状的尺寸。

eg1: s(5,5,5) 表示将三个方向的值设为绝对值5
eg2: s('0.5,'1,'1.5) 等同于s(0.5*scope.sx,scope.sy,1.5*scope.sz),如果加上'符号,括号内的值在0-1之间,表示设置xyz的值为原先的多少倍。

②t(0,0,-0.25)
平移:t(tx, ty, tz)
③i(window_asset)或者i("builtin:cube:notex")
对象替换:i(geometryPath)
CityEngine有内置的素材可以直接使用,分为Geometry Assets和Textures。

Geometry Assets:
builtin:cube—有节点的单位立方体,带有纹理图层的纹理坐标系
builtin:cube:notex—单位立方体,不带有纹理坐标系
Textures:
builtin:default—表示16×16黑白方格相间的纹理
builtin:uvtest.png—使用CE标准的测试纹理
最终效果:
到此我们完成了简单建筑物的构建,学习了构建流程,如何拉伸、分解面、分割Tile 等。

规则可以一步步尝试,也可以替换成其他颜色或将obj替换为其他模型。

如下:
二、为简单建筑物贴纹理
本节内容开始对之前构建的建筑贴上纹理。

使用的规则是在上一节的基础上进行修改。

作者也是在学习中,内容中如有不对的地方,欢迎大家指正。

1. 开始贴纹理之前,先在规则的最前面对要使用的纹理进行定义。

// textures
frontdoor_tex = "facade/shopdoor.tif"
wall_tex = "facade/brickwall2.tif"
dirt_tex = "facade/dirtmap.15.tif"
roof_tex = "roof/roof.tif"
由于要使用的窗户的纹理有9种不同的纹理,这些纹理存放在assets/façade文件夹中。

在使用的时候,我们这里定义随机获取其中一个窗户纹理,这样窗户的纹理就是随机的了。

randomWindowTexture = fileRandom("*facades/textures/window.*.tif")
2. 为建筑物的正面和侧面定义纹理
Frontfacade -->
setupProjection(0, scope.xy 1.5, 1, 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, 1)
setupProjection(2, scope.xy, scope.sx, scope.sy)
split(y){ groundfloor_height: Floor | { ~floor_height: Floor }* }
添加红色部分的代码,setupProjection()定义面在scope的xy平面使用color 和dirt图片(由通道0和通道2代表)。

在使用color map时,纹理图片将以1.5m×1m进行重复贴模。

而使用dirt map时,将会在scope的x、y方向平铺。

其中setupProjection()命令有以下几种:
setupProjection(uvSet, axesSelector, texWidth, texHeight)
setupProjection(uvSet, axesSelector, texWidth, texHeight, widthOrigin, heightOrigin)
setupProjection(uvSet, axesSelector, texWidth, texHeight, widthOrigin, heightOrigin, uwFactor)
(1)uvset代表的是不同的纹理图层:
(2)axesSelector定义哪个轴分别代表u和v轴,可选的参数有:scope.xy, scope.xz, scope.yx, scope.yz, scope.zx, scope.zy 以scope的轴定义
world.xy, world.xz, world.yx, world.yz, world.zx, world.zy 以world的轴定义
(3)texWidth和texHeight分别代表纹理的宽度和长度。

如果值小于0,则认为可以对纹理做镜像显示,~符号表示值大小可以浮动,‘符号表示相对值。

(4)widthOrigin和heightOrigin分别代表距离u方向和v方向的偏移(5)uwFactor设置w轴值相对于u轴的系数,默认为0
3. 添加Roof规则
Roof -->
setupProjection(0, scope.xy, scope.sx, scope.sy)
texture(roof_tex)
projectUV(0)
其中projectUV()命令含义如下:
命令:projectUV(uvSet)
指定纹理应用于哪个uvset。

4. 为窗户和门指定纹理:
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")
5. 定义Wall和SolidWall的纹理
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)
为Wall和SolidWall定义使用的纹理,使用set()命令定义在material.dirtmap 属性,使用dirt_tex纹理。

然后定义了将纹理贴在color和dirt通道。

set(attribute, bool value)
set(attribute, float value)
set(attribute, string value)
set命令将一个值指定给当前shape的一个属性。

属性分为两类,一种是builtin 属性,就是内置属性,例如material的属性。

另一种是在规则文件中生命的属性。

最终结果如下图:
三、给建筑物制作LOD
LOD技术主要是根据距离建筑物对象的距离来调用不同复杂度的模型,即在较远距离时显示复杂度低的模型,在较近距离时显示复杂度高的模型。

在CityEngine中为了提高显示效率,也可以使用LOD机制。

本节我们就给建筑物模型添加一个简单的LOD机制。

当我们要创建大范围的建筑物模型时,可以由此降低模型的复杂度(多边形的数量)。

1、添加LOD属性
attr LOD = 1
在本示例中,只设置两个显示级别:
LOD 0:代表较低级别,低复杂度
LOD 1:代表较高级别,高复杂度
因为模型制作中,我们做的模型已经是搞分辨率的模型,因此现在通过简单的步骤创建低分辨率模型。

2 、为模型设置LOD
在目前的模型中,对于window类型的模型,之前是使用obj文件创建的一个较复杂的窗户,可以通过使用纹理平面代替obj这种复杂模型。

需要添加红色部分的代码:Window -->
case LOD > 0 :
s('1,'1,0.4)
t(0,0,-0.25)
texture(randomWindowTexture)
i(window_asset)
else :
texture(randomWindowTexture)
当LOD大于0时,使用的是之前创建的高分辨率的窗户模型,否则,使用的是一个简单的平面。

同样的,对Door和SolidWall对象也添加类似的代码。

Door -->
case LOD > 0 :
s('1,'1,0.1)
t(0,0,-0.5)
texture(frontdoor_tex)
else :
texture(frontdoor_tex)
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
应用这个规则之后,选择一个建筑物并查看其属性,会发现多了一个LOD属性。

将LOD 属性值改为0,属性表中的Source字段就从Rules改为Value。

当再次应用规则时,将使用0值作为LOD的值应用在建筑物模型上。

当LOD为0时,模型显示如下:
当LOD为1时,模型显示如下:
显示模型时,按数字7键显示/隐藏模型上的黑线,按数字5键显示/隐藏纹理图片,按字母D键显示模型包含的面数。

使用LOD之后,模型的面数从3699个面降低到了475个。

相关文档
最新文档