材質(zhì)是用于描述多邊形、折線、橢球等對象的外觀特征,材質(zhì)可以是幾何對象表面的任一一種著色,可以是貼在其表面的一張圖片、也可以是一個(gè)紋理或圖案。cesium中也提供了一些材質(zhì),比如顏色、圖片,棋盤、虛線,箭頭線等。但這些基本是不會(huì)滿足我們實(shí)際開發(fā)中的需求,需要自定義材質(zhì)。使用Fabric和GLSL可以寫腳本新建材質(zhì),也可以從現(xiàn)在的材質(zhì)中派生。
1. Material
Material是用于修改幾何對象材質(zhì)的一個(gè)類,在添加幾何圖形的時(shí)候,將設(shè)置material屬于,用于設(shè)置幾何對象的材質(zhì)。如給繪制的線條設(shè)置一個(gè)顏色,可以使用顏色材質(zhì),如下所示:
let line = new Cesium.Entity({
polyline:new Cesium.PolylineGraphics({
positions : positions,
material:Cesium.Color.RED.withAlpha(0.5),
width:5,
})
});
Cesium為我們提供了23種現(xiàn)成的Material類型,可通過Material.fromType方法和Fabric兩種方式去獲取并設(shè)置幾何對象材質(zhì)。如下是通過Material類的兩種方式實(shí)現(xiàn)著色的示例:
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中用于描述材質(zhì)的一種JSON規(guī)定,使用Fabric和GLSL可以方便的定義材質(zhì)。定義一個(gè)簡單的Fabric對象,需要配置type,uniforms,兩個(gè)屬性,如果需要自定義著色器,需要添加source屬性。如下為創(chuàng)建一個(gè)簡單的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:用于定義材質(zhì)的類型,使用的時(shí)候可以直接通過Cesium.Material.fromType('type');來指定定義好的材質(zhì)。設(shè)置該參數(shù),可以復(fù)用材質(zhì),傳入一個(gè)不存在的 type類型之后,這個(gè)材質(zhì)將被緩存下來。下次調(diào)用 new Cesium.Material或者 Material.fromType 就會(huì)引用緩存里的材質(zhì),不需要再傳入Fabric對象。
uniforms:用于定義變量,每個(gè) Material 均可以有 0 ~ N 個(gè) uniform,這個(gè)參數(shù)在建立時(shí)指定,也能夠在渲染后修改。其中有一個(gè)repeat屬性,用于控制圖片在水平和垂直方向重復(fù)的次數(shù)。
components: 該屬性包含了 定義了材質(zhì)外觀的子屬性。每個(gè)子屬性是一個(gè)GLSL的代碼段。該屬性值包含了以下幾個(gè)子屬性:
1. diffuse:材質(zhì)的散射光通道,使用
vec3定義了光在所有方向的散射值 。
2. specular:材質(zhì)的高光屬性,定個(gè)定義了材質(zhì)的反射強(qiáng)度。
3. shininess:高反射的銳度,值 越大創(chuàng)建一個(gè)更小的高亮光斑。
4. normal:材質(zhì)的法向?qū)傩?,使?code>vec3定義了在視點(diǎn)空間的表面法向量,一般在法向貼圖上使用,默認(rèn)是表面法向量。
5. emission:材質(zhì)的自發(fā)光屬性,使用vec3定義了所有方向上燈光發(fā)出的顏色。
6. alpha:材質(zhì)的透明度,使用一個(gè)float值 定義。
2.1創(chuàng)建新的材質(zhì)
創(chuàng)建一個(gè)新的材質(zhì),只需要設(shè)置Fabric,再加上一點(diǎn)點(diǎn)GLSL或者其他材質(zhì)就可以了。通過source可以指定glsl的代碼,如下是返回每個(gè)分量的默認(rèn)值:
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 材質(zhì)輸入
在czm_getMaterial函數(shù)中有一個(gè)czm_materialInput類型的屬性,用于設(shè)置材質(zhì)的輸入,materialInput 變量在source和components屬性中都可以配置,主要包括以下幾個(gè)屬性:
1.s:一維紋理坐標(biāo)。
2.st:二維紋理坐標(biāo)。
3.str:三維紋理坐標(biāo)。
4. tangentToEyeMatrix:從片元的切線空間轉(zhuǎn)到視點(diǎn)空間的轉(zhuǎn)換矩陣,在法向貼圖和凹凸貼圖時(shí)使用。
5. positionToEyeEC:從片元到視點(diǎn)之間的向量,為了反射和折射計(jì)算。向量的模表示了從片元到視點(diǎn)的距離。
6. normalEC:片元在視點(diǎn)空間的單位化后的法向量,在凹凸貼圖、反射、折射的時(shí)候使用。
2.3 合并材質(zhì)
Fabric 有個(gè)materials屬性,它的每個(gè)子屬性也是Fabric材質(zhì)。他們的材質(zhì)可以可以在components或者source中引用。比如一個(gè)塑料材質(zhì)可以通過 DiffuseMap和SpecularMap兩個(gè)材質(zhì)的合并來模擬。
{
type : 'OurMappedPlastic',
materials : {
diffuseMaterial : {
type : 'DiffuseMap'
},
specularMaterial : {
type : 'SpecularMap'
}
},
components : {
diffuse : 'diffuseMaterial.diffuse',
specular : 'specularMaterial.specular'
}
};
3自定義Material類
在實(shí)際開發(fā)中,為了使用方便,往往將一些常用的材質(zhì)一個(gè)一個(gè)的封裝,需要將其定義成Material類,以方便代碼的復(fù)用。如下為封裝的一個(gè)擴(kuò)散回的代碼:
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時(shí),需要設(shè)置幾個(gè)公共的方法,分別是:getValue,isConstant,definitionChanged,equals。
1.getValue:用來獲取某個(gè)時(shí)間點(diǎn)的特定屬性值,包括兩個(gè)參數(shù):type和result,分別是用于傳遞時(shí)間點(diǎn)和存儲(chǔ)屬性值。
2.isConstant:用來判斷該屬性是否會(huì)隨時(shí)間變化,是一個(gè)bool類型。Cesium會(huì)通過這個(gè)變量來決定是否需要在場景更新的每一幀中都獲取該屬性的數(shù)值,從而來更新三維場景中的物體。如果isConstant為true,則只會(huì)獲取一次數(shù)值,除非definitionChanged事件被觸發(fā)。
3.definitionChanged:是一個(gè)事件,可以通過該事件,來監(jiān)聽該P(yáng)roperty自身所發(fā)生的變化,比如數(shù)值發(fā)生修改。
4.equals:用來檢測屬性值是否相等。
具體的實(shí)例可以在。cgis中預(yù)覽,后期將添加更多的自定義材質(zhì)。