Fabric 是Cesium中定義的描述材質Material
的JSON 結構體。Material代表了一個物體的外觀。
材質Material
可以是比較簡單的,比如直接將一張圖片賦予表面,或者使用條紋狀、棋盤狀的圖案;也可以使用Fabric
和GLSL
,重新建立一個新的材質或者組合現有的材質。例如,我們可以通過程式生成的紋理(procedural brick)
、凹凸貼圖(bump map)
和高光貼圖(specular map)
來生成一個潮溼碎裂的磚塊材質。
在Cesium中支援賦予材質的圖元都有一個material
屬性。
polygon.material = Material.fromType('Color');
上邊這行程式碼中,Color是一個內建材質屬性,代表了單一顏色,包括透明度(alpha)。Material.fromType
是一個快捷的方式,完整的Fabric JSON 應該是這樣:
polygon.material = new Cesium.Material({
fabric : {
type : 'Color'
}
});
每一種材質(material)
都有uniforms
屬性,uniforms
可以在建立材質(material)
時或之後設定。
注:uniform是一個webgl概念,用於與頂點無關的資料。
polygon.material = new Cesium.Material({
fabric : {
type : 'Color',
uniforms : {
color : new Cesium.Color(1.0, 0.0, 0.0, 0.5)
}
}
});
// Change from translucent red to opaque white
polygon.material.uniforms.color = Cesium.Color.WHITE;
Cesium有一些內建的材質,常用的兩種為:
名稱 | 縮圖 | 描述 |
---|---|---|
Color | 顏色,包括透明度 | |
Image | 圖片,可以沒有透明度(.jpg),也可以包含透明度(.png)格式; 漫反射、rgb、alpha通道組合。 |
所有內建的材質都可以像我們建立顏色那樣簡單的建立:
polygon.material = Material.fromType('Image');
polygon.material.uniforms.image = 'image.png';
也可以這樣建立:
polygon.material = new Cesium.Material({
fabric : {
type : 'Image',
uniforms : {
image : 'image.png'
}
}
});
程式化紋理不直接依賴於圖片檔案,而是通過GPU計算而來,他們可以設定漫反射(diffuse)
和透明度(alpha)
。
名稱 | 縮圖 | 描述 |
---|---|---|
Checkerboard | Checkerboard with alternating light and dark colors. | |
Stripe | Alternating light and dark horizontal or vertical stripes | |
Dot | A pattern of dots organized by row and column. | |
Grid | A grid of lines, useful for displaying 3D volumes. |
基礎材質較為底層,可以設定基礎的材質特性,比如某個方向有多少光線被反射(鏡面強度)、或者光線發射量等等。這些材質特性通常組合起來使用,從而建立一個複雜的材質。
Name | 註釋 | Screenshot | Description |
---|---|---|---|
漫反射貼圖DiffuseMap |
可以表現出物體被光照射到而顯出的顏色和強度 | 一張具有一個三維向量(vec3) 的圖片,定義了光在所有方向上的散射顏色。 |
|
高光貼圖SpecularMap |
高光貼圖是用來表現當光線照射到模型表面時,其表面屬性的 | 一張具有標量分量的圖片,定義了單一方向反射的入射光的強度。 通過用於使物體表面的一部分有光澤,比如:水和地面。 |
|
透明貼圖 AlphaMap |
一張具有標量分量的圖片,定義了材質的透明度。通常用於使物體表面的一部分有透明度,比如:刪欄。 | ||
法線貼圖 NormalMap |
一張具有三維向量的圖片,定義了物體表面發現的切線座標。通常用於增加物體表面的細節。 | ||
凹凸貼圖BumpMap |
也叫高度貼圖,豐富物體表面的細節。 | 一張具有標量分量的圖片,類似法線貼圖,凹凸貼圖用於增加物體表面的細節無需通過實際修改物體表面。 |
|
自發光貼圖EmissionMap |
一張具有三維向量(vec3)的圖片,定義了材質在所有方向上發射的光線。例如:沿著一條公路的燈 |
多段線材質只可以用於線狀的物體。
Name | 註釋 | Screenshot |
---|---|---|
帶箭頭線 PolylineArrow |
Places an arrow head at the end point of a line. | |
發光線 PolylineGlow |
Makes glowing lines. | |
帶邊框的線 PolylineOutline |
Line outline. |
名稱 | 註釋 | 簡介 |
---|---|---|
Water | Animating water with waves and ripples. | |
高亮輪廓 RimLighting |
突出邊緣輪廓 |
更多的內建材質,請檢視 Cesium Materials Plugin.
很多的材質(material)
都有image uniform,定義了圖片路徑或資料路徑:
polygon.material.uniforms.image = 'image.png';
polygon.material.uniforms.image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC/SURBVDhPrZPRDYQgEEQpjVKuFEvhw0IoxU6QgQwMK+vdx5FsooT3GHdjCM4qZnnnHvvkYoxFi/uvIhwiRCClXFC6v5UQ1uQAsbrkHCLsbaPjFgIzQQc1yUOwu33ePGE3BQUaee2BpjhbP5YUmkAlbNzsAURfBDqJnMIyyv4JjsCCgCnIR32uZUfcJuGBOwEk6bOKhoAADh31EIq3MgFg1mgkE1BA2AoUZoo2iZ3gyqGgmMDC/xWwkfb3/eUd7A1v3kxjNW9taQAAAABJRU5ErkJggg=='
一些屬性,例如漫反射(diffuse)
或法線貼圖(NormalMap)
的屬性,要求圖片的每個畫素具有RGB三個通道;其他材質屬性,例如高光(specular)
和透明度(alpha)
,要求具有一個通道。我們可以指定從紋理圖片的那個通道中獲取資料,通過channels
或者channel
來設定。
例如,預設情況下高光specular
屬性讀取r通道,我們可以改變讀取的通道:
polygon.material = new Cesium.Material({
fabric : {
type : 'SpecularMap',
uniforms : {
image : 'specular.png',
channel : 'a'
}
}
});
允許多個材質從相同的圖片中讀取資料,例如一張相同的圖片即儲存了漫反射屬性(diffuse)
所需的rgb通道,也儲存了高光屬性(specular)
所需的a通道。這樣這張圖片只會載入一次,節省了資源。
材質material也可以使用images的repeat屬性,控制圖片在橫向和縱向的重複次數。經常被用於在物體表面的瓦片紋理。
polygon.material = new Cesium.Material({
fabric : {
type : 'DiffuseMap',
uniforms : {
image : 'diffuse.png',
repeat : {
x : 10,
y : 2
}
}
}
});
建立一個新的材質,可以通過Fabric、一些GLSL程式碼,以及其他的材質組合起來。
如果新建立的材質只使用一次,可以不設定Type
屬性:
var fabric = {
// no type
// ...rest of fabric JSON
};
polygon.material = new Cesium.Material({
fabric : fabric
});
當使用一個新的材質型別type
時,材質會在第一次繪製時快取,之後的繪製(通過new Cesium.Material
或者Material.fromType)就可以直接使用快取的材質,就像使用內建材質一樣,不需要提供完整的Fabric
描述,只需要通過type
和定義需要使用的uniforms
即可。
var fabric = {
type : 'MyNewMaterial',
// ...rest of fabric JSON
};
polygon.material = new Cesium.Material({
fabric : fabric
});
// ... later calls just use the type.
anotherPolygon.material = Material.fromType('MyNewMaterial');
可能最簡單的使用材質的方式就是直接反射白色:
var fabric = {
components : {
diffuse : 'vec3(1.0)'
}
}
稍微複雜的例子是新增高光反射屬性specular component
,這樣材料的反射光線在直視的時候最強烈,而在斜視時就變弱。
{
components : {
diffuse : 'vec3(0.5)',
specular : '0.1'
}
}
components
屬性包含了定義材料外觀的子屬性。每個子屬性都是一個GLSL
程式碼片段,比如上面範例程式碼中的vec(0.5)
建立了一個3D向量,3D向量中每個分量都被設定為0.5,。
共有以下幾個子屬性:
屬性名 | 預設值 | 描述 |
---|---|---|
漫反射diffuse |
'vec3(0.0)' | 漫反射屬性是一個三維向量vec3 ,這個向量定義了光在所有方向上的散射值。 |
高光specular |
0.0 | 高光屬性,使用浮點數定義了單一方向上的反射強度。 |
光澤度shininess |
1.0 | 鏡面反射的光澤度。越高的值建立一個更小、更集中的鏡面高光。 |
法線normal |
材質的法線屬性是一個三維向量vec3 ,定義了視點座標系下的表面法向量。通常用於法向貼圖。預設值是物體表面預設的發現。 |
|
自發光emission |
'vec3(0.0)' | 自發光屬性使用三維向量vec3 定義,定義了在所有方向上燈光發出的顏色值。預設是vec3(0.0) ,也就是不發光。 |
alpha |
1.0 | 阿法爾通道使用浮點數定義,0.0表示全透,1.0表示不透明。 |
總的來說,這些子屬性定義了材質的特點,他們是材質material的輸出值,同時也是光照系統的輸入值。
source
屬性通過為czm_getMaterial
函數定義GLSL程式碼的方式,提供了一個更加靈活的定義材質的方式。
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);
使用source
最簡單的方式是每一個屬性都直接返回預設值。
czm_material czm_getMaterial(czm_materialInput materialInput)
{
return czm_getDefaultMaterial(materialInput);
}
Fabric
定義:
{
source : 'czm_material czm_getMaterial(czm_materialInput materialInput) { return czm_getDefaultMaterial(materialInput); }'
}
我們把之前的例子中通過source
來實現的:
// 通過FABRIC 定義
{
components : {
diffuse : 'vec3(0.5)',
specular : '0.1'
}
}
// 通過source
{
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;
}`
}
使用source
代替components
的方式程式碼量更加多,但也會更加靈活,包括可以為不同的元件公用相同的計算邏輯和函數。一個經驗法則是在大多數情況下使用components
,除非需要用到czm_getMaterial
的靈活性。在底層實現上,components
子屬性也是通過czm_getMaterial
來實現的。在這兩種方式下,我們都可以用到GLSL
和Cesium
提供的內建的函數、變數、常數等。
materialInput
變數在source
和components
屬性中都是有效的,materialInput
具有以下引數欄位:
名稱 | 型別 | 描述 |
---|---|---|
**s** |
float | 一維紋理座標 |
**st** |
vec2 | 二維紋理座標 |
**str** |
vec3 | 三維紋理座標。> 注意:一維、二維、三維紋理座標之間並不一定分量相同,不能保證str.st == st and st.s == s 。例如,對於一個橢圓體,一維紋理座標s 可能是從底部到頂部,二維紋理座標st 是經緯度座標,三維紋理座標是沿著座標軸的包圍盒。 |
|
| **tangentToEyeMatrix**
| mat3 | 片元切線空間到視點座標系的轉換矩陣,通常用於法線貼圖和凹凸貼圖中。 |
| **positionToEyeEC**
| vec3 | 在視點座標系下從片元到視點的向量,用於反射、折射等等。值大小表示從片元到視點的距離。 |
| **normalEC**
| vec3 | 片元在視點座標系下單位化後的發現了,用於凹凸貼圖、反射、折射等。 |
一個使用二維紋理座標st
的簡單材質使用如下:
{
components : {
diffuse : 'vec3(materialInput.st, 0.0)'
}
}
同樣的我們可以設定materialInput.normalEC
到diffuse
,以在視點座標系下法線的視覺化。
除此之外,對於materialInput
,材質還可以使用uniform
變數,不管是Cesium內建的uniforms
還是材質特定的uniforms
。
例如,我們可以實現我們自己的Color
材質,基於color uniform
設定diffuse
以及alpha
屬性。
{
type : 'OurColor',
uniforms : {
color : new Color(1.0, 0.0, 0.0, 1.0)
},
components : {
diffuse : 'color.rgb',
alpha : 'color.a'
}
}
在Fabric
中,uniform
屬性的子屬性也是**GLSL**
中的uniforms
的名稱,以及使用new Material
以及Material.fromType
中的返回的**JavaScript**
物件。子屬性的值也是uniform的值(對於標量及向量)。
我們可以通過image uniform
實現我們自己的diffuseMap
屬性
{
type : 'OurDiffuseMap',
uniforms : {
image : 'czm_defaultImage'
},
components : {
diffuse : 'texture2D(image, materialInput.st).rgb'
}
}
在上面程式碼中,'czm_defaultImage'
是一個1x1預留位置影象,也可以使用影象URL或資料URL來指定紋理影象。例如,使用者可以這樣來建立一個OurDiffuseMap
:
polygon.material = Material.fromType('OurDiffuseMap');
polygon.material.uniforms.image = 'diffuse.png';
還有一個立方圖預留位置 czm_defaultCubeMap
。支援標準的GLSL
uniform 型別,float
、vec3
、mat4
等等。Uniform
陣列還不支援。
到目前為止,我們可以使用內建材質,或者建立我們自己的材質。我們也可以從現有的材質中建立材質(遞迴),形成材質的層次結構。
材質Fabric
具有materials
屬性,這個materials
屬性的子屬性的值都是一個材質Fabric
,也就是一種材質。這些materials
可以在components
和source
屬性中參照。例如,一個代表塑料的材質可以通過設定diffuseMap
及specularMap
來實現。
{
type : 'OurMappedPlastic',
materials : {
diffuseMaterial : {
type : 'DiffuseMap'
},
specularMaterial : {
type : 'SpecularMap'
}
},
components : {
diffuse : 'diffuseMaterial.diffuse',
specular : 'specularMaterial.specular'
}
};
上邊這段程式碼中,components
屬性中有漫反射diffuse
以及鏡面反射specular
屬性,他們從材質的materials
屬性中提取數值。命名為diffuseMaterial
及 specularMaterial
的子屬性(通過型別DiffuseMap
及SpecularMap
建立,不要混淆了名稱——範例——型別(也可以叫類))。在components
和source
屬性中,子屬性可以通過欄位名來存取,就像他們是czm_material
結構體,因此在上面程式碼中通過.diffuse
和.specular
欄位可以存取。
鑑於這一點,我們的材質material
可以像其他材質material
一樣被使用。
var m = Material.fromType('OurMappedPlastic');
polygon.material = m;
m.materials.diffuseMaterial.uniforms.image = 'diffuseMap.png';
m.materials.specularMaterial.uniforms.image = 'specularMap.png';
Fabric
的JSON結構描述在Cesium倉庫中。所有Fabric
屬性、子屬性的細節,包括type
, materials
, uniforms
, components
, source
。有一些JSON。
除了更嚴格的Fabric檔案外,該模式還可用於使用JSV等工具來驗證Fabric。
幾何物件包括 Polygon, PolylineCollection, Ellipsoid, CustomSensorVolume,等,都與材質系統整合以支援材質。大多數使用者只需簡單設定他們所需的材質屬性即可,但對於想用書寫自定義渲染程式碼的使用者,可能也需要與材質系統結合。
從渲染的角度,材質是GLSL
函數,czm_getMaterial
,以及uniforms
的組合。片元著色器需要構造一個czm_MaterialInput
,呼叫czm_getMaterial
函數,之後將計算的czm_material
結果傳遞給lighting
函數,以計算片元著色器顏色。
在JavaScript中,物件應該有一個公共的material
屬性。當這個屬性變化時,update
函數應該將材質中的GLSL
源預置到幾何物件的片元著色器中,並且組合幾何物件和材料的uniforms
。
var fsSource =
this.material.shaderSource +
ourFragmentShaderSource;
this._drawUniforms = combine([this._uniforms, this.material._uniforms]);