Cesium中自定义材质material

文章转自: https://blog.csdn.net/weixin_38676065/article/details/126123975

学习参考文章:https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric

自定义材质不是必须的,但想要呈现绚丽的效果,还得自定义材质来实现。

文章目录

内置材质

类型

使用

自定义材质

组件

源代码

输入变量

fabric 对象

实例

效果

代码

分析

内置材质

类型

材质通过漫反射、镜面反射、法线、发射和 alpha 分量的组合来定义表面外观。 这些值是使用名为 Fabric 的 JSON 模式指定的,该模式在幕后被解析并组装成 glsl 着色器代码。内置的材质可以直接拿来使用,最常用的就是Color和Image。部分材质及它的uniforms如下:

材料类型描述uniforms

Color单纯的颜色color

Imagejpg 或 png 的贴图图片image、repeat

Checkerboard国际象棋格子lightColor、darkColor、repeat

Stripe竖条纹旗帜horizontal、evenColor、oddColor、offset、repeat

Dot行列点阵lightColor、darkColor、repeat

Grid线状网格color、cellAlpha、lineCount、lineThickness、lineOffset

DiffuseMap漫反射贴图image、channels、repeat

SpecularMap单通道贴图image、channel、repeat

AlphaMap单通道的不透明度贴图image、channel、repeat

NormalMap三通道贴图image、channels、repeat、strength

BumpMap单通道的凹凸贴图image、channels、repeat、strength

EmissionMap三通道的自发光贴图image、channel、repeat

PolylineArrow箭头线,终点在折线末端color

PolylineGlow发光线color、glowPower、taperPower

PolylineOutline描边线color、outlineColor、outlineWidth

Water水面贴图,看起来有水波动效baseWaterColor、blendColor、specularMap、normalMap、frequency、animationSpeed、amplitude、specularIntensity

RimLighting边缘会比较亮color、rimColor、width

使用

通过几何对象的 material 属性可以创建材质,这个属性是 Cesium.Material对象,使用内置材质设置material 非常简单。

// color

polygon.appearance.material = Cesium.Material.fromType('color');

// image

polygon.appearance.material = Cesium.Material.fromType('Image')

polygon.appearance.material.uniforms.image = 'image.png'

1

2

3

4

5

6

7

上面就创建了自定义的颜色和贴图的材质。Cesium.Material.fromType() 方法是一个简写,完整的写法是如下,Fabric 是 Cesium 中用于描述材质的一种 JSON 规定,里面type属性是材质的类型,也就是材质标识,uniforms是对应材质的一些变量,可以设置材质的颜色、图片等,不同材质的uniforms不一样。

// color

polygon.appearance.material = new Cesium.Material({

fabric: {

type: 'Color',

uniforms: {

color: new Cesium.Color(1.0, 0.0, 0.0, 0.5)

}

}

})

polygon.appearance.material.uniforms.color = Cesium.Color.WHITE

// image

polygon.appearance.material = new Cesium.Material({

fabric: {

type: 'Image',

uniforms: {

image: 'image.png'

}

}

})

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

自定义材质

使用 fabric 对象 + GLSL 代码和其他素材,就可以创建自定义材质。

let fabric = {

// ...

}

polygon.appearance.material = new Cesium.Material({

fabric: fabric

})

1

2

3

4

5

6

7

8

let fabric = {

type : 'MyNewMaterial',

// ...其他 fabric JSON 的属性

}

polygon.appearance.material = new Cesium.Material({

fabric : fabric

});

// ... 然后在另一处需要这个 fabric

anotherPolygon..appearance.material = Material.fromType('MyNewMaterial');

1

2

3

4

5

6

7

8

9

10

组件

白色的漫反射材质或许是最常用的:

let fabric = {

components: {

diffuse: 'vec3(1.0)'

}

}

1

2

3

4

5

6

稍微复杂一些,加一点镜面反射,使得正射视角看反光最强,侧面变弱:

let fabric = {

components : {

diffuse : 'vec3(0.5)',

specular : '0.1'

}

}

1

2

3

4

5

6

Fabric 是 Cesium 中用于描述材质的一种 JSON 规定,components 属性包含了 fabric 所定义的材质的各种子因素。每个子因素均使用简短的 glsl 代码字符串表示,因此上面写的 vec(0.5) 就表示 rgb 均为 0.5 的一种颜色。这个简单的 glsl 代码可以使用所有 glsl 内置的函数,例如 mix、cos、texture2D 等。components 可以定义 6 个属性:

名称默认值描述

diffuse‘vec3(0.0)’漫反射颜色,即物体的基本颜色

specular‘0.0’镜面反射,定义的是单方向反射光强度

shininess‘1.0’镜面反射的清晰度,这个值越大会出现更小的高光光斑

normal法线,默认无法线

emission‘vec3(0.0)’自发光,默认不发光

alpha‘1.0’不透明度,0.0 是完全透明,1.0 是不透明。

源代码

components 还有一个更强大而灵活的选择是 glsl 源代码,通过 glsl 的方式修改材质。这个途径将设置的 glsl 代码传递到 czm_getMaterial 函数,这个函数执行后返回材质的 components:

struct czm_materialInput

{

float s;

vec2 st;

vec3 str;

mat3 tangentToEyeMatrix;

vec3 positionToEyeEC;

vec3 normalEC;

};

struct czm_material

{

vec3 diffuse;

float specular;

float shininess;

vec3 normal;

vec3 emission;

float alpha;

};

czm_material czm_getMaterial(czm_materialInput materialInput);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

默认情况下,材质的默认值会被返回:

czm_material czm_getMaterial(czm_materialInput materialInput)

{

return czm_getDefaultMaterial(materialInput);

}

1

2

3

4

5

这个时候的 fabric 对象是:

let fabric = {

components: {

source: `czm_material czm_getMaterial(czm_materialInput materialInput) { return czm_getDefaultMaterial(materialInput); }`

}

}

1

2

3

4

5

6

上面修改了漫反射和镜面反射的例子可以通过 glsl 改写为:

let fabric = {

source: `czm_material czm_getMaterial(czm_materialInput materialInput)

{

czm_material m = czm_getDefaultMaterial(materialInput);

m.diffuse = vec3(0.5);

m.specular = 0.5;

return m;

}`

}

1

2

3

4

5

6

7

8

9

10

使用 glsl 代替 components 虽然看起来代码比较冗长,但是提供了灵活性。

如果不是有特别的需求,使用 components 属性指定材质的各种因子就可以了。但是,不管是哪一种,在这些 glsl 代码中,都是可以直接使用 glsl 的内置函数和 Cesium 预定义的 函数、结构体、常量的。

输入变量

materialInput 变量在 source 和 components 中均可以使用,在 glsl 代码的定义中,这个变量是 czm_materialInput 结构体有如下字段:

名称类型描述

sfloat一维纹理坐标

stvec2二维纹理坐标

strvec3三维纹理坐标,三维纹理的二维部分不一定就是二维纹理坐标,切记。例如,在一个椭球几何中,s可能就是从下到上,st可能是经纬度,str三维纹理就是包围盒的三轴方向。

tangentToEyeMatrixmat3用于法线贴图、凹凸贴图的转换矩阵,转换切线空间坐标到视图坐标

positionToEyeECvec3从 fragment 到 视图空间坐标的向量(不知道这个 fragment 说的是什么),用于反射和折射等。向量的长度是 fragment 到视图(相机)的距离。

normalECvec3fragment 在视图坐标中的法线(已归一化),作用于凹凸贴图、反射、折射等例如可以这么设置来可视化纹理坐标:

let fabric = {

components: {

diffuse: 'vec3(materialInput.st, 0.0)'

}

}

1

2

3

4

5

6

一样的,可以把 diffuse 组件设置为 materialInput.normalEC 来可视化法线。

除了 materialInput 这个传入的参数,还可以访问 Cesium 提供的 uniform 变量。

例如,可以通过一个 color uniform 去设置 diffuse 组件和 alpha 组件,来创建自己的 Color 材质:

let fabric = {

type: 'MyColor',

uniforms: {

color: new Color(1.0, 0.0, 0.0, 1.0)

},

components: {

diffuse: 'color.rgb',

alpha: 'color.a'

}

}

1

2

3

4

5

6

7

8

9

10

11

在 fabric 中,glsl 中的 uniform 变量、new Cesium.Material() 和 Cesium.Material.fromType() 返回的 js 对象中的 uniform 变量与 uniforms 属性的子属性(例如这里的 uniforms.color)具有相同的名称。

子属性的值(对于标量来说)或子属性(对于向量来说)即 uniform 的值。

下例,通过 image uniform 来实现自定义的 DiffuseMap 材质:

let fabric = {

type: 'OurDiffuseMap',

uniforms: {

image: 'czm_defaultImage'

},

components: {

diffuse: 'texture2D(image, materialInput.st).rgb'

}

}

1

2

3

4

5

6

7

8

9

czm_defaultImage 是 1x1 分辨率的图片,根据上面的说法,这可以从 dataurl 或图片文件中获取,例如:

polygon.appearance.material = Material.fromType('OurDiffuseMap');

polygon.appearance.material.uniforms.image = 'diffuse.png';

1

2

3

还有一个多维数据集的变量:czm_defaultCubeMap。

支持 glsl 的 uniform 类型,例如 float、vec3、mat4 等。

对于 uniform 数组还不支持,不过在规划中了。

在 fabric 这个对象中,uniforms 下的所有属性均被 glsl 认作是 uniform 变量,可以直接当变量使用,例如上例中的 texture2D(image, materialInput.st) 中的 image 参数。

在这里,规定了 image 这个 uniform 的类型是 Cesium 内置的 czm_defaultImage 结构体类型。

fabric 对象

fabric 是一个有官方规定如何写的 js 对象,它拥有 5 个属性:

type:用于声明 fabric 对象最终会生成什么材质,如果是官方内置的,直接用官方内置的,否则则创建自定义的材质并缓存。

materials:允许再塞进去子一级的 fabric,构成复合材质。

source:是 glsl 源代码,它主要是对 czm_getMaterial 这个 Cesium 内置的 glsl 函数的实现,返回值是 czm_material

components:是几个基本材质因子的 glsl 代码快捷入口,是 source 的一种简略实现。

uniforms:一些全局变量,可以在 glsl 代码中用到这个 uniform 定义的所有变量了。

实例

效果

发光特效

代码

材质代码:

const Cesium = require('cesium/Cesium')

function DynamicWallMaterialProperty (options) {

this._definitionChanged = new Cesium.Event()

this._color = undefined

this._colorSubscription = undefined

this.color = options.color

this.duration = options.duration

this.trailImage = options.trailImage

this._time = (new Date()).getTime()

this.viewer = options.viewer

}

Object.defineProperties(DynamicWallMaterialProperty.prototype, {

isConstant: {

get: function () {

return false

}

},

definitionChanged: {

get: function () {

return this._definitionChanged

}

},

color: Cesium.createPropertyDescriptor('color')

})

DynamicWallMaterialProperty.prototype.getType = function (time) {

return 'DynamicWall'

}

DynamicWallMaterialProperty.prototype.getValue = function (time, result) {

if (!Cesium.defined(result)) {

result = {}

}

result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color)

if (this.trailImage) {

result.image = this.trailImage

} else {

result.image = Cesium.Material.DynamicWallImage

}

if (this.duration) {

result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration

}

this.viewer.scene.requestRender()

return result

}

DynamicWallMaterialProperty.prototype.equals = function (other) {

return this === other ||

(other instanceof DynamicWallMaterialProperty &&

Cesium.Property.equals(this._color, other._color))

}

Cesium.DynamicWallMaterialProperty = DynamicWallMaterialProperty

Cesium.Material.DynamicWallType = 'DynamicWall'

Cesium.Material.DynamicWallImage = require('./colors.png')

Cesium.Material.DynamicWallSource = `

czm_material czm_getMaterial(czm_materialInput materialInput)

{

czm_material material = czm_getDefaultMaterial(materialInput);

vec2 st = materialInput.st;

vec4 colorImage = texture2D(image, vec2(fract(st.t - time), st.t));

vec4 fragColor;

fragColor.rgb = color.rgb / 1.0;

fragColor = czm_gammaCorrect(fragColor);

material.alpha = colorImage.a * color.a;

material.diffuse = color.rgb;

material.emission = fragColor.rgb;

return material;

}

`

Cesium.Material._materialCache.addMaterial(Cesium.Material.DynamicWallType, {

fabric: {

type: Cesium.Material.DynamicWallType,

uniforms: {

color: new Cesium.Color(1.0, 1.0, 1.0, 1),

image: Cesium.Material.DynamicWallImage,

time: 0

},

source: Cesium.Material.DynamicWallSource

},

translucent: function (material) {

return true

}

})

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

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

分析

上面是自定义材质的代码,大部分自定义材质代码的模板也是如此,不同的就是glsl里的代码和uniforms变量。uniforms变量里定义的属性,可以直接在Cesium.Material.DynamicWallSource中的glsl代码里使用。简单的光效不学glsl语言也可以模仿网上案例修改一下参数,复杂的光效就得对glsl有一定的了解。

————————————————

版权声明:本文为CSDN博主「一指流沙叹风华」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/weixin_38676065/article/details/126123975

猜你喜欢

转载自blog.csdn.net/liubangbo/article/details/129501626