Issue when passing normals to shaders

Started by
11 comments, last by Jack Shannon 11 years, 4 months ago
shader.vert:
[source lang="plain"]#version 120
varying vec3 position;
varying vec3 normal;

void main()
{
position = (vec3(gl_ModelViewMatrix*gl_Vertex)); //get the position of the vertex after translation, rotation, scaling
normal = gl_NormalMatrix*gl_Normal; //get the normal direction, after translation, rotation, scaling
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
[/source]

shader.frag:
[source lang="plain"]#version 120
varying vec3 position;
varying vec3 normal;
uniform vec3 lightColor;
uniform vec3 surfaceColor;
uniform float ambientScale;
void main()
{
vec3 lightAmbient = lightColor * ambientScale;
vec3 surfaceAmbient = surfaceColor;
vec3 ambient = lightAmbient * surfaceAmbient;
//vec3 lightDirection = normalize(position); // ***********
//float n_dot_1 = max(0.0, dot(normalize(normal), position));
vec3 lightDiffuse = lightColor;
vec3 surfaceDiffuse = surfaceColor;
//vec3 diffuse = (surfaceDiffuse * lightDiffuse) * n_dot_1;

//gl_FragColor=vec4(ambient + diffuse, 1.0);
gl_FragColor=vec4(ambient, 1.0);
}[/source]

*********** When this line is uncommented everything runs fine and the fragment colour is correct:
2y1RA.png

However, if that line is uncommented then this is what happens;
HJAjb.png

Why is this? Is it because my normals VBO passing is wrong? Is it because of the way I've written the shader itself. It's almost like the varying variable is causing the fragment shader to crash and each fragment is being defaulted as (1.0, 1.0, 1.0, 1.0). The following code is my implimentation for the VBO's.

Mesh.h:
[source lang="cpp"]#ifndef MESH_H
#define MESH_H

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cml/cml.h>
#include <GL/glfw.h>

typedef cml::vector3f vec3f;

class Mesh
{
std::vector<vec3f> vertexList;
std::vector<vec3f> normalList;
std::vector<GLuint> indexList;
std::vector<GLuint> normalIndexList;
GLuint vbo[3];

public:
Mesh(const std::string& fileName);
void init();
void display();
};

#endif[/source]

Mesh.cpp:
[source lang="cpp"]#include "Mesh.h"

Mesh::Mesh(const std::string& fileName)
{
std::string s;
// std::ifstream file(fileName);
std::ifstream file("untitled.obj");

std::string line;
while( std::getline(file, line)) {
std::istringstream iss(line);
std::string result;
if (std::getline( iss, result , ' ')) {
if (result == "v") {
float f;
vertexList.push_back(vec3f(0, 0, 0));
for (int i = 0; i < 3; i++) {
iss >> f;
vertexList.back() = f;
}
} else if (result == "vn") {
float f;
normalList.push_back(vec3f(0, 0, 0));
for (int i = 0; i < 3; i++) {
iss >> f;
normalList.back() = f;
}
} else if (result == "f") {
while (std::getline(iss, s, ' ')) {
std::istringstream indexBlock(s);
for (int i = 0; i < 3; i++) {
std::string intString;
if (std::getline(indexBlock, intString, '/')) {
std::istringstream sstream(intString);
int index = -1;
sstream >> index;
if (!(index == -1)) {
if (i == 0) {
indexList.push_back(index - 1);
} else if (i == 1) {
} else if (i == 2) {
normalIndexList.push_back(index - 1);
}
}
}
}
}
}
}
}
std::cout << "Loaded " << fileName << std::endl;
}

void Mesh::init()
{
GLfloat tmp_normals[normalList.size()][3];

unsigned int index = 0;

for (int c = 0; c < indexList.size(); c++) {
tmp_normals[indexList.at©][0] = normalList.at(normalIndexList.at©)[0];
tmp_normals[indexList.at©][1] = normalList.at(normalIndexList.at©)[1];
tmp_normals[indexList.at©][2] = normalList.at(normalIndexList.at©)[2];
std::cout << normalList.at(normalIndexList.at©)[0] << " ";
}

glGenBuffers(3, vbo);

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // vertices
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * vertexList.size(), (const GLvoid*)& vertexList.front(), GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // normals
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * normalList.size(), (const GLvoid*)& tmp_normals[0], GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); // indices
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexList.size() * sizeof(GLuint), (const GLvoid*)& indexList.front(), GL_STATIC_DRAW);
}

void Mesh::display()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);


glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // vertices
glVertexPointer(3, GL_FLOAT, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // normals
glNormalPointer(GL_FLOAT, 0, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); // indices
glDrawElements(GL_TRIANGLES, indexList.size(), GL_UNSIGNED_INT, 0);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);

}
[/source]

Thank you.
Advertisement
Not sure about this line "GLfloat tmp_normals[normalList.size()][3];" does that even compile? normalList.size() is not a constant size and its not dynamically allocated array, so...

Try displaying your normal gl_FragColor = vec4(normal, 1.0); to debug if it looks correct.
Thanks for the quick reply NumberXaero.

Yes it compiles, thinking about it now I'm not sure why it does but the couts from line 64 are correct.

Just tried as you suggested and I got the white object again. It seems it's just the varying variables not being passed properly. Very strange.
Are you running an AMD card by any chance?
Nope, I'm running a 'NVIDIA GeForce GT 330M' on a 2010 Macbook Pro.
I ask because under AMD ive had to do this with GLSL 120 to get the correct results, the built in gl_NormalMatrix was just wrong for whatever reason, dont think they ever did fix it, one of my vertex shaders still uses this

vec3 col0 = gl_ModelViewMatrixInverseTranspose[0].xyz;
vec3 col1 = gl_ModelViewMatrixInverseTranspose[1].xyz;
vec3 col2 = gl_ModelViewMatrixInverseTranspose[2].xyz;
mat3 nm = mat3(col0, col1, col2); // build the normal matrix and by pass gl_NormalMatrix


How are calculating your lighting, was it intended to be done in world space or view space, or are you just trying to make sure the everything setup correctly for now?
Hmm, I just tried substituting that and I'm still getting the same issue.

After playing with it some more I've narrowed down an exact description of my issue;

Any 'varying' variable being called by fragment shader causes all the fragments to be white, even if it doesn't modify gl_FragColor at all!
So the normal data being passed through the buffer was read in from the file correctly?
Lets say you did something like
"varying vec3 color; color = vec3(0.0, 1.0, 0.0);" in vertex shader and did "gl_FragColor = vec4(color, 1.0);" in fragment shader, you wouldnt get green?
No, I get white.

It's so strange, as soon as a varying is used it is always white.

I can do "gl_FragColor=vec4(0.0, 1.0, 0.0, 1.0);" and it's green no problem.

Should I change to a later glsl version?

E: and yes as far as I'm aware the normal data is fine.

E: and to answer your earlier question about lighting I'm just trying to get it set up correctly before worrying about specifics, I haven't used per fragment lighting before.
Did you make any changes to the tmp_normals code section, because &tmp_normals[0] is being passed to glBufferData, if normalList is correct it might not be after copied to that funky tmp_normals array.

This topic is closed to new replies.

Advertisement