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);
}