0
votes

I store an object's material in a array texture 2D comprised of the diffuse, bump, specular, etc. The handle to this texture array is then stored per vertex, along side the vertex, uv, normal arrays in a VAO, instead of using UBO's or SSBO's to achieve the same purpose.

My goal is to compress an entire model into a single vertex array object, since a model may have many meshes and each mesh may have its own texture. This way with the texture handle stored per vertex, I could just render the entire model in 1 draw call.

The problem is that all object's render black, suggesting to me that the sampler isn't working or somehow the handle isn't getting transferred all the way through. The shader program compiles successfully, and the geometry is rendering correctly (that is, I can substitute the final diffuse color with a fixed color and see the scene).


Texture Creation:

void TextureManager::FinishWorkOrders()
{
    for ( ... ) {
        Material_WorkOrder *material = Mat_Work_Orders[x];   
        glGenTextures(1, material->gl_array_ID);
        glBindTexture(GL_TEXTURE_2D_ARRAY, *material->gl_array_ID);
        glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, material->size.x, material->size.y, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, material->textureData);
        glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_GENERATE_MIPMAP, GL_TRUE);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);

        // Material handle is of type GLuint64
        *material->handle = glGetTextureHandleARB(*material->gl_array_ID);
        glMakeTextureHandleResidentARB(*material->handle);
    }
}

VAO generation:

GLuint ModelManager::genVAO(const vector<vec3> &vs, const vector<vec2> &uv, const vector<vec3> &nm, const vector<vec3> &tg, const vector<vec3> &bt, const vector<GLuint64*> &ts)
{
    AttribBuffers b;
    GLuint vao = 0;
    size_t arraySize = vs.size();
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glGenBuffers(MAX_BUFFERS, b.buffers);

    // Vertex array
    glBindBuffer(GL_ARRAY_BUFFER, b.buffers[0]);
    glBufferData(GL_ARRAY_BUFFER, arraySize * sizeof(vec3), &vs[0][0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    ...

    // Texture Handle array
    glBindBuffer(GL_ARRAY_BUFFER, b.buffers[5]);
    glBufferData(GL_ARRAY_BUFFER, arraySize * sizeof(GLuint64), &ts[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(5);
    glVertexAttribLPointer(5, 1, GL_UNSIGNED_INT64_ARB, 0, 0);

    glBindVertexArray(0);
    return vao;
}

Shader Usage:

Vertex:

#version 450
#extension GL_ARB_bindless_texture : require
#extension GL_ARB_gpu_shader5 : require 
#extension GL_ARB_gpu_shader_int64 : require

layout (location = 0) in vec3 vertex;

...

layout (location = 5) in uint64_t texHandle;

flat out uint64_t TextureHandle;

void main(void)
{
    TextureHandle           = texHandle;

    ...

    gl_Position             = worldMVP * v;         
}

Fragment:

#version 450
#extension GL_ARB_bindless_texture : require
#extension GL_ARB_gpu_shader5 : require 
#extension GL_ARB_gpu_shader_int64 : require

flat in uint64_t TextureHandle;

layout (location = 0) out vec4 DiffuseOut; 

void main()                                 
{                           
    sampler2DArray MaterialMap = sampler2DArray(TextureHandle);

    ... 

    DiffuseOut = texture(MaterialMap, vec3(TexCoord0, 0));
}
1
"This way with the texture handle stored per vertex, I could just render the entire model in 1 draw call." There are better ways to do that which don't require every vertex to have a 8 extra bytes in it. Especially since most of those bytes will be the same. It's far better to pass a 1-byte index which you look up in the 2D array texture. That's why it's an array texture, after all. - Nicol Bolas
In any case, the easiest way to find out what is broken is to provide the handle via a uniform rather than a VS input, then see if that works. If not, then you can better localize the problem. - Nicol Bolas
Yeah I just tried that and similar methods. The problem appears to be that I'm specifying GLuint pointers or something. But in any case I will just instead put the handles in an ssbo and specify array positions via vertex attributes - Yattabyte

1 Answers

0
votes

The issue is that glBufferData can't accept a vector of pointers.

I set up my data this way so that the last vertex attribute array was an array of Gluint64* handles for 2 reasons: 1) so that the appropriate texture per triangle would just stream from the vertex shader to the fragment shader, 2) so that I could create the array ahead of time and wait for the texture to be created and update the array automatically by just updating the underlying pointers separately

This can work, but the vector needs to be changed from type GLuint* to GLuint (drop the pointer).