貼圖圖集


到目前為止,已經有過幾次在立方體貼上貼圖的示範了,基本上就是在立方體六面貼上相同的貼圖,在立方體各面貼上不同的貼圖等,貼的方式很隨意,貼圖來源基本上就是個別的圖檔。

然而,若是要在立方體貼圖,通常不會採用個別的圖檔,特別是在 Web 上,多個圖檔代表著多次的 HTTP 連線下載,由於網路的不確定性,這會增加下載的時間。

因為貼圖是根據貼圖座標,決定要將哪些部份繪製出來,因此,可以將需要的貼圖畫在同一張圖上,這樣的圖稱為貼圖圖集(Texture atlas),然後使用貼圖座標決定取用哪個貼圖,這個技巧在 2D 繪圖中也經常使用,在〈畫框檔案管理〉中也談過。

如果要為立方體六面貼上不同的貼圖,也可以採用相同的技巧,這不過就是如何切圖的問題,只不過到目前為止,立方體頂點訂的很隨意,貼圖座標也訂得很隨意,反正如果不在意貼出來的圖有沒有方向性,這樣就夠了。

然而,如果你想在立方體貼上世界地圖呢?

貼圖圖集

這可就不能隨意訂了,因為六個面必須正確接合,最好有一定的規則,通常,像這種立方體貼圖,會採用這樣的貼圖圖集,其中我加上了六個面的標示:

貼圖圖集

這張圖取自於 Humus 的 Earth,這個網站上提供了許多貼圖,多數基於 CC Attribution 3.0 Unported 授權。

在指定貼圖座標與頂點的對應時就必須留意是否正確了,例如:

貼圖圖集

由於貼圖圖集是直接展開在我們的面前,建議貼圖座標固定一個方向的取法,例如,我都是左上、左下、右下、右上來取貼圖座標:

[
    // 前
    1/2, 1/3,
    1/2, 2/3,
    3/4, 2/3,
    3/4, 1/3,
    // 後
    0, 1/3,
    0, 2/3,
    1/4, 2/3,
    1/4, 1/3,
    // 上
    1/4, 0,
    1/4, 1/3,
    1/2, 1/3,
    1/2, 0,
    // 下
    1/4, 2/3,
    1/4, 1,
    1/2, 1,
    1/2, 2/3,
    // 左
    1/4, 1/3,
    1/4, 2/3,
    1/2, 2/3,
    1/2, 1/3,
    // 右
    3/4, 1/3,
    3/4, 2/3,
    1, 2/3,
    1, 1/3
]

然後,頂點座標小心地對應至貼圖座標:

const n = 0.2;
const verteices = [
    // 前
    -n, n,  -n,
    -n, -n,  -n,
    n,  -n, -n,
    n,  n, -n,
    // 後
    n, n, n,
    n, -n, n,
    -n, -n, n,
    -n, n, n,
    // 上
    n, n, n,
    -n, n, n,
    -n, n,  -n,
    n, n, -n,
    // 下
    -n, -n, n,
    n, -n, n,
    n, -n, -n,
    -n, -n, -n,
    // 左
    -n, n, n,
    -n, -n, n,
    -n, -n, -n,
    -n, n, -n,
    // 右
    n, n, -n,
    n, -n, -n,
    n, -n, n,
    n, n, n
];

掌握住這種對應方式之後,剩下的就是索引陣列正確設定等工作了,當然,這樣的貼圖圖集在高度上,顯然不會是 2 的次方,如果使用 WebGL 1,記得要如下設定:

// 寬或高不是 2 次方,只能用 gl.CLAMP_TO_EDGE
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// 因為無法產生 MINMAP,必須是 gl.LINEAR 或 gl.NEAREST
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

你可以按一下範例網頁看看效果,不過,這邊只是為了特意示範,如何使用貼圖圖集,才用這個方式為立方體貼圖的,在 WebGL 中,使用立方體映射(Cube mapping)來進行這項任務,會更加簡單與方便。