Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 4 of 4

Thread: How to pass Array to Shader like Vertices?

  1. #1
    Junior Member Newbie
    Join Date
    Feb 2014
    Posts
    13

    How to pass Array to Shader like Vertices?

    Following a tutorial on importing animations using ASSIMP I've come across a problem in that the developers code was intended for a mesh where every vertex was affected by no more than 4 bones, which he thusly passed as two vec4's in the layout section.

    Here is presumably his code:
    Code :
       	glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[BONE_VB]);
    	glBufferData(GL_ARRAY_BUFFER, sizeof(Bones[0]) * Bones.size(), &Bones[0], GL_STATIC_DRAW);
        glEnableVertexAttribArray(BONE_ID_LOCATION);
     
        glVertexAttribIPointer(BONE_ID_LOCATION, 4, GL_INT, sizeof(VertexBoneData), (const GLvoid*)0);
        glEnableVertexAttribArray(BONE_WEIGHT_LOCATION);    
        glVertexAttribPointer(BONE_WEIGHT_LOCATION, 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData), (const GLvoid*)16);

    VertexBoneData is a struct:

    Code :
        struct VertexBoneData
        {        
            uint IDs[NUM_BONES_PER_VEREX];
            float Weights[NUM_BONES_PER_VEREX]; }

    and Bones is a vector of VertexBoneData, his shader looks like:

    Code :
    #version 330                                                                        
     
    layout (location = 0) in vec3 Position;                                             
    layout (location = 1) in vec2 TexCoord;                                             
    layout (location = 2) in vec3 Normal;                                               
    layout (location = 3) in ivec4 BoneIDs;
    layout (location = 4) in vec4 Weights;
     
    out vec2 TexCoord0;
    out vec3 Normal0;                                                                   
    out vec3 WorldPos0;                                                                 
     
    const int MAX_BONES = 100;
     
    uniform mat4 gWVP;
    uniform mat4 gWorld;
    uniform mat4 gBones[MAX_BONES];
     
    void main()
    {       
    	mat4 BoneTransform = gBones[BoneIDs[0]] * Weights[0];
    	BoneTransform     += gBones[BoneIDs[1]] * Weights[1];
    	BoneTransform     += gBones[BoneIDs[2]] * Weights[2];
    	BoneTransform     += gBones[BoneIDs[3]] * Weights[3];
     
        vec4 PosL    = BoneTransform * vec4(Position, 1.0);
        gl_Position  = gWVP * PosL;
        TexCoord0    = TexCoord;
        vec4 NormalL = BoneTransform * vec4(Normal, 0.0);
        Normal0      = (gWorld * NormalL).xyz;
        WorldPos0    = (gWorld * PosL).xyz;                                
    }

    I believe my mesh ends up with 6 bones but I had 12 as the max size to be safe.

    My idea to get around this is to pass two matrices and have the shader look like this:

    Code :
    #version 330                                                                        
     
    layout (location = 0) in vec3 Position;                                             
    layout (location = 1) in vec2 TexCoord;                                             
    layout (location = 2) in vec3 Normal;                                               
    layout (location = 3) in mat4 BoneIDs;
    layout (location = 4) in mat4 Weights;
     
    out vec2 TexCoord0;
    out vec3 Normal0;                                                                   
    out vec3 WorldPos0;                                                                 
     
    const int MAX_BONES = 100;
     
    uniform mat4 gWVP;
    uniform mat4 gWorld;
    uniform mat4 gBones[MAX_BONES];
     
    void main()
    {       
     
    	ivec4 BoneIDvec1 = ivec4(BoneIDs[0][0], BoneIDs[0][1], BoneIDs[0][2], BoneIDs[0][3]);
    	ivec4 BoneIDvec2 = ivec4(BoneIDs[0][0], BoneIDs[0][1], BoneIDs[0][2], BoneIDs[0][3]);
    	ivec4 BoneIDvec3 = ivec4(BoneIDs[0][0], BoneIDs[0][1], BoneIDs[0][2], BoneIDs[0][3]);
    	ivec4 BoneIDvec4 = ivec4(BoneIDs[0][0], BoneIDs[0][1], BoneIDs[0][2], BoneIDs[0][3]);
        mat4 BoneTransform = gBones[BoneIDvec1[0]] * Weights[0][0];
       BoneTransform     += gBones[BoneIDvec1[1]] * Weights[0][1];
        BoneTransform     += gBones[BoneIDvec1[2]] * Weights[0][2];
      BoneTransform     += gBones[BoneIDvec1[3]] * Weights[0][3];
    	BoneTransform     += gBones[BoneIDvec2[0]] * Weights[1][0];
    	BoneTransform     += gBones[BoneIDvec2[1]] * Weights[1][1];
    	BoneTransform     += gBones[BoneIDvec2[2]] * Weights[1][2];
    	BoneTransform     += gBones[BoneIDvec2[3]] * Weights[1][3];
    	BoneTransform     += gBones[BoneIDvec3[0]] * Weights[2][0];
    	BoneTransform     += gBones[BoneIDvec3[1]] * Weights[2][1];
    	BoneTransform     += gBones[BoneIDvec3[2]] * Weights[2][2];
    	BoneTransform     += gBones[BoneIDvec3[3]] * Weights[2][3];
     
        vec4 PosL    = BoneTransform * vec4(Position, 1.0);
        gl_Position  = gWVP * PosL;
        TexCoord0    = TexCoord;
        vec4 NormalL = BoneTransform * vec4(Normal, 0.0);
        Normal0      = (gWorld * NormalL).xyz;
        WorldPos0    = (gWorld * PosL).xyz;                                
    }

    Would this work in theory? It seems like a lot of work, as I would need I think, to enter in all of his vertex data into two 4v4 matrices, and even then that's a maximum of 16 slots.

    Thoughts?

  2. #2
    Advanced Member Frequent Contributor
    Join Date
    Apr 2010
    Posts
    788
    You could use Uniform Buffer Objects (available from GL 3.1, may have smallish size limit) or Shader Storage Buffer Objects (available from 4.3, much larger) and use the vertex index to look up the bone/weight data.
    Other than that using extra vertex attributes should work as well. I think you have to assign location 7 to the Weights mat4, because locations 4,5,6,7 are taken up by the BoneIDs mat4.

  3. #3
    Junior Member Newbie
    Join Date
    Feb 2014
    Posts
    13
    Wait what, a mat4 uses up 4 spots?

    Otherwise though, there's a different between passing a uniform and passing whats in the layout section right performance wise?

  4. #4
    Advanced Member Frequent Contributor
    Join Date
    Apr 2010
    Posts
    788
    Wait what, a mat4 uses up 4 spots?
    That's what I remember, I might confuse it with something else, but I thought matrix vertex attributes are just syntactic sugar for passing the columns as separate attributes, so they consume the same amount of layout slots.

    Sorry, no idea about the performance trade-offs.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •