-1

I'm drawing sprites that are all in a buffer using glDrawElements. To tell sprites what texture to be in the fragment shader I have uniform sampler2D textures[32]; each vertex has an index, which is passed to the fragment shader from the vertex shader:

color = texture(textures[index], fs_in.uv);

when I try draw my sprites with more than 1 texture active it gets the wrong textures in the top right corner

http://puu.sh/lyr5j/d8c2cf6c8f.png

I have no clue why this is happening have tried texture parameters

I cant seem to find anyone who has had a similar problem.

This is my renderer's init function (I am purposly passing the texid as float since I have heard ints don't work well (also tried))

glGenBuffers(1, &m_VDBO); glGenVertexArrays(1, &m_VAO);

        glBindVertexArray(m_VAO);
        glBindBuffer(GL_ARRAY_BUFFER, m_VDBO);
        glBufferData(GL_ARRAY_BUFFER, RENDERER_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW);

        glEnableVertexAttribArray(SHADER_VERTEX_INDEX);
        glEnableVertexAttribArray(SHADER_UV_INDEX);
        glEnableVertexAttribArray(SHADER_COLOR_INDEX);
        glEnableVertexAttribArray(SHADER_TEXID_INDEX);

        glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::vertex));
        glVertexAttribPointer(SHADER_UV_INDEX, 2, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::uv));
        glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_UNSIGNED_BYTE, GL_TRUE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::color));
        glVertexAttribPointer(SHADER_TEXID_INDEX, 1, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *)offsetof(VertexData, VertexData::texID));

        glBindBuffer(GL_ARRAY_BUFFER, 0);

        const GLushort modelindices[] = { 0, 1, 2, 2, 3, 0 };
        GLuint indices[RENDERER_INDICES_SIZE];

        for (int i = 0; i < RENDERER_INDICES_SIZE; i += 6)
        {
            for (int o = 0; o < 6; o++)
            {
                indices[i + o] = modelindices[o] + (i / 6 * 4);
            }
        }

        glGenBuffers(1, &m_IBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, RENDERER_INDICES_SIZE * sizeof(GLuint), indices, GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        glBindVertexArray(0);

the flush function

            glBindVertexArray(m_VAO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);

        for (int i = 0; i < m_TextureSlots.size(); i++)
        {
            glActiveTexture(GL_TEXTURE0 + i);
            glBindTexture(GL_TEXTURE_2D, m_TextureSlots[i]);
        }

        glDrawElements(GL_TRIANGLES, m_IndexCount, GL_UNSIGNED_INT, 0);

        m_TextureSlots.clear();
        m_IndexCount = 0;

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
user1952500
  • 6,611
  • 3
  • 24
  • 37
arkeyon
  • 1
  • 1
  • 1
    Your code is undefined behavior. Arrays of samplers are special in OpenGL. You cannot use a non-uniform expression like something derived from an vertex attribute as an index. I've explained that in more detail in [this answer](http://stackoverflow.com/questions/27972661/glsl-data-distortion/27973129#27973129). – derhass Nov 25 '15 at 19:58

1 Answers1

0

It is hard for me to see where your problem is coming from, the only thing I can suggest is taking a look at an Image2d class object constructor that I have. Now, my source depends on outside classes such as a ShaderManager class that relies heavily on template types and a Batch class and a BatchManager class to send over the vertices to the video card. Also this Image2d is an inherited object. However, this may serve as some help to you in tracking down your own problem. There are two different constructors for different versions of the implementation depending on which version of OpenGL and GLSL is being used. If I remember correctly version 2 uses the BatchManager to send the vertices to the video card where version 1 doesn't which can be seen within the render() method.

Image2d v1.0

// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( glm::uvec2(), strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {

    if ( fWidth <= 0 || fHeight <= 0 ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Invalid image size (" << fWidth << "," << fHeight << ") must be more then 0 in each dimension.";
        throw ExceptionHandler( strStream );
    }

    // Save TextureId
    TextureFileReader textureFileReader( strTextureFilename );
    m_textureInfo = textureFileReader.getOrCreateTextureInfo( filterQuality, generateMipMap, false );

    // Define Texture Co-Ordinates
    std::vector<float> vTextureCoordinates;
    vTextureCoordinates.push_back( 0.0f );
    vTextureCoordinates.push_back( 1.0f );

    vTextureCoordinates.push_back( 0 );
    vTextureCoordinates.push_back( 0 );

    vTextureCoordinates.push_back( 1.0f );
    vTextureCoordinates.push_back( 1.0f );

    vTextureCoordinates.push_back( 1.0f );
    vTextureCoordinates.push_back( 0 );

    // Define Vertex Positions (x,y,z)
    std::vector<float> vVertexPositions;
    vVertexPositions.push_back( 0 );
    vVertexPositions.push_back( fHeight );
    vVertexPositions.push_back( 0 );

    vVertexPositions.push_back( 0 );
    vVertexPositions.push_back( 0 );
    vVertexPositions.push_back( 0 );

    vVertexPositions.push_back( fWidth );
    vVertexPositions.push_back( fHeight );
    vVertexPositions.push_back( 0 );

    vVertexPositions.push_back( fWidth );
    vVertexPositions.push_back( 0 );
    vVertexPositions.push_back( 0 );

    // Define 2 Triangle Faces
    std::vector<unsigned char> vIndices;
    vIndices.push_back( 0 );
    vIndices.push_back( 1 );
    vIndices.push_back( 2 );
    vIndices.push_back( 3 );

    // Create Vertex Array Object
    glGenVertexArrays( 1, &m_vao );
    glBindVertexArray( m_vao ); // Start Array

    m_pShaderManager->setAttribute( A_COLOR, COLOR_WHITE );

    // Create Position Buffer And Store On Video Card
    glGenBuffers( 1, & m_vboPosition );
    glBindBuffer( GL_ARRAY_BUFFER, m_vboPosition );
    glBufferData( GL_ARRAY_BUFFER, vVertexPositions.size() * sizeof( vVertexPositions[0] ), &vVertexPositions[0], GL_STATIC_DRAW );
    m_pShaderManager->enableAttribute( A_POSITION );

    // Create Texture Coordinate Buffer
    glGenBuffers( 1, &m_vboTexture );
    glBindBuffer( GL_ARRAY_BUFFER, m_vboTexture );
    glBufferData( GL_ARRAY_BUFFER, vTextureCoordinates.size() * sizeof( vTextureCoordinates[0] ), &vTextureCoordinates[0], GL_STATIC_DRAW );
    m_pShaderManager->enableAttribute( A_TEXTURE_COORD0 );

    // Create Index Buffer
    glGenBuffers( 1, &m_vboIndices );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_vboIndices );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, vIndices.size() * sizeof( vIndices[0] ), &vIndices[0], GL_STATIC_DRAW );

    glBindVertexArray( 0 ); // Stop Array

    // Disable Attribute Pointers
    m_pShaderManager->disableAttribute( A_POSITION );
    m_pShaderManager->disableAttribute( A_TEXTURE_COORD0 );

    // THIS MUST BE AFTER Vertex Array Buffer Is Unbound!
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); // Stop Buffer Index
    glBindBuffer( GL_ARRAY_BUFFER, 0 ); // Stop Buffer

    // We have a Valid Image2d Save Filename
    m_strFilename = strTextureFilename;

} // Image2D - v1.0

Image2D - v2.0

// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( size, strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {

    m_version = 2;

    TextureFileReader textureFileReader( strTextureFilename );
    m_textureInfo = textureFileReader.getOrCreateTextureInfo( TextureInfo::FILTER_NONE, false, false );
    m_config.uTextureId = m_textureInfo.uTextureId;

    if ( 0 == m_textureInfo.size.x || 0 == m_textureInfo.size.y ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << "size of " << strTextureFilename << " is invalid " << m_textureInfo.size;
        throw ExceptionHandler( strStream );
    }

    // Verify Image Fits Inside Texture
    if ( m_textureInfo.size.x < size.x + origin.x || m_textureInfo.size.y < size.y + origin.y ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " " << strTextureFilename << " size is " << m_textureInfo.size
            << " which is too small for an image that is " << size
            << " pixels in size, with an origin point set at " << origin ;
        throw ExceptionHandler( strStream );
    }

    glm::vec2 textureCoordScaleFactor( 1.0f / static_cast<float>( m_textureInfo.size.x ),
        1.0f / static_cast<float>( m_textureInfo.size.y ) );

    glm::vec2 textureCoordBottomLeft = glm::vec2( textureCoordScaleFactor.x * origin.x,
                                                  textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y - size.y ) );
    glm::vec2 textureCoordTopRight   = glm::vec2( textureCoordScaleFactor.x * ( origin.x + size.x ),
                                                  textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y ) );

    // Set Colors And Texture Coordinates (Position Will Be Updated In Render Function)
    m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordBottomLeft.x, textureCoordTopRight.y ) ) );
    m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordBottomLeft.x, textureCoordBottomLeft.y ) ) );
    m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordTopRight.x,   textureCoordTopRight.y ) ) );
    m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordTopRight.x,   textureCoordBottomLeft.y ) ) );

} // Image2d - v2.0

and here is my render() method

// ----------------------------------------------------------------------------
// render()
void Image2d::render() {
    if ( 1 == m_version ) {
        m_pShaderManager->setTexture( 0, U_TEXTURE0_SAMPLER_2D, m_textureInfo.uTextureId );

        glBindVertexArray( m_vao );
        glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr );
        glBindVertexArray( 0 );
    } else {
        // Version 2.0
        // Update Vertices
        if ( m_transformMatrix.updateTranslation || m_transformMatrix.updateScale || m_transformMatrix.updateRotation ) {
            m_transformMatrix.updateTranslation = m_transformMatrix.updateScale = m_transformMatrix.updateRotation = false;

            // Order Of Operations Matter Here!
            glm::mat4 matrix; // Identity

            if ( m_transformMatrix.hasTranslation ) {
                matrix[3][0] = m_transformMatrix.translation.x;
                matrix[3][1] = m_transformMatrix.translation.y;
            }

            if ( m_transformMatrix.hasRotation ) {
                matrix = glm::rotate( matrix, m_transformMatrix.fRotationAngleRadians, glm::vec3( 0.0f, 0.0f, -1.0f ) );
            }

            if ( m_transformMatrix.hasScale ) {
                matrix = matrix * glm::mat4( m_transformMatrix.scale.x,                       0.0f, 0.0f, 0.0f,
                                                                   0.0f, m_transformMatrix.scale.y, 0.0f, 0.0f,
                                                                   0.0f,                      0.0f, 1.0f, 0.0f,
                                                                   0.0f,                      0.0f, 0.0f, 1.0f );
            }

            // Center Offset
            if ( m_offsetPosition.x != 0 || m_offsetPosition.y != 0 ) {
                matrix = glm::translate( matrix, glm::vec3( -m_offsetPosition.x, -m_offsetPosition.y, 0.0f ) );
            }

            // Apply Transformation To All 4 Vertices
            m_vVertices[0].position = glm::vec2( matrix * glm::vec4(        0,        0, 0, 1.0f ) );
            m_vVertices[1].position = glm::vec2( matrix * glm::vec4(        0, m_size.y, 0, 1.0f ) );
            m_vVertices[2].position = glm::vec2( matrix * glm::vec4( m_size.x,        0, 0, 1.0f ) );
            m_vVertices[3].position = glm::vec2( matrix * glm::vec4( m_size.x, m_size.y, 0, 1.0f ) );
        }
        renderBatch();
    }
} // render

Make sure that the sizes you are specifying in your glBufferData(GL_ARRAY_BUFFER, RENDERER_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW); is accurate. Also make sure that you are stopping your your VertexArray at the appropriate time as well as disabling your Attribute Pointers. Everything that you bound must be unbound, and for some types Order does matter!

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59