Graphics Tech in Cesium - Vertex Compression | cesium.com
頂點壓縮概述
計算機圖形學中一種常見的作法是打包、壓縮頂點屬性,它增加了頂點著色器中的代碼,達到減小記憶體占用的效果,同時也減少了資料通過總線從CPU到GPU的時間,降低了GPU記憶體帶寬,
另一個好處是,可以存放超過頂點屬性的最大數量的其他額外頂點屬性,
減少頂點屬性的一種方法是將所有的屬性成四維向量,并確保所有的分量充分得到使用,例如,代替如下頂點屬性:
attribute vec3 axis;
attribute float rotation;
可以用四維向量來代替:
attribute vec4 axisAndRotation;
// 使用它
vec3 axis = axisAndRotation.xyz;
float rotation = axisAndRotation.w;
通過將多個頂點屬性打包到單個浮點數中,可以進一步操作,舉個例子,為什么在一個無符號的 byte 中存盤一個 bool 型別的頂點屬性?顯然,bool 型別的只需要 1bit(1byte能存8bit),作者希望 WebGL 2.0 中會有 GLSL 逐位運算子,不過在此之前,可以用乘除2的次方的方法來移位操作,
一個 32 位浮點數有 24 位精度,所以,可以將 24 位打包成一個浮點數,以 Cesium 中的 Billboard 的屬性打包來舉例,首先:
var UPPER_BOUND = 32768.0; // 2^15
var LEFT_SHIFT7 = 128.0;
var LEFT_SHIFT5 = 32.0;
var LEFT_SHIFT3 = 8.0;
var LEFT_SHIFT2 = 4.0;
// value 小于min回傳min,大于max回傳max,否則回傳value
function clamp(value, min, max) {
return value < min ? min : value > max ? max : value;
}
// pixelOffset 是螢屏空間的像素偏移量,假設它很短,
// 開始,將它限制在 ±2^15 范圍內,
var compressed = CesiumMath.clamp(pixelOffsetX, -UPPER_BOUND, UPPER_BOUND);
// 然后加上 UPPER_BOUND,讓它回到范圍 [0, 2^16] 內
compressed = Math.floor(compressed + UPPER_BOUND);
// 左移,以便可以使用剩余的位
// [譯者注] js 的左移貌似不是這樣的,而且左移 128 位應該是不對的,應該是左移 7 位(2^7=128)?
// [譯者注] 經查應該是 compressd << 7;
compressed = * LEFT_SHIFT7;
// 水平的對齊方式(horizontalOrigin)可以是 中央、左邊、右邊,那么用2bit就可以表示,
// 整數范圍取值就是 [-1, 1],加一個1到 [0, 2],然后左移5位
// [譯者注] horizontalOrigin 應該是一個表達 billboard 對齊點位的方式,一共三種,用 -1、0、1可以表示,加1就是 0、1、2,用二進制的
// 00、01、10 完全可以表示,只占 2bit,所以在上面移動了7位之后的7個bit中占2bit即可,即向左移動5bit
// [譯者注] 假設 horizontalOrigin 是 2,那么二進制就是 0000 0010,因為前面左移空出7個bit,所以把頂頭這個1移動5個bit即可:
// 0000 0010 -> 0100 0000
// [譯者注] 所以這里這個乘號我也不知道他是不是寫錯代碼了
compressed += (horizontalOrigin + 1.0) * LEFT_SHIFT5;
// 垂直方向的同理
compressed += (verticalOrigin + 1.0) * LEFT_SHIFT3;
// 是否顯示是一個 bool 值,只用1bit就夠了,剛好用完剩下的1bit
compressed += (show ? 1.0 : 0.0) * LEFT_SHIFT2;
只需要在 GLSL 中反過來操作就可以獲取值,見 BillboardCollectionVS.glsl 中的頂點著色器,
有關更多的頂點壓縮資訊,見參考,
譯者注
這很坑啊,js代碼里的位運算貌似寫錯了,不過大體意思我是讀懂了,根據特定場合優化資料的存盤,從二進制入手,
只需要進行位運算,空出一些 bit,將一些本身并不需要很長存盤位的變數塞進去就行了,在 glsl 中進行反操作,就可以獲取壓縮的值,
法線壓縮
官方使用八進制表示法來表示 Cesium 中的單位向量,此表示方法將一個三維單位向量壓縮為二維向量,這個二維向量的每個分量用 8 bit 存盤,
參考 AttributeCompression.octEncode 方法來學習如何將單位三維向量轉換成一個八進制編碼的二維向量,
十進制編碼的向量可以存盤為二維無符號byte 型別的頂點屬性,如果有更多可用的資料,或許可以更進一步打包向量,
還可以打包兩個8bit 分量進一個浮點數,為其他資料留出 8bit,參考 AttributeCompression.octEncodeFloat 這個方法來學習編碼程序,參考 czm_octDecode 這個 glsl 函式來解碼,
還可以將三個單位向量打包成兩個浮點數,參考 AttributeCompression.octPack 方法來學習如何編碼,參考 czm_octDecode 這個 glsl 函式來解碼,
將三個單位向量編碼為兩個浮點數僅對不相關的單位向量有用,例如,切線向量僅需要編碼兩個向量,可以使用其他兩個的叉積作為第三個向量,
譯者注
主要是各種縮縮縮,摳1bit是1bit,知道是單位向量的前提下可以盡可能減少bit的占用,而且知道關系的話,可以用數學計算完成表達的,就減少一個資料的存盤也是不錯的,例如這里提到的叉積,
紋理坐標壓縮
對于 Cesium 的 Billboard 生成的幾何,它的紋理坐標并不需要用完浮點數的全24位精度,只需要12位精度即可,
紋理重復并不需要,每個紋理坐標嚴格地限制在 0 到1之間,參考 AttributeCompression.compressTextureCoordinates 方法,它將紋理坐標壓縮成一個浮點數,
在 Cesium 中,這么壓縮可能會導致 billboard 失真,但是截至發文時,官方還沒看到失真的效果,
Cesium 中的頂點壓縮
Primitive 類有一個 compressVertices 屬性,默認值是 true,這意味著 切線空間向量、紋理坐標將會被壓縮,
BillboardCollection 和 LabelCollection 的每個頂點具有18個屬性,每個屬性又是不同的型別和維度,壓縮和打包后,每個頂點的屬性被壓縮成 8 個四維浮點向量,
參考 BillboardCollection 和它的頂點著色器(BillboardCollectionVS.glsl),
譯者小結
通過預判各種屬性的情況,充分利用位運算和邏輯關系,可以將資料安插在有限的二進制位中,壓縮的作業交給資料生產者和JavaScript,
隨后由頂點著色器完成逆向決議資料的程序,充分利用GPU的計算能力,
參考
[Calver02] Dean Calver. Vertex Decompression in a Shader. In Direct3D ShaderX: Vertex and Pixel Shader Tips and Tricks. Edited by Wolfgang F. Engel. 2002.
[Cigolle14] Cigolle, Donow, Evangelakos, Mara, McGuire, Meyer, A Survey of Efficient Representations for Independent Unit Vectors, Journal of Computer Graphics Techniques (JCGT), vol. 3, no. 2, 1-30, 2014.
[Persson12] Emil Persson. Creating Vast Game Worlds. 2012.
[Pranckevi?ius09] Aras Pranckevi?ius. Compact Normal Storage for Small G-Buffers. 2009.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/228808.html
標籤:GIS
