簡體   English   中英

在 OpenGL 中使用紋理圖集作為紋理數組

[英]Using Texture Atlas as Texture Array in OpenGL

我現在正在構建一個體素游戲。 一開始,我使用存儲所有體素紋理的紋理圖集,它工作正常。 之后,我決定在我的游戲中使用 Greedy Meshing,因此紋理圖集不再有用。 我讀了一些文章,說應該改用紋理數組。 然后我嘗試閱讀並使用紋理數組技術進行紋理化。 然而,我得到的結果在我的游戲中全黑。 那么我錯過了什么?

這是我的紋理圖集 (600 x 600)

我的紋理圖集

這是我的 Texture2DArray,我使用這個類來讀取和保存一個紋理數組

Texture2DArray::Texture2DArray() : Internal_Format(GL_RGBA8), Image_Format(GL_RGBA), Wrap_S(GL_REPEAT), Wrap_T(GL_REPEAT), Wrap_R(GL_REPEAT), Filter_Min(GL_NEAREST), Filter_Max(GL_NEAREST), Width(0), Height(0)
{
   glGenTextures(1, &this->ID);
}

void Texture2DArray::Generate(GLuint width, GLuint height, unsigned char* data)
{
   this->Width = width;
   this->Height = height;

   glBindTexture(GL_TEXTURE_2D_ARRAY, this->ID);

   // I cannot decide what the texture array layer (depth) should be (I put here is 1 for layer number)
   //Can anyone explain to me how to decide the texture layer here? 
   glTexImage3D(GL_TEXTURE_2D_ARRAY, 1, this->Internal_Format, this->Width, this->Height, 0, 1 , this->Image_Format, GL_UNSIGNED_BYTE, data);

   glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, this->Wrap_S);
   glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, this->Wrap_T);
   glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, this->Wrap_R);

   glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, this->Filter_Min);
   glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, this->Filter_Max);

   //unbind this texture for another creating texture
   glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
}

void Texture2DArray::Bind() const
{
   glBindTexture(GL_TEXTURE_2D_ARRAY, this->ID);
}

這是我的片段着色器

#version 330 core

uniform sampler2DArray ourTexture;

in vec2 texCoord;

out vec4 FragColor;

void main(){
   // 1 (the layer number) just for testing
   FragColor = texture(ourTexture,vec3(texCoord, 1));
}

這是我的頂點着色器

#version 330 core

layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inTexCoord;

out vec2 texCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main(){
    gl_Position =  projection * view * vec4(inPos,1.0f);
    texCoord = inTexCoord;
}  

這是我的渲染結果

渲染結果

編輯 1:

我發現紋理圖集不適用於紋理數組,因為它是一個網格,所以 OpenGl 無法決定它應該從哪里開始。 所以我創建了一個垂直紋理 (18 x 72) 並再試一次,但它仍然到處都是黑色。

我的垂直紋理圖集

在使用它之前,我已經檢查了綁定紋理。

當指定了 3 維紋理圖像時,深度必須是必須存儲在數組中的圖像數量(例如imageCount )。 width 和 height 參數表示 1 個 tile(例如tileWtileH )的寬度和高度。 圖層應為 0,邊框參數必須為 0。請參閱glTexImage3D glTexImage3D為紋理圖像創建數據存儲。 保留紋理所需的內存 (GPU)。 可以傳遞指向圖像數據的指針,但這不是必需的。

如果所有的tile都存儲在一個垂直的圖集中,那么可以直接設置圖像數據:

glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, this->Internal_Format, 
             tileW, tileH, imageCount, 0,
             this->Image_Format, GL_UNSIGNED_BYTE, data);

如果圖塊在 16x16 的圖集中,則圖塊必須從紋理圖集中提取並設置紋理數組中的每個子圖像。 data[i]是一個瓦片的成像數據)。 創建紋理圖像:

glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, this->Internal_Format, 
             tileW, tileH, imageCount, 0,
             this->Image_Format, GL_UNSIGNED_BYTE, nullptr);

之后使用glTexSubImage3D將紋理數據放入紋理對象的數據存儲中。 glTexSubImage3D使用現有的數據存儲並復制數據。 例如:

for (int i = 0; i < imageCount; ++i)
{
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0,
        0, 0, i,
        tileW, tileH, 1,
        this->Image_Format, GL_UNSIGNED_BYTE, data[i]);
}

請注意,您必須從紋理圖集中提取圖塊並在紋理數組中設置每個子圖像。 data[i]是一個瓦片的成像數據)


提取瓦片並指定紋理圖像的算法可能如下所示

#include <algorithm>    // std::copy
#include <vector>       // std::vector
unsigned char* data = ...; // 16x16 texture atlas image data
int tileW = ...;           // number of pixels in a row of 1 tile
int tileH = ...;           // number of pixels in a column of 1 tile
int channels = 4;          // 4 for RGBA

int tilesX = 16;
int tilesY = 16;
int imageCount = tilesX * tilesY;

glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, this->Internal_Format, 
             tileW, tileH, imageCount, 0,
             this->Image_Format, GL_UNSIGNED_BYTE, nullptr);

std::vector<unsigned char> tile(tileW * tileH * channels);
int tileSizeX = tileW * channels;
int rowLen    = tilesX * tileSizeX;

for (int iy = 0; iy < tilesY; ++ iy)
{
    for (int ix = 0; ix < tilesX; ++ ix)
    {
        unsigned char *ptr = data + iy*rowLen + ix*tileSizeX;
        for (int row = 0; row < tileH; ++ row)
            std::copy(ptr + row*rowLen, ptr + row*rowLen + tileSizeX,
                      tile.begin() + row*tileSizeX);


        int i = iy * tilesX + ix;
        glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0,
            0, 0, i,
            tileW, tileH, 1,
            this->Image_Format, GL_UNSIGNED_BYTE, tile.data());
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM