Cannot pass normals array correctly

Started by
2 comments, last by AdamYon 9 years, 8 months ago

Hi,

I wanted to implement Phong shading for my heightmap. So far I was using simple shading (set color manually) and everything worked fine.

Then the work started: I wrote shader, passed some uniform variables, commented out int vec3 vNormal; in shader and everything was fine.

Today I wanted to pass normals array, because I'd read that in newer version I have to calc them manually. What I did is create ARRAY_BUFFER, calculate normals ({0,1,0} for testing purposes), pass them to buffer, enabled VA and set glVertexAttribPointer.

Shader has stopped working since then - nothing is rendered, only background color. Doesn't matter if lines using vNormal in shader are active or in the comment.

I paste sources below - renderer class with new lines and shaders:

MapRenderer.hpp


#ifndef DEPENDENTIA_MAPRENDERER_HPP
#define DEPENDENTIA_MAPRENDERER_HPP

#include "Map.hpp"
#include <vector>

#include <iostream>

class MapRenderer {

public:
    MapRenderer(Map* gameMap, Camera* camera) : gameMap(gameMap), camera(camera) {

        indices = gameMap->getSizeX() * 2 * gameMap->getSizeY() + 2 * gameMap->getSizeY() + gameMap->getSizeY();

        prepareOGLBuffers();
        prepareShaderPrograms();
        prepareIndicesData();

        generateHeightMap();

    }

    void render() {

        /* if (gameMap has changed) */ //generateHeightMap();

        glClearColor(0.234357f, 0.472656f, 0.667968f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Temporary wireframe

        updateShaderVariables();
        renderHeightMap();

    };

    ~MapRenderer() {

        glDeleteProgram(shaderProgram);

        glDeleteBuffers(1, &hmNormals);
        glDeleteBuffers(1, &hmVBOindices);
        glDeleteBuffers(1, &hmVBO);
        glDeleteVertexArrays(1, &hmVAO); // NEW

    }

protected:

    void prepareOGLBuffers() {

        glGenVertexArrays(1, &hmVAO);
        glGenBuffers(1, &hmVBO);
        glGenBuffers(1, &hmVBOindices);
        glGenBuffers(1, &hmNormals); // NEW

        glBindVertexArray(hmVAO);
        glBindBuffer(GL_ARRAY_BUFFER, hmVBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, hmVBOindices);
        glBindBuffer(GL_ARRAY_BUFFER, hmNormals); // NEW

    }

    void prepareShaderPrograms() {

        shaderProgram = loadShaders("shaders/sample.vs", "shaders/sample.fs");
        locMVP = glGetUniformLocation(shaderProgram, "mvpMatrix");
        locMV = glGetUniformLocation(shaderProgram, "mvMatrix");
        locNormalM = glGetUniformLocation(shaderProgram, "normalMatrix");
        locLightPos = glGetUniformLocation(shaderProgram, "vLightPosition");

    }

    void prepareIndicesData() {
        unsigned int* hmIndices = new unsigned int[indices];
        for (int i=0; i<gameMap->getSizeY(); i++) {

            unsigned int indexOffset = i * ((gameMap->getSizeX() + 1) * 2 + 1);
            unsigned int vertexOffset = i * (gameMap->getSizeX() + 1);

            for (int j=0; j<2*(gameMap->getSizeX()+1)+1; j++) {
                hmIndices[indexOffset + j] = j/2 + (j % 2 ? (gameMap->getSizeX() + 1) : 0) + vertexOffset;
            }
        }

        for (int i=1; i<=gameMap->getSizeY(); i++) {
            hmIndices[i * ((gameMap->getSizeX() + 1) * 2 + 1) - 1] = gameMap->getHeightMapSize();
        }

        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices, hmIndices, GL_STATIC_DRAW);
        delete[] hmIndices;
    }

    void generateHeightMap() {

        // Fill VAO
        // TODO: refactor
        glm::vec3* heightMapVertices = new glm::vec3[gameMap->getHeightMapSize()];

        for (int i=0; i<gameMap->getHeightMapSize(); i++) {
            float x = float(i % (gameMap->getSizeX()+1)), z = float(i / (gameMap->getSizeX()+1));
            heightMapVertices[i] = glm::vec3(
                x,
                0.5 * (float) gameMap->getHeightAt(i),
                z
            );
        }

        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * gameMap->getHeightMapSize(), heightMapVertices, GL_STATIC_DRAW);
        delete[] heightMapVertices;

        // Normals buffer // NEW
        glm::vec3* hmNormalsData = new glm::vec3[gameMap->getHeightMapSize()];

        for (int i=0; i<gameMap->getHeightMapSize(); i++) {
            hmNormalsData[i] = glm::vec3(
                0,
                1,
                0
            );
        }

        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * gameMap->getHeightMapSize(), hmNormalsData, GL_STATIC_DRAW);
        delete[] hmNormalsData;


    }

    void updateShaderVariables() {

        MVP = camera->getProjectionMatrix() * camera->getViewMatrix();
        glm::mat4 MV = camera->getViewMatrix();
        glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(MV)));

        glm::vec3 lightPos(5, 10, 5);

        glUniformMatrix4fv(locMVP, 1, GL_FALSE, &MVP[0][0]);
        glUniformMatrix4fv(locMV, 1, GL_FALSE, &MV[0][0]);
        glUniformMatrix4fv(locNormalM, 1, GL_FALSE, &normalMatrix[0][0]);
        glUniformMatrix4fv(locLightPos, 1, GL_FALSE, &lightPos[0]);

        glUseProgram(shaderProgram);

    }

    void renderHeightMap() {

        glEnable(GL_PRIMITIVE_RESTART);
        glPrimitiveRestartIndex(gameMap->getHeightMapSize());

        // 1rst attribute buffer : vertices
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, hmVBO);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

// NEW below
        glEnableVertexAttribArray(1);
        glBindBuffer(GL_ARRAY_BUFFER, hmNormals);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

        glDrawElements(GL_TRIANGLE_STRIP, indices, GL_UNSIGNED_INT, 0);

        GLenum err;
        while ((err = glGetError()) != GL_NO_ERROR) {
            std::cerr << "OpenGL error: " << err << std::endl;
        }

        glEnableVertexAttribArray(1); // NEW
        glDisableVertexAttribArray(0);
        glDisable(GL_PRIMITIVE_RESTART);

    };

protected:
    Map* gameMap;
    Camera* camera;

    glm::mat4 MVP;

    GLuint shaderProgram;
    GLuint locMVP;
    GLuint locMV;
    GLuint locNormalM;
    GLuint locLightPos;

    GLuint hmVAO;
    GLuint hmVBO;
    GLuint hmVBOindices;
    GLuint hmNormals; // NEW

    long indices;

};

#endif // DEPENDENTIA_MAPRENDERER_HPP


#version 330

in vec4 vVertex;
// in vec3 vNormal;

uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;

smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;

void main(){

    /*vVaryingNormal = normalMatrix * gl_Normal;*/

    vec4 vPosition4 = mvMatrix * vVertex;
    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;

    vVaryingLightDir = normalize(vLightPosition - vPosition3);

    gl_Position = mvpMatrix * vVertex;

}


#version 330

out vec3 vFragColor;

void main(){
    vFragColor = vec3(0.31640625,0.66796875,0.234375);
}

Advertisement

shouldn't you be passing something like glGetAttribLocation(shaderProgram,"vNormal") to glEnableVertexAttribArray ?

Also, see exactly which line allows something to be rendered again if commented out, i'm guessing it's the three lines following "NEW below" ?

Check for shader compilation errors. I suspect that


// in vec3 vNormal;

This is unused, but probably doesn't cause an error.


/*vVaryingNormal = normalMatrix * gl_Normal;*/

didn't you mean normalMatrix*vNormal? Also, gl_Normal is deprecated in OpenGL 3.0+ core and GL-ES 2.0+ - you might get an undefined variable error.

Lastly - gl_Normal is vec4 and normalMatrix is mat3, so you have mat3*vec4 - it's definitely a warning, maybe even an error(don't remember for sure).

N.I.B., that is a change I made when looking for solution.

3TATUK2, I have to delete everything new to make it render.

This topic is closed to new replies.

Advertisement