2017-04-02 37 views
0

我從-1型的爲1 3個值的27種組合:如何將27個vector3編碼成0-256值?

Vector3(0,0,0); 
Vector3(-1,0,0); 
Vector3(0,-1,0); 
Vector3(0,0,-1); 
Vector3(-1,-1,0); 
... up to 
Vector3(0,1,1); 
Vector3(1,1,1); 

我需要將它們轉換到和從8位爲sbyte /字節數組。

一種解決方案是說第一個數字,的256 = X的第二個數字是Y和第三個是Z ...

所以

Vector3(-1,1,1) becomes 022, 
    Vector3(1,-1,-1) becomes 200, 
    Vector3(1,0,1) becomes 212... 

我更願意對其進行編碼以更緊湊的方式,也許使用字節(我無能爲力),因爲上述解決方案使用了大量的乘法和循環函數來解碼,你有一些建議嗎?另一個選項是寫入27條件,如果將Vector3組合寫入數組,看起來效率不高。

感謝惡德的指導下,我改變了代碼有點0-1值添加到第一位,並適應它unity3d:

function Pack4(x:int,y:int,z:int,w:int):sbyte { 
var b: sbyte = 0; 

b |= (x + 1) << 6; 
b |= (y + 1) << 4; 
b |= (z + 1) << 2; 
b |= (w + 1); 
return b; 
} 

function unPack4(b:sbyte):Vector4 { 
var v : Vector4; 
v.x = ((b & 0xC0) >> 6) - 1;  //0xC0 == 1100 0000 
v.y = ((b & 0x30) >> 4) - 1; // 0x30 == 0011 0000 
v.z = ((b & 0xC) >> 2) - 1;  // 0xC == 0000 1100 
v.w = (b & 0x3) - 1;   // 0x3 == 0000 0011 
return v; 
} 

回答

1

的一種方法是存儲組件每個向量位於一個字節的每2位中。

將矢量分量值轉換爲2位存儲的形式和從2位存儲形式轉換矢量分量值分別如同加1和減1一樣簡單。

-1 (1111 1111 as a signed byte) <-> 00 (in binary) 
0 (0000 0000 in binary)  <-> 01 (in binary) 
1 (0000 0001 in binary)  <-> 10 (in binary) 

打包的2位值可以按照您的偏好的任意順序存儲在一個字節中。我將使用以下格式:00XXYYZZ其中XX是X組件的轉換(打包)值,依此類推。開始時的0不會被使用。

載體然後將在一個字節被包裝如下:

byte Pack(Vector3<int> vector) { 
    byte b = 0; 
    b |= (vector.x + 1) << 4; 
    b |= (vector.y + 1) << 2; 
    b |= (vector.z + 1); 
    return b; 
} 

開箱從其字節形式的矢量將是如下:

Vector3<int> Unpack(byte b) { 
    Vector3<int> v = new Vector<int>(); 
    v.x = ((b & 0x30) >> 4) - 1; // 0x30 == 0011 0000 
    v.y = ((b & 0xC) >> 2) - 1;  // 0xC == 0000 1100 
    v.z = (b & 0x3) - 1;  // 0x3 == 0000 0011 
    return v; 
} 

上述兩種方法假定輸入是有效的,即中的vector的所有組件都是-1,01,並且Unpack中的b的所有兩位段具有(二進制)值爲00,0110

由於此方法使用按位運算符,因此速度快且效率高。如果您希望進一步壓縮數據,則可以嘗試使用2個未使用的位,並將每3個處理過的2位元素轉換爲向量。

+0

非常酷,謝謝,這是非常困難的,如果沒有良好的話題知識。我用xyzw爲vector4更改了代碼。 –

+0

好吧,我有一個錯誤,以轉換vec4版本,我修好了,歡呼聲。 –

+0

@comprehensible:用(v.x << 4)+(v.y << 2)+ v.z + 21'稍快。 –

1

最緊湊的方式是通過寫基3一個27位數(使用移位-1 -> 00 -> 11 -> 2)。

這個數的值的範圍從03^27-1 = 7625597484987,這需要43比特進行編碼,即6字節(和5備用比特)。

與一個字節中包含4兩位數字(因此總共爲7字節/ 位)的打包表示相比,這是一個小小的節省。

一個有趣的變體是將基數爲3的數字以字節爲單位進行分組(因此編號爲0242)。您仍然需要6字節(並且沒有備用位),但字節的解碼可以很容易地被硬編碼爲243條目的表格。

+0

由於我必須處理15億個體素,所以8位陣列需要大約2個演出,而vector3 int需要8個演出,最大的問題是讀寫速度。在i7上讀取10億個8位數組的速度相當快,1-2秒,然後爲每個數字做2-3個數學/轉換指令需要2-3倍的時間。因此,每次將1條指令添加到1bn數據讀取操作時,大約需要1-2秒。我會用你的建議寫數組到磁盤,聽起來很難。謝謝,基地3轉換很酷。 –

+0

@comprederstaible:「聽起來很難」:什麼? –

+0

我並不是很瞭解基地3 ......我研究了它,顯然它與使用3x3x3的基數10是一致的。艱難..我的法國人是全景的。我說出來。 –

2
  1. 我假設你值float非整

    這樣的位操作不會提高速度太多相較於轉換爲整型。所以我用全系列的賭注會更好。我會爲3D的情況下做到這一點:

    8 bit -> 256 values 
    3D -> pow(256,1/3) = ~ 6.349 values per dimension 
    6^3 = 216 < 256 
    

    所以(x,y,z)包裝看起來像這樣:

    BYTE p; 
    p =floor((x+1.0)*3.0); 
    p+=floor((y+1.0)*3.0*6.0); 
    p+=floor((y+1.0)*3.0*6.0*6.0); 
    

    的想法是轉換<-1,+1>到範圍<0,1>因此+1.0*3.0,而不是*6.0,然後只需乘上最後的BYTE中的正確位置即可。

    p拆包看起來像這樣:

    x=p%6; x=(x/3.0)-1.0; p/=6; 
    y=p%6; y=(y/3.0)-1.0; p/=6; 
    z=p%6; z=(z/3.0)-1.0; 
    

    這樣你用216從256個值是更好的然後就2位(4個值)。你的4D案例看起來類似,只是使用3.0,6.0不同的常量floor(pow(256,1/4))=4所以使用2.0,4.0但要小心p=256或使用2位每維和比特方法,如接受的答案。

    如果你需要真正的速度你可以優化這種強制包BYTE的浮點表示控股結果特定指數,並提取尾數位爲您打包直接BYTE。結果將是<0,216>您可以添加任何更大的數字。詳情請參閱IEEE 754-1985,但您希望尾數與您的BYTE對齊,所以如果您添加到p的數字如2^23那麼float的最低8位應該是您的打包值(因爲MSB 1不在尾數中),因此不需要昂貴的轉換是必要的。

  2. 如果你得到的只是{-1,0,+1}代替<-1,+1>

    那麼粗,你應該使用整型的方法,如位與每個維度2位包裝或使用LUT表的所有3^3 = 27可能性和包裝整向量在5位。

    編碼應該是這樣的:

    int enc[3][3][3] = { 0,1,2, ... 24,25,26 }; 
    p=enc[x+1][y+1][z+1]; 
    

    和解碼:

    int dec[27][3] = { {-1,-1,-1},.....,{+1,+1,+1} }; 
    x=dec[p][0]; 
    y=dec[p][1]; 
    z=dec[p][2]; 
    

    應該是足夠快,如果你有許多載體可以包裝p到每個5位...以節省更多內存空間

+0

嗨,這是一個非常有趣的編程技巧。非常感謝。原來的問題會很清楚地說明,它涉及一個體素空間,其中法線是從體素周圍的自由空間導出的,並且由於樣本太多,程序只需要0/1 2位法線來說立方體/樣品所面對的位置,之後通過泊松圓盤頂點映射將它們相加。之後我必須升級到8位精度,因爲我可以通過只保留鋸齒狀的角落並在平坦的區域平均他們周圍的樣本來抗鋸齒體素。 –

+0

@在這種情況下可理解BYTE表示更有意義,因爲您可以將其用於蒙版平滑和不僅用於抗鋸齒所需的東西。我用它來處理平鋪Voxel 3D地形的過程,即通過掩蓋相鄰體素的組合來平滑化(如何在java中生成一個類似make的Zelda)(http://stackoverflow.com/a/36263999/2521214)。基本上,我將27個體素立方體轉換爲字符串和掩碼字符串,與我執行的任務的規則相比,比如檢測特定角落以放置特定的瓷磚等等......它真的可以簡化代碼,所以相反,數百個「if else」我有幾個。 – Spektre