材质是用于描述多边形、折线、椭球等对象的外观特征,材质可以是几何对象表面的任一一种着色,可以是贴在其表面的一张图片、也可以是一个纹理或图案。cesium
中也提供了一些材质,比如颜色
、图片
,棋盘
、虚线
,箭头
线等。但这些基本是不会满足我们实际开发中的需求,需要自定义材质。使用Fabric
和GLSL
可以写脚本新建材质,也可以从现在的材质中派生。
1. Material
Material
是用于修改几何对象材质的一个类,在添加几何图形的时候,将设置material
属于,用于设置几何对象的材质。如给绘制的线条设置一个颜色,可以使用颜色材质,如下所示:
let line = new Cesium.Entity({
polyline:new Cesium.PolylineGraphics({
positions : positions,
material:Cesium.Color.RED.withAlpha(0.5),
width:5,
})
});
Cesium
为我们提供了23种现成的Material
类型,可通过Material.fromType
方法和Fabric
两种方式去获取并设置几何对象材质。如下是通过Material
类的两种方式实现着色的示例:
polygon.material = Cesium.Material.fromType('Color');
polygon.material.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 1.0);
//Fabric
polygon.material = new Cesium.Material({
fabric : {
type : 'Color',
uniforms : {
color : new Cesium.Color(1.0, 1.0, 0.0, 1.0)
}
}
});
2. Fabric
Fabric
是Cesium
中用于描述材质的一种JSON
规定,使用Fabric
和GLSL
可以方便的定义材质。定义一个简单的Fabric
对象,需要配置type
,uniforms
,两个属性,如果需要自定义着色器,需要添加source
属性。如下为创建一个简单的Fabric
对象:
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
type:用于定义材质的类型,使用的时候可以直接通过Cesium.Material.fromType('type');
来指定定义好的材质。设置该参数,可以复用材质,传入一个不存在的 type类型之后,这个材质将被缓存下来。下次调用 new Cesium.Material
或者 Material.fromType
就会引用缓存里的材质,不需要再传入Fabric
对象。
uniforms:用于定义变量,每个 Material
均可以有 0 ~ N 个 uniform
,这个参数在建立时指定,也能够在渲染后修改。其中有一个repeat
属性,用于控制图片在水平和垂直方向重复的次数。
components: 该属性包含了 定义了材质外观的子属性。每个子属性是一个GLSL的代码段。该属性值包含了以下几个子属性:
1. diffuse:材质的散射光通道,使用
vec3
定义了光在所有方向的散射值 。
2. specular:材质的高光属性,定个定义了材质的反射强度。
3. shininess:高反射的锐度,值 越大创建一个更小的高亮光斑。
4. normal:材质的法向属性,使用vec3
定义了在视点空间的表面法向量,一般在法向贴图上使用,默认是表面法向量。
5. emission:材质的自发光属性,使用vec3
定义了所有方向上灯光发出的颜色。
6. alpha:材质的透明度,使用一个float值 定义。
2.1创建新的材质
创建一个新的材质,只需要设置Fabric
,再加上一点点GLSL
或者其他材质就可以了。通过source
可以指定glsl
的代码,如下是返回每个分量的默认值:
czm_material czm_getMaterial(czm_materialInput materialInput)
{
return czm_getDefaultMaterial(materialInput);
}
Fabric
这么定义:
{
source : 'czm_material czm_getMaterial(czm_materialInput materialInput) { return czm_getDefaultMaterial(materialInput); }'
}
2.2 材质输入
在czm_getMaterial
函数中有一个czm_materialInput
类型的属性,用于设置材质的输入,materialInput
变量在source
和components
属性中都可以配置,主要包括以下几个属性:
1.s:一维纹理坐标。
2.st:二维纹理坐标。
3.str:三维纹理坐标。
4. tangentToEyeMatrix:从片元的切线空间转到视点空间的转换矩阵,在法向贴图和凹凸贴图时使用。
5. positionToEyeEC:从片元到视点之间的向量,为了反射和折射计算。向量的模表示了从片元到视点的距离。
6. normalEC:片元在视点空间的单位化后的法向量,在凹凸贴图、反射、折射的时候使用。
2.3 合并材质
Fabric
有个materials
属性,它的每个子属性也是Fabric材质。他们的材质可以可以在components
或者source
中引用。比如一个塑料材质可以通过 DiffuseMap
和SpecularMap
两个材质的合并来模拟。
{
type : 'OurMappedPlastic',
materials : {
diffuseMaterial : {
type : 'DiffuseMap'
},
specularMaterial : {
type : 'SpecularMap'
}
},
components : {
diffuse : 'diffuseMaterial.diffuse',
specular : 'specularMaterial.specular'
}
};
3自定义Material类
在实际开发中,为了使用方便,往往将一些常用的材质一个一个的封装,需要将其定义成Material
类,以方便代码的复用。如下为封装的一个扩散回的代码:
import * as Cesium from '@/Cesium/Source/Cesium';
import createPropertyDescriptor from "@/Cesium/Source/DataSources/createPropertyDescriptor.js";
import Property from "@/Cesium/Source/DataSources/Property.js";
const source = "czm_material czm_getMaterial(czm_materialInput materialInput)\n" +
"{\n" +
"czm_material material = czm_getDefaultMaterial(materialInput);\n" +
"material.diffuse = 1.5 * color.rgb;\n" +
"vec2 st = materialInput.st;\n" +
"float dis = distance(st, vec2(0.5, 0.5));\n" +
"float per = fract(time);\n" +
"if(dis > per * 0.5){\n" +
"material.alpha = 0.0;\n"+
"discard;\n" +
"}else {\n" +
"material.alpha = color.a * dis / per / 1.0;\n" +
"}\n" +
"return material;\n" +
"}";
function AnimationPointMaterialProperty(color,duration) {
Cesium.PolylineTrailLinkMaterialProperty = AnimationPointMaterialProperty;
Cesium.Material.AnimationPointMaterialType = 'AnimationPoint';
Cesium.Material.AnimationPointMaterialSource = source;
Cesium.Material._materialCache.addMaterial(Cesium.Material.AnimationPointMaterialType, {
fabric: {
type: Cesium.Material.AnimationPointMaterialType,
uniforms: {
color: new Cesium.Color(1.0, 0.0, 0.0, 1),
time: 0
},
source: Cesium.Material.AnimationPointMaterialSource
},
translucent: function (material) {
return true;
}
})
this._definitionChanged = new Cesium.Event();
this._color = undefined;
this._colorSubscription = undefined;
this.color = color;
this.duration = duration;
this._time = (new Date()).getTime();
}
Object.defineProperties(AnimationPointMaterialProperty.prototype, {
isConstant: {
get: function () {
return Property.isConstant(this._color);
},
},
definitionChanged: {
get: function () {
return this._definitionChanged;
},
},
color: createPropertyDescriptor("color"),
});
AnimationPointMaterialProperty.prototype.getType = function () {
return "AnimationPoint";
};
AnimationPointMaterialProperty.prototype.getValue = function (time, result) {
if (!Cesium.defined(result)) {
result = {};
}
result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;
};
AnimationPointMaterialProperty.prototype.equals = function (other) {
return (
this === other ||
(other instanceof AnimationPointMaterialProperty &&
Property.equals(this._color, other._color))
);
};
export default AnimationPointMaterialProperty;
3.1 公共方法
在定义自己的AnimationPointMaterialProperty
时,需要设置几个公共的方法,分别是:getValue
,isConstant
,definitionChanged
,equals
。
1.getValue:用来获取某个时间点的特定属性值,包括两个参数:type
和result
,分别是用于传递时间点和存储属性值。
2.isConstant:用来判断该属性是否会随时间变化,是一个bool
类型。Cesium
会通过这个变量来决定是否需要在场景更新的每一帧中都获取该属性的数值,从而来更新三维场景中的物体。如果isConstant
为true
,则只会获取一次数值,除非definitionChanged
事件被触发。
3.definitionChanged:是一个事件,可以通过该事件,来监听该Property自身所发生的变化,比如数值发生修改。
4.equals:用来检测属性值是否相等。
具体的实例可以在。cgis中预览,后期将添加更多的自定义材质。