OpenGL Texture Sampling not working

DanoThom Source

I'm using VC++10 + OpenGL + the Assimp Library to consume and then render some 3D models.

The code is rendering the positions correctly, but for some reason the textures are seriously bugged. My texcoords appear to be loading correctly as are the texture files themselves - however I can't help but feel that the issue must be located with the loaded textures themselves.

www.flickr.com/photos/[email protected]/8685913640/in/photostream { i seem to have a lack of rep to post inline images }

********** EDIT1 : ***********

So, I've been using the awesome GDebugger application to debug and interrogate the OpenGL pipeline in realtime. 2 things stand out really : 1. The biggy here is that the loaded texture is meant to look like this -> http://www.flickr.com/photos/[email protected]/8688860034/in/photostream but actually looks like this when loaded into OpenGL memory : http://www.flickr.com/photos/[email protected]/8688860042/in/photostream/ 2. Not sure if this is still applicable(as discussed in the comments), however the GL_TEXTURE_2D state variable is always FALSE throughout the game loop.

So I'm going to have to play with the texture loading code to see if I can get any traction there and post another update.

A few big relevant code chunks{sorry!} :

* Vertex Shader *

    #version 420

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 texCoord;

uniform mat4 cameraToClipMatrix;
uniform mat4 modelToCameraMatrix;

out vec2 oTexCoord;
out vec4 oNormal;

void main()
{
    oTexCoord = texCoord;
    vec4 cameraPos = modelToCameraMatrix * vec4(position,1.0);
    gl_Position = cameraToClipMatrix * cameraPos;

    oNormal = normalize(vec4(modelToCameraMatrix * vec4(normal,0.0)));

}

* Fragment Shader *

    #version 420

in vec4 Normal;
in vec2 TexCoord;

layout (location = 0) out vec4  FragColor;

uniform sampler2D gSampler;   

void main()
{
    FragColor = texture(gSampler, TexCoord);
    //FragColor = vec4(1.1, 0.0, 1.1, 1.0);
}

* GL Init etc *

    void GLSystem::init() {

    InitializeProgram();

    glClearColor(0.75f, 0.75f, 1.0f, 1.0f);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);
    glDepthFunc(GL_LEQUAL);
    glDepthRange(0.0f, 1.0f);
}

void GLSystem::InitializeProgram()
{
    std::vector<GLuint> shaderList;

    shaderList.push_back(LoadShader(GL_VERTEX_SHADER, "VertShader1.vert"));
    shaderList.push_back(LoadShader(GL_FRAGMENT_SHADER, "FragShader1.frag"));

    theProgram = CreateProgram(shaderList);

    modelToCameraMatrixUnif =       glGetUniformLocation(theProgram, "modelToCameraMatrix"); // view matrix
    cameraToClipMatrixUnif =        glGetUniformLocation(theProgram, "cameraToClipMatrix"); // projection matrix
    m_samplerUnif =                 glGetUniformLocation(theProgram, "gSampler"); // grab the gSampler uniform location reference in the fragment shader

    float fzNear = 1.0f; float fzFar = 45.0f;

    cameraToClipMatrix[0].x = fFrustumScale;
    cameraToClipMatrix[1].y = fFrustumScale;
    cameraToClipMatrix[2].z = (fzFar + fzNear) / (fzNear - fzFar);
    cameraToClipMatrix[2].w = -1.0f;
    cameraToClipMatrix[3].z = (2 * fzFar * fzNear) / (fzNear - fzFar);

    glUseProgram(theProgram);
    glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(cameraToClipMatrix));
    glUseProgram(0);
}

* Texture Loading *

    bool CTexture::Load()  {
    m_texObj = 0;  // init to zero
    std::auto_ptr<glimg::ImageSet> pImgSet;
    try {
        pImgSet.reset( glimg::loaders::stb::LoadFromFile(m_filename) );
        m_texObj = glimg::CreateTexture( &(*pImgSet), 0);               // generates a texture and returns the related texture id

        //glimg::SingleImage image = pImgSet->GetImage(0, 0, 0);
        //glimg::Dimensions dims = image.GetDimensions();
        //GLuint targetTexType = glimg::GetTextureType( &(*pImgSet), 0); // not using this yet - but potentially might need to base this objects targetType on this interpreted value.
        //glimg::OpenGLPixelTransferParams params = GetUploadFormatType(image.GetFormat(), 0);
        //glPixelStorei(GL_UNPACK_ALIGNMENT, image.GetFormat().LineAlign());

        //glGenTextures(1, &m_texObj);
        //glActiveTexture(GL_TEXTURE0);
        //glBindTexture(GL_TEXTURE_2D, m_texObj);
        //glTexImage2D(m_targetType, 0, glimg::GetInternalFormat(image.GetFormat(), 0), dims.width, dims.height, 0, params.format, params.type, image.GetImageData());
        //glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, dims.width, dims.height, 0, GL_RGB, GL_UNSIGNED_BYTE, image.GetImageData() );

        /*glTexParameterf(m_targetType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(m_targetType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(m_targetType, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameterf(m_targetType, GL_TEXTURE_WRAP_T, GL_REPEAT);*/
    }
    catch(glimg::loaders::stb::StbLoaderException &e) {
        std::cout << "Warning : " << e.what() << " || .Image file loading failed for file : '" << m_filename << std::endl;
        return false;
    }

    glBindTexture(m_targetType, 0);  // Bind to default texture

    return true;
}

* Mesh Loading *

    #include "MeshModel.h"
// ----------------------------------------------------------------------------------------
#include "Texture.h"
#include "GLSystem.h"
#include "Game.h"
// ----------------------------------------------------------------------------------------
#include <assert.h>
// ----------------------------------------------------------------------------------------

MeshItem::MeshItem() {
}

MeshItem::MeshItem(MeshModel& p_meshModel) {
    m_pmeshModel = &p_meshModel;
    p_delete_object_data = true;
    VBO = INVALID_OGL_VALUE;
    IBO = INVALID_OGL_VALUE;
    NBO = INVALID_OGL_VALUE;
    TBO = INVALID_OGL_VALUE;
    NumVertices = 0;
    NumFaces = 0;
    NumIndices  = 0;
    MaterialIndex = INVALID_MATERIAL;
};

MeshItem::~MeshItem() {
    if (VBO != INVALID_OGL_VALUE) {
        glDeleteBuffers(1, &VBO);
    }
    if (IBO != INVALID_OGL_VALUE) {
        glDeleteBuffers(1, &IBO);
    }
    if (NBO != INVALID_OGL_VALUE) {
        glDeleteBuffers(1, &NBO);
    }
    if (TBO != INVALID_OGL_VALUE) {
        glDeleteBuffers(1, &TBO);
    }
}

void MeshItem::BuildVBO() {
    glGenVertexArrays(1, &VAO); /* Generate a vertex array object - container for all vertex attribute arrays */
    glBindVertexArray(VAO); /* Bind this VAO as the current Vertex Attribute Array container [ Holds the state for all attributes i.e. not the Vertex and Index data ] */

    // Positions
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * NumVertices * 3, &Positions[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // Positions

    // Indices
    glGenBuffers(1, &IBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * NumFaces * 3, &Indices[0], GL_STATIC_DRAW);

    // Normals
    glGenBuffers(1, &NBO);
    glBindBuffer(GL_ARRAY_BUFFER, NBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * NumVertices * 3, &Normals[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); // Normals

    // TexCoords
    glGenBuffers(1, &TBO);
    glBindBuffer(GL_ARRAY_BUFFER, TBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * NumVertices * 2, &TexCoords[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0); // TexCoords

    glBindVertexArray(0);                           // Unbind the VAO
    glBindBuffer(GL_ARRAY_BUFFER,0);                // Unbind the vertices array buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);       // Unbind the indices array buffer


    // Our copy of the data is no longer necessary, it is safe in the graphics card memory
    if(p_delete_object_data) {
        Positions.erase( Positions.begin(), Positions.end() );
        Indices.erase( Indices.begin(), Indices.end() );
        Normals.erase( Normals.begin(), Normals.end() );
        TexCoords.erase( TexCoords.begin(), TexCoords.end() );
    }
}

// ********************* MESHMODEL *********************

MeshModel::MeshModel(GLSystem& p_gls) 
    : m_pgls(&p_gls)
{
    m_texUnit = 0;
    m_samplerObj = 0;
}

MeshModel::~MeshModel() {
    Clear();
}

GLSystem& MeshModel::getGLSystem() {
    return *m_pgls;
}

void MeshModel::Clear() {
    //for (unsigned int i = 0 ; i < m_textures.size() ; i++) {
    //    m_textures[i]);
    //}
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
}

bool MeshModel::LoadMesh(const std::string& p_filename) {
    Clear(); // Release the previously loaded mesh (if it exists)

    bool Ret = false;
    Assimp::Importer Importer;
    const aiScene* pScene = Importer.ReadFile(p_filename.c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals /* | aiProcess_FlipWindingOrder*/ /* | aiProcess_FlipUVs*/ | aiProcess_ValidateDataStructure);
    //const aiScene* pScene = aiImportFile(p_filename.c_str(), aiProcessPreset_TargetRealtime_MaxQuality);

    if (pScene) {
        printf("3D Object File '%s' loaded successfully.\n", p_filename.c_str() );
        Ret = InitFromScene(pScene, p_filename);
    }
    else {
        printf("Error parsing '%s': '%s'.\n", p_filename.c_str(), Importer.GetErrorString());
    }

    return Ret;
}

bool MeshModel::InitFromScene(const aiScene* pScene, const std::string& p_filename) {  
    //m_meshItems.resize(pScene->mNumMeshes);
    m_textures.resize(pScene->mNumMaterials);

    InitMaterials(pScene, p_filename); // load materials/textures etc

    // Initialize the meshes in the scene one by one
    for (unsigned int i = 0 ; i < pScene->mNumMeshes ; i++) {
        const aiMesh* paiMesh = pScene->mMeshes[i];
        MeshItem mItem(*this);
        InitMesh(mItem, paiMesh);
        mItem.BuildVBO();
        m_meshItems.push_back(mItem);
    }

    return true;
}

void MeshModel::InitMesh(MeshItem& p_meshItem, const aiMesh* p_paiMesh) {
    p_meshItem.MaterialIndex = p_paiMesh->mMaterialIndex;

    // Indices
    p_meshItem.NumFaces = p_paiMesh->mNumFaces;
    p_meshItem.NumIndices = p_meshItem.NumFaces * 3;
    p_meshItem.Indices.resize(p_meshItem.NumIndices);

    for (unsigned int i = 0 ; i < p_paiMesh->mNumFaces ; ++i) {
        const aiFace& face = p_paiMesh->mFaces[i];
        assert(face.mNumIndices == 3);
        p_meshItem.Indices[i*3+0] = face.mIndices[0];
        p_meshItem.Indices[i*3+1] = face.mIndices[1];
        p_meshItem.Indices[i*3+2] = face.mIndices[2];
    }

    p_meshItem.NumVertices = p_paiMesh->mNumVertices;
    p_meshItem.Positions.resize(p_meshItem.NumVertices * 3);
    p_meshItem.Normals.resize(p_meshItem.NumVertices * 3);
    p_meshItem.TexCoords.resize(p_meshItem.NumVertices * 2);

    for (unsigned int i = 0 ; i < p_paiMesh->mNumVertices ; ++i) {
        // Positions
        if( p_paiMesh->HasPositions() ) {
            p_meshItem.Positions[i*3+0] = p_paiMesh->mVertices[i].x;
            p_meshItem.Positions[i*3+1] = p_paiMesh->mVertices[i].y;
            p_meshItem.Positions[i*3+2] = p_paiMesh->mVertices[i].z;
        }
        // Normals
        if( p_paiMesh->HasNormals() ) {
            p_meshItem.Normals[i*3+0] = p_paiMesh->mNormals[i].x;
            p_meshItem.Normals[i*3+1] = p_paiMesh->mNormals[i].y;
            p_meshItem.Normals[i*3+2] = p_paiMesh->mNormals[i].z;
        }
        // TexCoords
        if( p_paiMesh->HasTextureCoords(0) ) {
            p_meshItem.TexCoords[i*2+0] = p_paiMesh->mTextureCoords[0][i].x;
            p_meshItem.TexCoords[i*2+1] = p_paiMesh->mTextureCoords[0][i].y;
        }

    }
}

bool MeshModel::InitMaterials(const aiScene* pScene, const std::string& p_filename) {
    // Extract the directory part from the file name
    std::string::size_type SlashIndex = p_filename.find_last_of("/");
    std::string Dir;

    if (SlashIndex == std::string::npos) {
        Dir = ".";
    }
    else if (SlashIndex == 0) {
        Dir = "/";
    }
    else {
        Dir = p_filename.substr(0, SlashIndex);
    }

    bool Ret = true;

    // Initialize the materials
    for (unsigned int i = 0 ; i < pScene->mNumMaterials ; i++) {
        const aiMaterial* pMaterial = pScene->mMaterials[i];

        m_textures[i] = NULL;
        std::string FullPath = "";

        if (pMaterial->GetTextureCount(aiTextureType_DIFFUSE) > 0) {
            aiString Path;

            if (pMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) {
                FullPath = Dir + "/" + Path.data;
                m_textures[i] = std::make_shared<CTexture>( GL_TEXTURE_2D, FullPath.c_str() );
                if ( !m_textures[i]->Load() ) {
                    printf("Error loading texture '%s'.\n", FullPath.c_str());
                    m_textures[i].reset();
                    m_textures[i] = NULL;
                    Ret = false;
                }
                else {
                    printf("Texture File '%s' loaded successfully\n", FullPath.c_str());
                }
            }
        }

        // Load a white texture in case the model does not include its own texture
        if (!m_textures[i]) {
            m_textures[i] = std::make_shared<CTexture>( GL_TEXTURE_2D, "..//Data/Textures/white.png");
            printf("A default Texture File was loaded for '%s'.\n", FullPath.c_str());

            Ret = m_textures[i]->Load();
        }
    }

    // Genertate a Sampler object
    glGenSamplers(1, &m_samplerObj);
    glSamplerParameteri(m_samplerObj, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glSamplerParameteri(m_samplerObj, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glSamplerParameteri(m_samplerObj, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glSamplerParameteri(m_samplerObj, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    return Ret;
}

void MeshModel::DrawMesh() {

    for (unsigned int i = 0 ; i < m_meshItems.size() ; i++) {
        glUseProgram( getGLSystem().getProgram() ); // Bind to our selected shader program
        glBindVertexArray(m_meshItems[i].VAO);

        const unsigned int MaterialIndex = m_meshItems[i].MaterialIndex;
        // If textures exist then bind them to samplers etc
        if (MaterialIndex < m_textures.size() && m_textures[MaterialIndex]) {
            glUniform1i(m_pgls->m_samplerUnif, 0);
            glActiveTexture(GL_TEXTURE0 + 0);
            glBindTexture(GL_TEXTURE_2D, m_textures[MaterialIndex]->m_texObj);
            glBindSampler(0, m_samplerObj);
        } else {
            printf("MeshItem has no material!");
        }

        // RTS
        glutil::MatrixStack currMatrix;
        currMatrix.Translate(glm::vec3(0.0f, -3.0f, -10.0f));
        currMatrix.Scale(0.1f, 0.1f, 0.1f);
        currMatrix.RotateX(-90);
        float a = Game::m_tick.asSeconds() /10;
        float fAngRad = m_pgls->ComputeAngleRad(a, 2.0);
        float fCos = cosf(fAngRad);
        float fSin = sinf(fAngRad);

        glm::mat3 theMat(1.0f);
        theMat[0].x = fCos; theMat[1].x = -fSin;
        theMat[0].y = fSin; theMat[1].y = fCos;
        currMatrix.ApplyMatrix(glm::mat4(theMat));
        glUniformMatrix4fv(m_pgls->modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));

        glDrawElements(GL_TRIANGLES, m_meshItems[i].NumIndices, GL_UNSIGNED_INT, 0);

        glBindVertexArray(0); // Unbind the VAO
        glUseProgram(0); // Close the link to the bound shader programs
    }
}
c++opengltexturestexture-mappingassimp

Answers

answered 5 years ago dwMagician #1

I think you need to enable textures with glEnable(GL_TEXTURES_2D) in your init section. I get the same look by commenting out that line from my project. Here's the code, if that helps:

EnableGraphics::EnableGraphics()
{
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 1.0);        
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // typical alpha transparency
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

EDIT:

In case your link dies, I should add that your screenshot shows a 3D model with no textures or shading, although it has colors.

answered 5 years ago GuyRT #2

I notice your vertex shader declares:

out vec2 oTexCoord;

but your fragment shader declares:

in vec2 TexCoord;

This might leave your texture coordinates undefined.

comments powered by Disqus