1. 簡介
Fabric 是 Cesium 中用于描述材質的一種 JSON 規定,
材質表現了多邊形、折線、橢圓等形狀的外觀,
使用 Fabric 和 GLSL,可以完全自定義材質,
通過幾何物件的 material 屬性可以創建材質,這個屬性是 Cesium.Material 物件,
可以這么用:
// 假設 polygon 是一個 primitive
polygon.appearance.material = Cesium.Material.fromType('color');
這就創建了一個只有顏色的材質,包括透明度的顏色,Cesium.Material.fromType() 方法是一個簡寫,完整的寫法是:
polygon.appearance.material = new Cesium.Material({
fabric: {
type: 'Color' // 大寫
}
})
每一個 Material 都可以有 0 ~ N 個 uniform,這個引數在創建時指定,也可以在渲染后修改,例如,color 型別的 Material 就有格式為 rgba 的顏色 uniform:
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
2. 內置材質(共計23種,ver1.75)
Cesium 有幾個內置的材質,列舉兩個比較常用的:
| 材質型別 | 截圖 | 描述 |
|---|---|---|
type: 'Color' |
![]() |
一個簡單的顏色,包括透明通道 |
type: 'Image' |
![]() |
jpg 或 png 貼圖型別的材質 |
所有的內置材質可以簡單地使用 Cesium.Material.fromType() 方法創建:
polygon.appearance.material = Cesium.Material.fromType('Image')
polygon.appearance.material.uniforms.image = 'image.png'
或者用全寫法:
polygon.appearance.material = new Cesium.Material({
fabric: {
type: 'Image',
uniforms: {
image: 'image.png'
}
}
})
從這兒開始,介紹因這個 fabric 物件中的 type 不同的十幾種內置紋理,2.1~2.5
2.1. 機器生成的規律紋理(4種)
只需指定幾個引數,就可以生成一些有規律的紋理貼圖,不需要依賴外部貼圖檔案,它們相當于漫反射+透明度的組合,
| 型別 | 截圖 | 描述 |
|---|---|---|
type: 'Checkerboard' |
![]() |
國際象棋格子 |
type: 'Stripe' |
![]() |
豎條紋旗幟 |
type: 'Dot' |
![]() |
行列點陣 |
type: 'Grid' |
![]() |
線狀網格,顯示一些網狀結構的圖形 |
2.2. 基礎材質(6種)
基礎材料表達的是各個材質因子表示的材料特征,例如鏡面反射強度、自發光,通常,組合在一個 fabric 物件中創建復雜的材質,
注:如果不懂這些東西,可以請教技術美工,
| 型別 | 截圖 | 描述 |
|---|---|---|
type: 'DiffuseMap' |
![]() |
漫反射貼圖,即最常見的貼圖,通常是 rgb 三個顏色 |
type: 'SpecularMap' |
![]() |
單通道貼圖,表示的是入射光強度貼圖 |
type: 'AlphaMap' |
![]() |
單通道的不透明度貼圖 |
type: 'NormalMap' |
![]() |
三通道貼圖,表示的是法線貼圖 |
type: 'BumpMap' |
![]() |
單通道的凹凸貼圖 |
type: 'EmissionMap' |
![]() |
三通道的自發光貼圖 |
2.3. 折線材質(3種)
折線材質只作用于折線圖形,
| 型別 | 截圖 | 描述 |
|---|---|---|
type: 'PolylineArrow' |
![]() |
箭頭線,終點在折線末端 |
type: 'PolylineGlow' |
![]() |
發光線 |
type: 'PolylineOutline' |
![]() |
描邊線 |
2.4. Misc 材質(2種)
還有一些材質不屬于上面的分類,例如:
| 型別 | 截圖 | 描述 |
|---|---|---|
type: 'Water' |
![]() |
水面貼圖,看起來有水波動效 |
type: 'RimLighting' |
![]() |
邊緣會比較亮 |
2.5. 公共 uniforms
許多材質是有 image 的,可能是一個 base64 編碼的字串或檔案路徑:
polygon.appearance.material.uniforms.image = 'image.png';
polygon.appearance.material.uniforms.image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC/SURBVDhPrZPRDYQgEEQpjVKuFEvhw0IoxU6QgQwMK+vdx5FsooT3GHdjCM4qZnnnHvvkYoxFi/uvIhwiRCClXFC6v5UQ1uQAsbrkHCLsbaPjFgIzQQc1yUOwu33ePGE3BQUaee2BpjhbP5YUmkAlbNzsAURfBDqJnMIyyv4JjsCCgCnIR32uZUfcJuGBOwEk6bOKhoAADh31EIq3MgFg1mgkE1BA2AoUZoo2iZ3gyqGgmMDC/xWwkfb3/eUd7A1v3kxjNW9taQAAAABJRU5ErkJggg==';
有的材質要求貼圖有三個顏色分量,而其他材料(如高光和透明貼圖)的貼圖只需要一個顏色分量,
可以指定貼圖的通道,例如,鏡面反射的材質中,鏡面反射默認取貼圖的自 r 顏色通道,但是可以修改它為 a 通道:
polygon.appearance.material = new Cesium.Material({
fabric : {
type : 'SpecularMap',
uniforms : {
image : 'specular.png',
channel : 'a'
}
}
});
這意味著,允許把各種貼圖集中到一個貼圖檔案種,然后使用不同的通道即可,減少加載請求次數,
有些材質的貼圖紋理可以重復多次繪制,例如水平或垂直上的重復:
polygon.appearance.material = new Cesium.Material({
fabric: {
type: 'DiffuseMap',
uniforms: {
image: 'diffuse.png',
repeat: {
x: 10,
y: 2
}
}
}
})
3. 創建新材質
使用 fabric 物件 + GLSL 代碼和其他素材,就可以創建材質,
如果一個材質不想被復用,那么就不要指定它的 type 屬性,
let fabric = {
// ...
}
polygon.appearance.material = new Cesium.Material({
fabric: fabric
})
當 fabric 物件中的 type 屬性之前是沒有指定過的,那么在第一次呼叫 new Cesium.Material() 時,這個新的 fabric 材質將被快取,隨后再次 new Material 或 Material.fromType() 時將從快取中取用,
let fabric = {
type : 'MyNewMaterial',
// ...其他 fabric JSON 的屬性
}
polygon.appearance.material = new Cesium.Material({
fabric : fabric
});
// ... 然后在另一處需要這個 fabric
anotherPolygon..appearance.material = Material.fromType('MyNewMaterial');
3.1. 組件
白色的漫反射材質或許是最常用的:
let fabric = {
components: {
diffuse: 'vec3(1.0)'
}
}
稍微復雜一些,加一點鏡面反射,使得正射視角看反光最強,側面變弱:
let fabric = {
components : {
diffuse : 'vec3(0.5)',
specular : '0.1'
}
}
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 是不透明, |
3.2. 源代碼
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);
默認情況下,材質的默認值會被回傳:
czm_material czm_getMaterial(czm_materialInput materialInput)
{
return czm_getDefaultMaterial(materialInput);
}
這個時候的 fabric 物件是:
let fabric = {
components: {
source: `czm_material czm_getMaterial(czm_materialInput materialInput) { return czm_getDefaultMaterial(materialInput); }`
}
}
上面修改了漫反射和鏡面反射的例子可以通過 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;
}`
}
使用 glsl 代替 components 雖然看起來代碼比較冗長,但是提供了靈活性,
如果不是有特別的需求,使用 components 屬性指定材質的各種因子就可以了,但是,不管是哪一種,在這些 glsl 代碼中,都是可以直接使用 glsl 的內置函式和 Cesium 預定義的 函式、結構體、常量的,
3.3. 輸入
materialInput 變數在 source 和 components 中均可以使用,在 glsl 代碼的定義中,這個變數是 czm_materialInput 結構體有如下欄位:
| 名稱 | 型別 | 描述 |
|---|---|---|
s |
float |
一維紋理坐標 |
st |
vec2 |
二維紋理坐標 |
str |
vec3 |
三維紋理坐標,三維紋理的二維部分不一定就是二維紋理坐標,切記,例如,在一個橢球幾何中,s可能就是從下到上,st可能是經緯度,str三維紋理就是包圍盒的三軸方向, |
tangentToEyeMatrix |
mat3 |
用于法線貼圖、凹凸貼圖的轉換矩陣,轉換切線空間坐標到視圖坐標 |
positionToEyeEC |
vec3 |
從 fragment 到 視圖空間坐標的向量(不知道這個 fragment 說的是什么),用于反射和折射等,向量的長度是 fragment 到視圖(相機)的距離, |
normalEC |
vec3 |
fragment 在視圖坐標中的法線(已歸一化),作用于凹凸貼圖、反射、折射等 |
例如可以這么設定來可視化紋理坐標:
let fabric = {
components: {
diffuse: 'vec3(materialInput.st, 0.0)'
}
}
一樣的,可以把 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'
}
}
在 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'
}
}
czm_defaultImage 是 1x1 解析度的圖片,根據上面的說法,這可以從 dataurl 或圖片檔案中獲取,例如:
polygon.appearance.material = Material.fromType('OurDiffuseMap');
polygon.appearance.material.uniforms.image = 'diffuse.png';
還有一個多維資料集的變數:czm_defaultCubeMap,
支持 glsl 的 uniform 型別,例如 float、vec3、mat4 等,
對于 uniform 陣列還不支持,不過在規劃中了,
譯者注
這段是真夠燒腦子的,不知所云,
梳理一下,在 fabric 這個物件中,uniforms 下的所有屬性均被 glsl 認作是 uniform 變數,可以直接當變數使用,例如上例中的
texture2D(image, materialInput.st)中的 image 引數,在這里,規定了 image 這個 uniform 的型別是 Cesium 內置的
czm_defaultImage結構體型別,
3.4. 復合材質
到現在為止,可以使用內置的材質或者通過指定 fabric 中的 components 屬性(或直接使用 glsl 源代碼)來創建材質物件,
還可以通過現有材質來創建復合型別的材質,
fabric 物件有一個 materials 屬性,它的每一個子物件均可以是 fabric 物件,最終即一個材質物件,在 materials 中設定的子一級 fabric,可以在最頂級的 fabric 的 components、source 中參考,例如,現在將 DiffuseMap 材質 和 SpecularMap 材質創建一個復合材質:
let rootFabric = {
type: 'OurMappedPlastic',
materials: {
diffuseMaterial: {
type: 'DiffuseMap' // 基本型別中的一種
},
specularMaterial: {
type: 'SpecularMap'
}
},
components: {
diffuse: 'diffuseMaterial.diffuse',
specular: 'specularMaterial.specular'
}
}
這個 rootFabric 材質擁有兩個組件:diffuse(漫反射)和 specular(鏡面反射強度),而這兩個組件的值是來自 materials 中的兩個子 fabric,顯然,在 materials 定義的兩個子屬性的名稱,將會在 components 的 glsl 代碼中被作為變數使用,直接點出 diffuse 和 specular 欄位,
然后就可以像其他材質一樣使用它了:
let m = Cesium.Material.fromType('OurMappedPlastic')
polygon.appearance.material = m;
m.materials.diffuseMaterial.uniforms.image = 'diffuseMap.png';
m.materials.specularMaterial.uniforms.image = 'specularMap.png';
4. 語法規定
用了這么多 fabric 物件,其實這個 fabric 物件是有一些規定的,
在 Cesium 的官方打包包中,找到 Documentation/Schemas/Fabric,就是 fabric 物件的規定,諸如 type、materials、uniforms、components、source 這幾個屬性均能找到詳細的定義,
5. 渲染流水線中的材質
從渲染的角度看,一種材質其實是一個 glsl 函式:czm_getMaterial,片元著色器需要構造一個 czm_MaterialInput 結構體變數,呼叫 czm_getMaterial 函式,然后生成 czm_material 結構變數,傳遞給照明函式來計算片元的顏色,
在 js 中,fabric 物件應該有一個 material 屬性,當此屬性發生變動時,圖元的 update 函式觸發,然后將 fabric 材質最終的 glsl 代碼與默認的片元著色器代碼合并在一起,然后再將 uniform 合并:
const fsSource = this.material.shaderSource + ourFragmentShaderSource;
this._drawUniforms = combine([this._uniforms, this.material._uniforms]);
6. 筆者注
這篇文章較為詳細地介紹了 Appearance 物件中的 fabric 屬性構成,
fabric 是一個有官方規定如何寫的 js 物件,它擁有 5 個屬性:
- type
- materials
- source
- components
- uniforms
其中,type 用于宣告 fabric 物件最侄訓生成什么材質,如果是官方內置的,直接用官方內置的(2.1~2.4),否則則創建自定義的材質并快取,
materials 允許再塞進去子一級的 fabric,構成復合材質,
uniforms 是一些全域變數,例如你可以在這里寫一個 myUniformVariable,然后你就可以在 components 或者 source 的 glsl 代碼中用到這個 uniform 變數了,
source 是 glsl 源代碼,它主要是對 czm_getMaterial 這個 Cesium 內置的 glsl 函式的實作,回傳值是 czm_material
components 是幾個基本材質因子的 glsl 代碼快捷入口,是 source 的一種簡略實作,
創建好 fabric 材質物件后,隨之就可以創建 Appearance 物件,與幾何實體一起創建 Primitive 了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/228506.html
標籤:其他
上一篇:智能資訊處理

















