geminiCoder
geminiCoder

Reputation: 2906

OpenGL ES 2.0 lighting not working in iOS app

I am currently learning OpenGL 2.0 and Im creating a basic iPhone app. I have created a model in blender and have exported it to a .obj file and have written a parser that pulls in the co-ordinates. The shape displays fine but with no colour (its black). This implies that there is something wrong with the normals. But I have check the normals and ant find anything wrong with them. Is there something missing from my code?

I would be ever so grateful for any help with this!

Screen shot

enter image description here

here is my OpenGL code

glEnable(GL_DEPTH_TEST);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);


glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);

glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, loader.currentCountOfVerticies * sizeof(GLfloat) * 3, arrayOfVerticies, GL_STATIC_DRAW);

glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0));

glGenVertexArraysOES(1, &_normalArray);
glBindVertexArrayOES(_normalArray);

glGenBuffers(1, &_normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _normalBuffer);
glBufferData(GLKVertexAttribNormal, loader.currentCountOfNormals  * sizeof(GLfloat) * 3,loader.arrayOfNormals , GL_STATIC_DRAW);

glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0));

glGenVertexArraysOES(1, &_textureArray);
glBindVertexArrayOES(_textureArray);

glGenBuffers(1, &_textureBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _textureBuffer);
glBufferData(GL_ARRAY_BUFFER, loader.currentCountOfTextureCoordinates * sizeof(GLfloat) * 2, loader.arrayOftextureCoOrdinates, GL_STATIC_DRAW);

glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 8, BUFFER_OFFSET(0));


glBindVertexArrayOES(0);

And My DrawRect Method

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindVertexArrayOES(_vertexArray); 

    glUseProgram(_program);

    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);

    #ifdef DEBUG_VERTEX_DATA_LOOP
    NSLog(@"size of c array * type %ld", loader.currentCountOfVerticies *sizeof(GLfloat));
    #endif

    //Takes in the ammout of indicies not triangels!
    glDrawArrays(GL_TRIANGLES, 0, loader.currentCountOfVerticies);
}

code from load shader method

glBindAttribLocation(_program, GLKVertexAttribPosition, "position");  
glBindAttribLocation(_program, GLKVertexAttribNormal, "normal");
glBindAttribLocation(_program, GLKVertexAttribTexCoord0, "TextCo");

Vertex shader

//  Created by Jake Cunningham on 13/10/2012.
//  Copyright (c) 2012 Jake Cunningham. All rights reserved.
//

attribute vec4 position;
attribute vec3 normal;

varying lowp vec4 colorVarying;

uniform mat4 modelViewProjectionMatrix;
uniform mat3 normalMatrix;

attribute vec2 TextCo;
varying vec2 textCoOut;

void main()
{
    vec3 eyeNormal = normalize(normalMatrix * normal);
    vec3 lightPosition = vec3(0.0, 0.0, 1.0);
    vec4 diffuseColor = vec4(0.4, 0.4, 1.0, 1.0);

    float nDotVP = max(0.0, dot(eyeNormal, normalize(lightPosition)));

    colorVarying = diffuseColor * nDotVP;

    gl_Position = modelViewProjectionMatrix * position;
    textCoOut = TextCo;
}

fragment shader

//
//  Created by Jake Cunningham on 13/10/2012.
//  Copyright (c) 2012 Jake Cunningham. All rights reserved.
//

varying lowp vec4 colorVarying;

varying lowp vec2 textCoOut;
uniform sampler2D texture;

void main()
{
    gl_FragColor = colorVarying * texture2D(texture, textCoOut);
}

Upvotes: 1

Views: 895

Answers (3)

Christian Rau
Christian Rau

Reputation: 45948

The problem is your usage of multiple vertex array objects. A vertex array object (VAO) is a lightweight object (meaning it doesn't contain any actual vertex attribute data) encapsulating all the state required for rendering a bunch of vertex arrays with a single draw call, in particular:

  • The settings made with glVertexAttribPointer for each attribute index
  • The enabled attribute arrays
  • The bound element array buffer

It is therefore one level higher than the individual vertex attribute arrays, comprising all the vertex attribute array settings of a single (conceptual) scene object, or more correctly, a single draw call.

But in your code you create a new vertex array object for each individual attribute. When then rendering you only bind _vertexArray which in turn only sets and enables the GLKVertexAttribPosition attribute, thus no normals, or texCoords, or whatever else.

So you should have rather replaced the original code with:

glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);

glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, loader.currentCountOfVerticies * sizeof(GLfloat) * 3, arrayOfVerticies, GL_STATIC_DRAW);

glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0));

//forget this
//glGenVertexArraysOES(1, &_normalArray);
//glBindVertexArrayOES(_normalArray);

glGenBuffers(1, &_normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _normalBuffer);
glBufferData(GLKVertexAttribNormal, loader.currentCountOfNormals  * sizeof(GLfloat) * 3,loader.arrayOfNormals , GL_STATIC_DRAW);

glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0));

//and this, too
//glGenVertexArraysOES(1, &_textureArray);
//glBindVertexArrayOES(_textureArray);

glGenBuffers(1, &_textureBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _textureBuffer);
glBufferData(GL_ARRAY_BUFFER, loader.currentCountOfTextureCoordinates * sizeof(GLfloat) * 2, loader.arrayOftextureCoOrdinates, GL_STATIC_DRAW);

glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 8, BUFFER_OFFSET(0));

glBindVertexArrayOES(0);

Upvotes: 0

geminiCoder
geminiCoder

Reputation: 2906

I have solved the problem, but I must confess Im still not certain what the problem was. I changed my code from above to

glEnable(GL_DEPTH_TEST);

glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);

glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, total * sizeof(GLfloat), mergedArray, GL_STATIC_DRAW);

glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));

glBindVertexArrayOES(0);

Merging both the arrays of vertices and normals into a single buffer resolved the problem. I now have lighting. Why I was unable to use 2 buffers I don't know If any one can spot something I cant I would be grateful for any feed back.

Much thanks to all G.C

Upvotes: 0

rickster
rickster

Reputation: 126137

I'd suggest first testing lighting separate from texturing. The multiply in your fragment shader means that if your texel is black -- which it's likely to be if you're failing to load a texture or have other texturing problems -- you won't see the output of your lighting code.

Upvotes: 2

Related Questions