文章转自: 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