在高性能計算場景,例如體素光線追蹤器中,數(shù)據(jù)存儲和檢索的效率至關(guān)重要。將空間數(shù)據(jù)存儲在字典中(如 data["4,16"])并使用字符串作為鍵雖然直觀,但字符串與坐標(biāo)之間的轉(zhuǎn)換以及字典本身的性能開銷,在大規(guī)模數(shù)據(jù)處理時會成為瓶頸。將數(shù)據(jù)扁平化存儲在有序數(shù)組(或列表)中,并通過數(shù)學(xué)運(yùn)算將一維索引映射到多維坐標(biāo),是實(shí)現(xiàn)性能優(yōu)化的關(guān)鍵策略。
理解三維轉(zhuǎn)換之前,我們先回顧二維空間中的索引轉(zhuǎn)換。對于一個寬度為 width 的二維網(wǎng)格,給定一個一維索引 i,其對應(yīng)的 (x, y) 坐標(biāo)可以這樣計算:
這可以通過以下Python函數(shù)實(shí)現(xiàn):
import math def index_vec2(i: int, width: int): """ 根據(jù)寬度將一維索引轉(zhuǎn)換為二維 (x, y) 坐標(biāo)。 參數(shù): i (int): 一維索引。 width (int): 網(wǎng)格的寬度。 返回: tuple: 對應(yīng)的 (x, y) 坐標(biāo)。 """ x = math.floor(i % width) y = math.floor(i / width) return x, y
例如,在一個4x4的網(wǎng)格中,索引3對應(yīng) (3, 0),索引4對應(yīng) (0, 1)。這個函數(shù)只需要寬度信息,因?yàn)楦叨瓤梢酝ㄟ^索引的范圍隱式確定。
將上述邏輯擴(kuò)展到三維空間時,我們需要考慮深度(z軸)。對于一個寬度為 width、高度為 height 的三維網(wǎng)格,給定一個一維索引 i,我們需要計算其對應(yīng)的 (x, y, z) 坐標(biāo)。
一個常見的錯誤嘗試是直接將二維邏輯疊加:
def incorrect_index_vec3(i: int, width: int, height: int): """ 錯誤的將一維索引轉(zhuǎn)換為三維 (x, y, z) 坐標(biāo)的嘗試。 此函數(shù)中y坐標(biāo)在Z層切換時不會歸零。 """ x = math.floor(i % width) y = math.floor(i / width) # 這里的y計算是錯誤的 z = math.floor(i / (width * height)) return x, y, z
讓我們通過一個 4x4x4 的立方體(總共64個元素)來模擬迭代,觀察 incorrect_index_vec3 函數(shù)的輸出:
索引 i | 預(yù)期 (x,y,z) | incorrect_index_vec3 輸出 (x,y,z) | 問題 |
---|---|---|---|
0 | (0,0,0) | (0,0,0) | 正確 |
... | ... | ... | ... |
15 | (3,3,0) | (3,3,0) | 正確 |
16 | (0,0,1) | (0,4,1) | y 錯誤地從 4 開始,而不是 0 |
... | ... | ... | y 持續(xù)增長 |
從輸出可以看出,當(dāng) z 坐標(biāo)從0變?yōu)?時(即從一個 width * height 的平面切換到下一個平面),y 坐標(biāo)并沒有像預(yù)期的那樣從0重新開始計數(shù),而是繼續(xù)遞增。這是因?yàn)?y = i / width 的計算沒有考慮到 z 層的邊界,它將整個一維數(shù)組視為一個非常高的二維平面,導(dǎo)致 y 值不斷累積。
為了解決 y 坐標(biāo)的問題,我們需要分層計算?;舅枷胧牵?/p>
Python的 divmod(a, b) 函數(shù)非常適合這種場景,它會同時返回 a 除以 b 的整數(shù)商和余數(shù),從而避免了重復(fù)的除法和取模運(yùn)算,使代碼更簡潔高效。
def index_vec3(i: int, width: int, height: int): """ 將一維索引高效轉(zhuǎn)換為三維 (x, y, z) 坐標(biāo)。 參數(shù): i (int): 一維索引。 width (int): 網(wǎng)格的寬度。 height (int): 網(wǎng)格的高度。 返回: tuple: 對應(yīng)的 (x, y, z) 坐標(biāo)。 """ # 1. 計算 z 坐標(biāo)和當(dāng)前 z 層內(nèi)的剩余索引 # z = i // (width * height) # remainder = i % (width * height) z, remainder = divmod(i, width * height) # 2. 在當(dāng)前 z 層內(nèi),計算 y 坐標(biāo)和當(dāng)前行內(nèi)的剩余索引 # y = remainder // width # x = remainder % width y, x = divmod(remainder, width) return x, y, z
讓我們再次使用 4x4x4 的立方體,并使用 index_vec3 函數(shù)驗(yàn)證其輸出:
# 模擬迭代一個 4x4x4 的立方體 width = 4 height = 4 depth = 4 # 實(shí)際上不需要深度來計算,但它定義了總大小 total_elements = width * height * depth print("使用正確的 index_vec3 函數(shù),4x4x4 立方體的索引映射:") for i in range(total_elements): x, y, z = index_vec3(i, width, height) print(f"索引 {i:2d} -> ({x},{y},{z})")
部分輸出如下:
... 索引 12 -> (0,3,0) 索引 13 -> (1,3,0) 索引 14 -> (2,3,0) 索引 15 -> (3,3,0) # 第一層 (z=0) 結(jié)束 索引 16 -> (0,0,1) # 第二層 (z=1) 開始,y 歸零 索引 17 -> (1,0,1) 索引 18 -> (2,0,1) 索引 19 -> (3,0,1) 索引 20 -> (0,1,1) 索引 21 -> (1,1,1) ... 索引 31 -> (3,3,1) # 第二層 (z=1) 結(jié)束 索引 32 -> (0,0,2) # 第三層 (z=2) 開始,y 歸零 ...
可以看到,當(dāng) z 坐標(biāo)增加時,y 坐標(biāo)正確地從0開始計數(shù),這符合我們的預(yù)期。
通過掌握這種一維索引到多維坐標(biāo)的映射技術(shù),開發(fā)者可以構(gòu)建出更高效、更節(jié)省資源的計算系統(tǒng),這在游戲開發(fā)、科學(xué)模擬和高性能圖形渲染等領(lǐng)域具有重要意義。
以上就是將一維數(shù)組索引高效轉(zhuǎn)換為三維坐標(biāo)的教程的詳細(xì)內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!
每個人都需要一臺速度更快、更穩(wěn)定的 PC。隨著時間的推移,垃圾文件、舊注冊表數(shù)據(jù)和不必要的后臺進(jìn)程會占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號