kikita & Maps

GIS,spatial and artificial intellegence learning and share

​ 接着上一篇

​ 为了让脚本看起来更连贯,无需跳转上一篇,我们从头开始。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* File: MyTestforBaseTexure.cga
* Created: 30 Mar 2018 08:16:37 GMT
* Author: Xiaoyan Mu
*/

version "2017.1"
attr height = 10
attr groundfloor_height = 4
attr floor_height = 3.5
attr tile_width = 3.5

wall_tex = "facades/textures/brickwall.jpg"
dirt_tex = "facades/textures/dirtmap.15.tif"
graffiti_tex = "facades/textures/Graffiti.jpg"
window_tex = "facades/textures/window.5.tif"

Lot --> extrude(height) Building

Building --> comp(f) {front : Sidefacade}

​ 假设我希望在这面墙上“凿”出窗户,就需要将Sidefacade进行细化切割。贴纹理时也要注意一下新的技巧,也就是在细分表面之前先定义纹理UV,细分之后再用上一篇中提到的贴纹理的方法应用到Wall,这样就可以得到连续的墙体贴图。这样的做的原因在于,CE中的shape都是被不断迭代替换的,如果不在细分之前定义UV,Sidefacade对象在细分之后已经消亡了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Sidefacade is modified

Sidefacade -->
# Setup texturing
setupProjection(1, scope.xy, 1.5, 1)
setupProjection(2, scope.xy, scope.sx, scope.sy)
# Divide Sidefacade
split(y){ groundfloor_height: Wall | {~floor_height : Floor}* }

Floor -->
split(x){ 1 : Wall | { ~tile_width : Tile }* | 1 : Wall }
Tile -->
split(x){ ~1 : Wall | 2 : split(y){ ~1: Wall | 1.5: Window | ~1: Wall } | ~1 : Wall }

Wall -->
# Apply the texture
set(material.bumpmap,wall_tex)
set(material.dirtmap, dirt_tex)
projectUV(1)
projectUV(2)

Window -->
offset(0.05)
comp(f) { inside: WondowInner | border: WondowFrame }
WondowInner -->
setupProjection(0, scope.xy, scope.sx, scope.sy)
texture(window_tex)
projectUV(0)
WondowFrame -->
extrude(0.1)

material.opacitymap

material.opacitymap 通道可以用于控制纹理的透明度。

继续上面的例子,如果希望做出透明的窗户效果,可以将Window的代码替换为如下的样子。

1
2
3
4
5
6
7
8
9
Window -->
offset(0.05)
comp(f) { inside: WondowInner | border: WondowFrame }
WondowInner -->
setupProjection(4, scope.xy, scope.sx, scope.sy)
set(material.opacitymap, window_tex)
projectUV(4)
WondowFrame -->
extrude(0.1)

material.specularmap

为了虚拟现实,窗户玻璃来点反光效果吧。

上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Window -->
offset(0.05)
comp(f) { inside: WondowInner | border: WondowFrame }
WondowInner -->
setupProjection(0, scope.xy, scope.sx, scope.sy)
texture(window_tex)
projectUV(0)
set(material.specular.r, 1)
set(material.specular.g, 1)
set(material.specular.b, 1)
set(material.shininess, 2)
setupProjection(3, scope.xy, scope.sx, scope.sy)
set(material.specularmap, specular_tex)
projectUV(3)
WondowFrame -->
extrude(0.1)

剩下最后的 normalmap了,法向贴图。手里没有什么好例子,找到一篇OpenGL的文档,帮助理解。

完结。

​ 经常看到官微、公众号的各种推送,了解到很多轰动一时的大片和电游的视觉制作都有CityEngine 助力过。CityEngine 在影娱视觉行业早已硕果累累,而对于GIS大众,CityEngine 算是刚从幕后走到了台前,从神秘娱乐圈走近了烟火人间。这几年来,这个不姓“Arc”的非主流产品在不断地推陈出新,吸引着慕名围观的用户去了解。3D模型的纹理贴图问题通常是建模中的高频问题,作为前排围观群众之一,我今天就用CityEngine做一面“墙”娱乐一下吧。

环境: Esri City Engine 2017.1

​ 在 CityEngine中的 shape 对象具有material 属性,这一属性可以控制模型的纹理贴图、阴影效果、外观等。CityEngine 支持的纹理图片的格式有:**.bmp、.gif、.jpg/.jpeg、.png、.tif/.tiff**。 CityEngine贴图支持6个纹理通道,它们通过特定的关键字来表达,如下:

uv-set Texture Layer
0 colormap
1 bumpmap
2 dirtmap
3 specularmap
4 opacitymap
5 normalmap

下面我通过几个实例来说明下它们的用途:

​ 基于共同的基础脚本向下进行,这里不再解释,相信你一看即懂。

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* File: MyTestforBaseTexure.cga
* Created: 21 Mar 2018 08:26:37 GMT
* Author: Xiaoyan Mu
*/

version "2017.1"
attr height = 6
wall_tex = "facades/textures/brickwall.jpg"
dirt_tex = "facades/textures/dirtmap.15.tif"
graffiti_tex = "facades/kiktia/Graffiti.jpg"
Lot --> extrude(height) Building
Building --> comp(f) {side : Sidefacade}

material.colormap

1
2
3
4
Sidefacade -->
setupProjection(0, scope.xy, 1.5, 1, 1)
texture(wall_tex) # set(material.colormap,wall_tex)
projectUV(0)

texture(wall_tex) ,实际是 set(material.colormap,wall_tex) 的简写,这个函数仅用于为当前shape指定纹理图片,而没有创建纹理坐标系。因此事先需要使用 setupProjection() ,用于指定贴图表面上的UV坐标系,以及贴图矩阵的排布样式。最后使用 ProjectUV()将贴图UV坐标系应用到贴图表面,这个过程有时被称为“烘焙(bake)”。相关函数的具体语法请查 帮助

​ “烘焙”是个形象生动的词,是个3D建模领域的常用词,对于GIS圈子的朋友可能有点陌生,在一个**论坛**里找到一个描述觉得不错分享大家。

“Baking” generally refers to the process of recording as an image, some aspect of the Material or Mesh characteristics of a model. One value of this is that certain kinds of Material parameters can take longer to compute and apply to a model than an Image Texture, so it saves rendering time. Baking is usually done once a Material or Mesh is finalized.

In texture baking, for example, what is originally a procedural texture can be recorded as an image. Sometimes various “channels” of a material can be consolidated into a single image, simplifying the number of texture images used. Material colors applied in Texture Paint mode can be saved to an image. Texture baking can also help with disguising seams on a UV unwrap, a somewhat complicated but very useful process.

In normal baking, the mesh normals (which affect how light appears to reflect from the model’s surface) can be recorded – this results in very specialized images with RGB values based on normal vectors.

Usually baking requires having the model UV-unwrapped and -mapped, so the resulting image is properly fit to the model.

material.bumpmap

material.bumpmap 可以实现贴图的浮雕效果。

1
2
3
4
Sidefacade -->
setupProjection(1, scope.xy, 1.5, 1, 1)
set(material.bumpmap,wall_tex)
projectUV(1)

material.dirtmap

​ 如果想使这面墙更逼真,来点“做旧”的感觉,可以使用 material.dirtmap 通道来增加图片镶嵌的效果。

1
2
3
4
5
6
7
8
Sidefacade -->
setupProjection(0, scope.xy, 1.5, 1, 1)
texture(wall_tex)
projectUV(0)
# Add dirtmap channel
setupProjection(2, scope.xy, scope.sx, scope.sy)
set(material.dirtmap, dirt_tex)
projectUV(2)

​ 相同的方法来做一面涂鸦墙也可以哦。(涂鸦图片来自网络,侵删)

​ 将dirtmap换张图, set(material.dirtmap, graffiti_tex)

先到这里,下篇继续……

我们可以将2D矢量数据、3D模型格式导入到CityEngine 中使用,前者一般作为CityEngine shape 来使用,后者作为模型来使用。

OBJ,DAE,FBX这几种模型格式导入时可以作为两种角色来使用,shape 或 static model。这是由导入窗口中的 Import as static model 设置控制的。

Import as static model

When checked, the file will be imported ‘as is’ and will not be modifiable by cga rules.

  • Shapes—Serve as a base for CGA generation. A typical example is footprint data.
  • Static models—Can be scaled, rotated, and translated after import but cannot be processed further with CGA.

通过如上说明,我们可以清晰的了解到把模型转为shape或Static Model的差异。 一般实际应用中,我们会把当作“素材”使用的模型小件作为static model用;而把表示基础结构的模型作为shape来使用。

static model导入之后,仍然可以再转换为shape,操作:菜单栏 Shapes->Convert Models to Shapes。成为shapes 之后,就可以通过cga对这个模型的继续进行改造了。

在如下示例图中了解:

这是一部老片。

年少无知的时候,看到题目《闻香识女人》,暗自以为这是一部有关调情高手的电影,完全无感,从此错过。

在没有很多电影可以走入内心的今天,翻看旧电影真的是种享受。竟然有几句台词可以让我记住和感动。


Now I’ve come to the crossroad in my life. I always knew what the right path was. Without exception. I knew, but I never took it. You know why. It’s was too damn hard.


But there is nothing like the sight of an amputated spirit. There is no prosthetic for that.


我虽不是很相信人有灵魂,但我确信看到过人性的高贵。

说到免费开放的数据,自然会想到 Open Street Map,这里分享下在 ArcGIS 产品线中osm数据的使用实践。

环境:ArcGIS Desktop 10.6, Esri CityEngine 2017.1

在ArcMap中使用osm数据

一般情况下,我们可以在 Open Street Map 官网可以通过指定范围直接下载osm格式数据,然后在 ArcMap中直接读取。如下,以Esri中国所在的金泰大厦为中心的数据:

ArcMap直读OSM

osm数据是基于xml的数据格式,ArcMap不能直接编辑。如果希望导入地理数据库中编辑,可以利用插件,这是Esri额外提供的一个桌面端的免费开源的osm插件,ArcGIS Editor for OSM 10.6.x Desktop。 通过这个插件可以下载、更新OSM数据有关这个插件的源码、文档,可以在Github上获得。

OSM is an XML-based format used to describe vector data in a map. It defines three basic data types—nodes, ways, and closed ways—which are used to describe all the other elements:

  • Nodes—Points between which segments are drawn.
  • Ways—Ordered list of nodes, displayed as connected by line segments in the editor.
  • Closed Ways—Ways that go in a complete loop. They are used to describe areas such as parks, lakes, or islands.

以前10.3年代的时候,整理过一次简单的说明,点这里直达。通过测试,相同的网络环境下,官网下载osm数据,之后再使用 Load OSM File 导入GDB,效率明显优于直接使用 Download OSM Data导入GDB。

在CityEngine中使用osm数据

如果osm数据用于CityEngine,那么无需事先导入GDB,CityEngine可以直接解析osm并可分类导入数据,例如下图中导入highway,Building类:

导入OSM至CityEngine场景

在CityEngine中导入osm时,可以勾选“Map OSM tags”,从而CityEngine会通过OSM street type来定义道路的宽度,并给与不同道路组成部分不同的起始规则,方便后续利用规则批量建模。如下,以金泰大厦以南的东直门大枢纽为例,复杂的交通仍然保持错落有致:

OSM Highway

选中Jintai_Streets 这个图层,可以在Inspect窗口中看到图层的属性,其中即为默认情况下osm数据在CityEngine中的映射规则,可以根据需要修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//------------------------- 
// Example OSM Tag Mapping

streetscale = 1 // street width scale factor

width = getObjectAttr("width", false)
lanes = getObjectAttr("lanes", false)

attr streetWidth = // street width dependeding on available attributes
case width > 0 : width * streetscale
case lanes > 0 : lanes * 3.5 * streetscale
else : streetWidthByClass * streetscale * oneway

class = getObjectAttr("highway", false)

streetWidthByClass =
case class == "primary" : 8
case class == "secondary" : 7
case class == "tertiary" : 6
case class == "motorway" : 12
case class == "trunk" : 11
case class == "road" : 6
case class == "residential" : 5
case class == "footway" : 2
case class == "cycleway" : 2
case class == "steps" : 2
else : 4

oneway = // oneway width correction
case getObjectAttr("oneway", false) == "yes" : 0.5
else : 1

sidewalkscale = 1 // sidewalk width scale factor

sidewalkWidth =
case class == "primary" : 2
case class == "secondary" : 2
case class == "tertiary" : 2
case class == "residential" : 2
else : 0

attr sidewalkWidthLeft = sidewalkWidth * sidewalkscale
attr sidewalkWidthRight = sidewalkWidth * sidewalkscale

默认情况下,进入cityEngine中的道路数据,会使用Esri.lib库中的规则Street_Modern_Standard.cga,当然也可以自己来编写。

0%