Наложение текстур с фонговым освещением

Я пытаюсь добавить освещение Фонга в свою сцену, в которую я загрузил сетку с текстурами. Это мой класс загрузки сетки:

#define INVALID_OGL_VALUE 0xFFFFFFFF
#define INVALID_MATERIAL 0xFFFFFFFF
#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }

Mesh::MeshEntry::MeshEntry()
{
    VB = INVALID_OGL_VALUE;
    IB = INVALID_OGL_VALUE;
    NumIndices  = 0;
    MaterialIndex = INVALID_MATERIAL;
};

Mesh::MeshEntry::~MeshEntry()
{
    if (VB != INVALID_OGL_VALUE)
    {
        glDeleteBuffers(1, &VB);
    }

    if (IB != INVALID_OGL_VALUE)
    {
        glDeleteBuffers(1, &IB);
    }
}

void Mesh::MeshEntry::Init(const std::vector<Vertex>& Vertices,
                          const std::vector<unsigned int>& Indices)
{
    NumIndices = Indices.size();

    glGenBuffers(1, &VB);
    glBindBuffer(GL_ARRAY_BUFFER, VB);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * Vertices.size(), &Vertices[0], GL_STATIC_DRAW);

    glGenBuffers(1, &IB);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IB);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * NumIndices, &Indices[0], GL_STATIC_DRAW);
}

Mesh::Mesh()
{
}


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


void Mesh::Clear()
{
    for (unsigned int i = 0 ; i < textures_cnt.size() ; i++) {
        SAFE_DELETE(textures_cnt[i]);
    }
}


/*Loads mesh
 *@Filename -   name of the .obj file
 **********************************************************/
bool Mesh::LoadMesh(const std::string& Filename){

    Assimp::Importer Importer;
    bool rc = false;

    //clear previous loaded mesh
    Clear();

    //read file content
    const aiScene* oScene = Importer.ReadFile(Filename.c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs );

    if(oScene){

        printf ("  %i animations\n", oScene->mNumAnimations);
        printf ("  %i cameras\n", oScene->mNumCameras);
        printf ("  %i lights\n", oScene->mNumLights);
        printf ("  %i materials\n", oScene->mNumMaterials);
        printf ("  %i meshes\n", oScene->mNumMeshes);
        printf ("  %i textures\n", oScene->mNumTextures);

        submeshes_cnt.resize(oScene->mNumMeshes);
        textures_cnt.resize(oScene->mNumMaterials);

        /*.........Initialize the meshes in the scene one by one...........*/
        for (unsigned int i = 0 ; i < submeshes_cnt.size() ; i++) {

            const aiMesh* paiMesh = oScene->mMeshes[i];
            InitMesh(i, paiMesh);
        }

        // Extract the directory part from the file name
        std::string::size_type SlashIndex = Filename.find_last_of("/");
        std::string Dir;

        if (SlashIndex == std::string::npos) {
            Dir = ".";
        }
        else if (SlashIndex == 0) {
            Dir = "/";
        }
        else {
            Dir = Filename.substr(0, SlashIndex);
        }
        /*.................Initialization of meshes end....................*/



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

            textures_cnt[i] = NULL;

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

                if (pMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) {
                    std::string FullPath = Dir + "/" + Path.data;
                    textures_cnt[i] = new Texture(GL_TEXTURE_2D, FullPath.c_str());

                    if (!textures_cnt[i]->Load()) {
                        printf("Error loading texture '%s'\n", FullPath.c_str());
                        delete textures_cnt[i];
                        textures_cnt[i] = NULL;
                        rc = false;
                    }
                    else {
                        printf("Loaded texture '%s'\n", FullPath.c_str());
                    }
                }
            }
        }
        /*.................Initialization of materials end....................*/
    }
    else {
        printf("Error parsing '%s': '%s'\n", Filename.c_str(), Importer.GetErrorString());
    }

    return rc;
}


void Mesh::InitMesh(unsigned int Index, const aiMesh* paiMesh)
{
    submeshes_cnt[Index].MaterialIndex = paiMesh->mMaterialIndex;

    std::vector<Vertex> Vertices;
    std::vector<unsigned int> Indices;

    const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);

    for (unsigned int i = 0 ; i < paiMesh->mNumVertices ; i++) {
        const aiVector3D* pPos      = &(paiMesh->mVertices[i]);
        const aiVector3D* pNormal   = &(paiMesh->mNormals[i]);
        const aiVector3D* pTexCoord = paiMesh->HasTextureCoords(0) ? &(paiMesh->mTextureCoords[0][i]) : &Zero3D;

        Vertex v(Vector3f(pPos->x, pPos->y, pPos->z),
                 Vector2f(pTexCoord->x, pTexCoord->y),
                 Vector3f(pNormal->x, pNormal->y, pNormal->z));

        Vertices.push_back(v);
    }

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

    submeshes_cnt[Index].Init(Vertices, Indices);
}

void Mesh::Render(){

    //enable VAOs for vertices, normals, textures
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);

    for(unsigned int i = 0 ; i < submeshes_cnt.size() ; i++){

        glBindBuffer(GL_ARRAY_BUFFER, submeshes_cnt[i].VB);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)12);
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)20);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, submeshes_cnt[i].IB);

        const unsigned int MaterialIndex = submeshes_cnt[i].MaterialIndex;

        if (MaterialIndex < textures_cnt.size() && textures_cnt[MaterialIndex]) {
            textures_cnt[MaterialIndex]->Bind(GL_TEXTURE0);
        }

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

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);


}

вершинный шейдер:

#version 420

uniform mat4 camera;
uniform mat4 model;

in vec3 vert;
in vec2 vertTexCoord;

out vec2 fragTexCoord;

void main() {
    // Pass the tex coord straight through to the fragment shader
    fragTexCoord = vertTexCoord;

    // Apply all matrix transformations to vert
    gl_Position = camera * model * vec4(vert, 1);
}

фрагментный шейдер:

#version 420

uniform sampler2D tex;

in vec2 fragTexCoord;

out vec4 finalColor;

void main() {
    //note: the texture function was called texture2D in older versions of GLSL
    finalColor = texture(tex, fragTexCoord);
}

вот что я получаю: до

но когда я пытаюсь добавить освещение Фонга, когда я добавляю атрибут нормалей к моему вершинному шейдеру, я получаю следующее: после

В чем проблема? Спасибо за помощь.

//редактируем загрузку шейдера и ссылку

shprogram::shprogram(const std::vector<shader>& shaders) :
    _object(0)
{
    if(shaders.size() <= 0)
        throw std::runtime_error("No shaders were provided to create the program");

    //create the program object
    _object = glCreateProgram();
    if(_object == 0)
        throw std::runtime_error("glCreateProgram failed");

    //attach all the shaders
    for(unsigned i = 0; i < shaders.size(); ++i)
        glAttachShader(_object, shaders[i].getObject());

    //link the shaders together
    glLinkProgram(_object);

    //detach all the shaders
    for(unsigned i = 0; i < shaders.size(); ++i)
        glDetachShader(_object, shaders[i].getObject());

    //throw exception if linking failed
    GLint status;
    glGetProgramiv(_object, GL_LINK_STATUS, &status);
    if (status == GL_FALSE) {
        std::string msg("Program linking failure: ");

        GLint infoLogLength;
        glGetProgramiv(_object, GL_INFO_LOG_LENGTH, &infoLogLength);
        char* strInfoLog = new char[infoLogLength + 1];
        glGetProgramInfoLog(_object, infoLogLength, NULL, strInfoLog);
        msg += strInfoLog;
        delete[] strInfoLog;

        glDeleteProgram(_object); _object = 0;
        throw std::runtime_error(msg);
    }
}

shprogram::~shprogram() {
    //might be 0 if ctor fails by throwing exception
    if(_object != 0) glDeleteProgram(_object);
}

GLuint shprogram::object() const {
    return _object;
}

void shprogram::use() const {
    glUseProgram(_object);
}

bool shprogram::isInUse() const {
    GLint currentProgram = 0;
    glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
    return (currentProgram == (GLint)_object);
}

void shprogram::stopUsing() const {
    assert(isInUse());
    glUseProgram(0);
}

GLint shprogram::attrib(const GLchar* attribName) const {
    if(!attribName)
        throw std::runtime_error("attribName was NULL");

    GLint attrib = glGetAttribLocation(_object, attribName);
    if(attrib == -1)
        throw std::runtime_error(std::string("Program attribute not found: ") + attribName);

    return attrib;
}

GLint shprogram::uniform(const GLchar* uniformName) const {
    if(!uniformName)
        throw std::runtime_error("uniformName was NULL");

    GLint uniform = glGetUniformLocation(_object, uniformName);
    if(uniform == -1)
        throw std::runtime_error(std::string("Program uniform not found: ") + uniformName);

    return uniform;
}

void shprogram::setUniformMatrix2(const GLchar* name, const GLfloat* v, GLsizei count, GLboolean transpose) {
    assert(isInUse());
    glUniformMatrix2fv(uniform(name), count, transpose, v);
}

void shprogram::setUniformMatrix3(const GLchar* name, const GLfloat* v, GLsizei count, GLboolean transpose) {
    assert(isInUse());
    glUniformMatrix3fv(uniform(name), count, transpose, v);
}

void shprogram::setUniformMatrix4(const GLchar* name, const GLfloat* v, GLsizei count, GLboolean transpose) {
    assert(isInUse());
    glUniformMatrix4fv(uniform(name), count, transpose, v);
}

void shprogram::setUniform(const GLchar* name, const glm::mat2& m, GLboolean transpose) {
    assert(isInUse());
    glUniformMatrix2fv(uniform(name), 1, transpose, glm::value_ptr(m));
}

void shprogram::setUniform(const GLchar* name, const glm::mat3& m, GLboolean transpose) {
    assert(isInUse());
    glUniformMatrix3fv(uniform(name), 1, transpose, glm::value_ptr(m));
}

void shprogram::setUniform(const GLchar* name, const glm::mat4& m, GLboolean transpose) {
    assert(isInUse());
    glUniformMatrix4fv(uniform(name), 1, transpose, glm::value_ptr(m));
}

void shprogram::setUniform(const GLchar* uniformName, const glm::vec3& v) {
    setUniform3v(uniformName, glm::value_ptr(v));
}

void shprogram::setUniform(const GLchar* uniformName, const glm::vec4& v) {
    setUniform4v(uniformName, glm::value_ptr(v));
}

установка униформы

//bind shader program
gProgram->use();

//set the "camera" uniform
gProgram->setUniform("camera", gCamera.matrix());

//set the "model" uniform in the vertex shader, based on the gDegreesRotated global
gProgram->setUniform("model", glm::rotate(glm::mat4(), 150.0f ,glm::vec3(0,1,0)));


gProgram->setUniform("light.position", gLight.position);
gProgram->setUniform("light.intensities", gLight.intensities);

person mezo    schedule 19.10.2013    source источник
comment
Пожалуйста, предоставьте компиляцию шейдера и код компоновки. Я до сих пор думаю, что вы не указали расположение атрибутов.   -  person derhass    schedule 19.10.2013
comment
В вашем вопросе есть код, который можно использовать для запроса местоположений атрибутов вершин (GLint shprogram::attrib(const GLchar* attribName) const), но вы его не используете! tsk-tsk. Кроме того, рассмотрите возможность переименования этой функции, так как существует множество операций, которые можно выполнять с местоположениями атрибутов вершин — вы можете запросить их после связывания, вы можете связать их перед связыванием и т. д.   -  person Andon M. Coleman    schedule 19.10.2013


Ответы (1)


Вы не устанавливаете расположение атрибутов в источнике шейдера явно, не привязываете их перед связыванием шейдера и не запрашиваете их. GL может свободно использовать любой действительный индекс атрибута для любого активного входного атрибута.

Вы просто предполагаете, что 0 — это position, 1 — texcoord, а 2 — normal. Это может сработать случайно для случая position+texcoord, но когда вы добавите нормаль, все индексы могут перепутаться. Либо используйте layout(location=...) (подробнее см. GL_ARB_explicit_attrib_location) в коде GLSL, либо используйте glBindAttribLocation(), чтобы указать нужное сопоставление.

person derhass    schedule 19.10.2013
comment
Хороший улов. Из этого правила есть одно исключение, хотя здесь оно не применяется... glVertexPointer (...) (функция, используемая для установки указателя позиции вершины в OpenGL с фиксированной функцией) — единственная функция указателя, которая использует псевдонимы (или по крайней мере, разрешено в совместимой реализации) к слоту атрибута в GLSL - это псевдоним 0. Я думаю, что это поведение отвечает за множество предположений, что слоты атрибутов всегда будут работать последовательно, или что привязка местоположения атрибутов не нужна; к сожалению, я думаю, что определение такого поведения приносит больше вреда, чем пользы :-\ - person Andon M. Coleman; 19.10.2013
comment
@ AndonM.Coleman: Хе-хе, это еще хуже. В режиме совместимости атрибут 0 является своего рода особенным, поскольку он полностью отражает всю старую функциональность спецификации вершины - вызов glVertexAttrib(0,...) внутри glBegin()/End() действительно создает вершину... Странные вещи. - person derhass; 19.10.2013