# OpenGL Question on how lighting works in OpenGL

This topic is 2776 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi everyone,

I've been learning how to code OpenGL (ES to be exact, for Android platform) for the past couple of weeks. I've bumped into a problem and I am unable to progress any further at the moment. I'd appreciate if someone can suggest what I'm doing wrong here.

I've drawn couple of walls here. The goal was to draw walls with spot lights so that I can see the "ring" of lights. Although I had a tunnel working with just 2 triangles per wall, I realized there just isn't enough vertices to create a realistic spot light, so I went further from here.

This is what I've done so far:

1. I've created a basic wall that contains 5x5 squares which in turn are made out of 2 triangles. Since this is going to be a tunnel, I've assigned normal vectors at each vertices to be (1,0,0) for the "left" wall.

2. I've used translations and rotations to create more walls.

3. I've placed the light source on top of the bottom surface, facing (-1, 0, 0). I am expecting a circular light pattern on the left wall and no other walls.

Here's the link to the render:

http://www.flickr.com/photos/yhb_photos/5173472812/

Explanation of what you are seeing in the picture:

1. All vertex points positions are ok - its working as intended.

2. For some reason, all walls further than 2f from the origin shows white. Only the left wall connected to the ceiling is rendered correctly.

3. Floor shows some weird patterns and even a hole in the middle. The light does not face in this direction at all. In fact, if I bring the lower left wall into the distance 1f, it looks identical to this floor.

Any idea what's going on here?

Thank you.

##### Share on other sites
Can you put up your relevant code?

##### Share on other sites
There's a lot of code already so I'll do my best to post only the relevant pieces. :)

// Initializationprivate float[] lightAmbient = { 0.1f, 0.1f, 0.1f, 1f };private float[] lightDiffuse = { 1f, 1f, 1f, 1f };private float[] lightSpecular = { 1f, 1f, 1f, 1f };private float[] lightPosition = { 0f, 0f, -7f, 1f };private float[] lightDirection = { -1f, 0f, 0f };private FloatBuffer lightAmbientBuffer;private FloatBuffer lightDiffuseBuffer;private FloatBuffer lightSpecularBuffer;private FloatBuffer lightPositionBuffer;private FloatBuffer lightDirectionBuffer;byteBuf = ByteBuffer.allocateDirect(lightAmbient.length * 4);byteBuf.order(ByteOrder.nativeOrder());lightAmbientBuffer = byteBuf.asFloatBuffer();lightAmbientBuffer.put(lightAmbient);lightAmbientBuffer.position(0);byteBuf = ByteBuffer.allocateDirect(lightDiffuse.length * 4);byteBuf.order(ByteOrder.nativeOrder());lightDiffuseBuffer = byteBuf.asFloatBuffer();lightDiffuseBuffer.put(lightDiffuse);lightDiffuseBuffer.position(0);ByteBuf = ByteBuffer.allocateDirect(lightSpecular.length * 4);byteBuf.order(ByteOrder.nativeOrder());lightSpecularBuffer = byteBuf.asFloatBuffer();lightSpecularBuffer.put(lightSpecular);lightSpecularBuffer.position(0);byteBuf = ByteBuffer.allocateDirect(lightPosition.length * 4);byteBuf.order(ByteOrder.nativeOrder());lightPositionBuffer = byteBuf.asFloatBuffer();lightPositionBuffer.put(lightPosition);lightPositionBuffer.position(0);byteBuf = ByteBuffer.allocateDirect(lightDirection.length * 4);byteBuf.order(ByteOrder.nativeOrder());lightDirectionBuffer = byteBuf.asFloatBuffer();lightDirectionBuffer.put(lightDirection);lightDirectionBuffer.position(0);gl.glViewport(0, 0, width, height);gl.glMatrixMode(GL10.GL_PROJECTION);gl.glLoadIdentity();GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f, 100.0f);gl.glMatrixMode(GL10.GL_MODELVIEW);gl.glLoadIdentity();gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbientBuffer);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuseBuffer);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, lightSpecularBuffer);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPositionBuffer);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPOT_DIRECTION, lightDirectionBuffer);gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_CUTOFF, 5f);gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_EXPONENT, 40f);gl.glEnable(GL10.GL_LIGHT0);gl.glEnable(GL10.GL_TEXTURE_2D); // Enable Texture Mappinggl.glShadeModel(GL10.GL_SMOOTH); // Enable Smooth Shadinggl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Backgroundgl.glClearDepthf(1f); // Depth Buffer Setupgl.glEnable(GL10.GL_DEPTH_TEST); // Enables Depth Testinggl.glDepthFunc(GL10.GL_LEQUAL); // The Type Of Depth Testing To Dogl.glEnable(GL10.GL_NORMALIZE);gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);// "OnDraw"gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);gl.glLoadIdentity();gl.glEnable(GL10.GL_LIGHTING);gl.glTranslatef(-1f, 0.0f, -5.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glLoadIdentity();gl.glTranslatef(0.0f, 2.0f, -5.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0.0f, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0.0f, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0.0f, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glLoadIdentity();gl.glRotatef(-90f, 0f, 0f, 1f);gl.glTranslatef(-2f, 0f, -5.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0.0f, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0.0f, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0.0f, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glLoadIdentity();gl.glRotatef(90f, 0f, 0f, 1f);gl.glTranslatef(0.0f, 0.0f, -5.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0.0f, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0.0f, 0.0f, -2.0f);mMeshWallLeft.draw(gl);gl.glTranslatef(0.0f, 0.0f, -2.0f);mMeshWallLeft.draw(gl);// mMeshWallLeft is an instance of a Class MeshWallLeft as follows:public MeshWallLeft(int ny, int nz) {	ByteBuffer byteBuf;	verticesLeft = new float[ny*nz*12];	int count = 0;	for (float y = -1; y < 1f-0.01; y += 2f/ny) {		for (float z = 1; z > -1f+0.01; z -= 2f/nz) {			// vertex 1			verticesLeft[count++] = -1f;		// 0			verticesLeft[count++] = y;	 		// 1			verticesLeft[count++] = z - 2f/nz;	// 2						// vertex 2			verticesLeft[count++] = -1f;		// 3			verticesLeft[count++] = y;	 		// 4			verticesLeft[count++] = z;			// 5							// vertex 3			verticesLeft[count++] = -1f;		// 6			verticesLeft[count++] = y + 2f/ny;	// 7			verticesLeft[count++] = z - 2f/nz;	// 8								// vertex 4			verticesLeft[count++] = -1f;		// 9			verticesLeft[count++] = y + 2f/ny; 	// 10			verticesLeft[count++] = z;			// 11		}	}	normalLeft = new float[ny*nz*12];	count = 0;	for (float y = -1; y < 1f-0.01; y += 2f/ny) {		for (float z = 1; z > -1f+0.01; z -= 2f/nz) {			normalLeft[count++] = 1f; // 0 			normalLeft[count++] = 0f; // 1			normalLeft[count++] = 0f; // 2			normalLeft[count++] = 1f; // 3			normalLeft[count++] = 0f; // 4			normalLeft[count++] = 0f; // 5			normalLeft[count++] = 1f; // 6			normalLeft[count++] = 0f; // 7			normalLeft[count++] = 0f; // 8			normalLeft[count++] = 1f; // 9			normalLeft[count++] = 0f; // 10			normalLeft[count++] = 0f; // 11		}	}	indicesLeft = new byte[ny*nz*6];	count = 0;	int count2 = 0;	for (float y = -1; y < 1f-0.01; y += 2f/ny) {		for (float z = 1; z > -1f+0.01; z -= 2f/nz) {			indicesLeft[count++] = (byte) (1 + count2); // 0 			indicesLeft[count++] = (byte) (0 + count2); // 1 			indicesLeft[count++] = (byte) (3 + count2); // 2 			indicesLeft[count++] = (byte) (3 + count2); // 3 			indicesLeft[count++] = (byte) (0 + count2); // 4 			indicesLeft[count++] = (byte) (2 + count2); // 5 			count2 += 4;		}	}	byteBuf = ByteBuffer.allocateDirect(verticesLeft.length * 4);	byteBuf.order(ByteOrder.nativeOrder());	vertexBufferLeft = byteBuf.asFloatBuffer();	vertexBufferLeft.put(verticesLeft);	vertexBufferLeft.position(0);	byteBuf = ByteBuffer.allocateDirect(normalLeft.length * 4);	byteBuf.order(ByteOrder.nativeOrder());	normalBufferLeft = byteBuf.asFloatBuffer();	normalBufferLeft.put(normalLeft);	normalBufferLeft.position(0);	indexBufferLeft = ByteBuffer.allocateDirect(indicesLeft.length);	indexBufferLeft.put(indicesLeft);	indexBufferLeft.position(0);}And here's the "Draw" method for the above class:private void drawLeft(GL10 gl) {	//Bind our only previously generated texture in this case	gl.glBindTexture(GL10.GL_TEXTURE_2D, texturesLeft[0]);	//Point to our buffers	gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);	gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);	gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);		//Set the face rotation	gl.glFrontFace(GL10.GL_CCW);	//Enable the vertex and texture state	gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBufferLeft);	gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBufferLeft);	gl.glNormalPointer(GL10.GL_FLOAT, 0, normalBufferLeft);		//Draw the vertices as triangles, based on the Index Buffer information	gl.glDrawElements(GL10.GL_TRIANGLES, indicesLeft.length, GL10.GL_UNSIGNED_BYTE, indexBufferLeft);	//Disable the client state before leaving	gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);	gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);	gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);}

I hope I didn't miss anything....

##### Share on other sites
I've gone through it a little bit and I haven't seen anything that would really indicate some of the strange artifacts that you see in your image. Can you call glGetError() during the rendering loop and assert if it is nonzero? That's always the first thing to check anytime you have unexpected behavior.

Secondly, your environment would really benefit from either finer tessellation or per-pixel lighting (shaders required).

You're never going to see a nice cone of light with such large quads, you'll just have ugly gradients across the surface which will not look anything like reality. Read chapter 2 of this page: 2. Poor Tessellation Hurts Lighting to understand what I mean.

##### Share on other sites
Quote:
 Original post by karwostsI've gone through it a little bit and I haven't seen anything that would really indicate some of the strange artifacts that you see in your image. Can you call glGetError() during the rendering loop and assert if it is nonzero? That's always the first thing to check anytime you have unexpected behavior.

Within the "draw" method, I added the glGetError() all over the places and checked for a non-zero value. I got nothing, so I guess all gl functions went through ok.

Quote:
 Secondly, your environment would really benefit from either finer tessellation or per-pixel lighting (shaders required).

Understood. I did code the class in such a way that I can specify the number of squares in my mesh wall. Unfortunately, I also realized that # of indices are specified in a byte variable? So am I limited to only 255 indices per draw call?

And about the use of shaders - I have no idea how to go about doing this yet. Is it available in OpenGL ES like the one I use for the Android phone environment?

Quote:
 You're never going to see a nice cone of light with such large quads, you'll just have ugly gradients across the surface which will not look anything like reality. Read chapter 2 of this page: 2. Poor Tessellation Hurts Lighting to understand what I mean.

Thanks for the link, very useful. :)

So in summary, I still have no idea where it went wrong. :(

##### Share on other sites
Just looking through the code again - is it fundamentally correct to write a code that draws a wall at a fixed position and use the same code + translate/rotate to draw other walls?

Thank you.

##### Share on other sites
Quote:
 I also realized that # of indices are specified in a byte variable? So am I limited to only 255 indices per draw call?

I'm not sure where you saw this, but it isn't true. You can use shorts or ints to specify your index variables, so you can have 2^32 verts in a single call if you want to.

Quote:
 Just looking through the code again - is it fundamentally correct to write a code that draws a wall at a fixed position and use the same code + translate/rotate to draw other walls?

There's nothing fundamentally wrong with this approach. Typically you might make your meshes in a modeling program and then import the vertices, but you can draw them procedurally if you want.

Quote:
 And about the use of shaders - I have no idea how to go about doing this yet. Is it available in OpenGL ES like the one I use for the Android phone environment?

Yes they are available and they are what you should eventually be using, but they have a bit of a learning curve to them so if you're satisfied where you are now you can keep on without them for now. But eventually you'll want to start looking into them. I recommend this site for help:
lighthouse3d GLSL tutorial

Quote:
 So in summary, I still have no idea where it went wrong. :(

I think you should try some finer tessellated walls, it may help you spot what is going on. Even if you do get it to work it will still look terrible on such large polygons, so you'll want to do it eventually anyway. It may help you see what's going on with your lights when you have more vertices to process.

##### Share on other sites
Quote:
 I'm not sure where you saw this, but it isn't true. You can use shorts or ints to specify your index variables, so you can have 2^32 verts in a single call if you want to.

You are right. :) The example I used happened to use the byte buffer so I naturally thought that was the only option. As soon as I flipped it over to the short buffer, it would let me have larger mesh. Thank you.

Quote:
 There's nothing fundamentally wrong with this approach. Typically you might make your meshes in a modeling program and then import the vertices, but you can draw them procedurally if you want.

Good to hear that the approach is ok. I can stop worrying about this concern now. :)

Quote:
 Yes they are available and they are what you should eventually be using, but they have a bit of a learning curve to them so if you're satisfied where you are now you can keep on without them for now. But eventually you'll want to start looking into them. I recommend this site for help:lighthouse3d GLSL tutorial

Will definitely look into this link once I get the current part ironed out. Thanks.

Quote:
 I think you should try some finer tessellated walls, it may help you spot what is going on. Even if you do get it to work it will still look terrible on such large polygons, so you'll want to do it eventually anyway. It may help you see what's going on with your lights when you have more vertices to process.

For now, I'll try the finer tessellated walls and see what happens. Thanks!

##### Share on other sites
Ok, here's the new result.

http://www.flickr.com/photos/yhb_photos/5178129104/

I've increased the tessellation to 100x100 per wall.

Then I noticed a part of a circle on the ceiling, so I pushed the light location by another -1 on the z-axis.

Now I can clearly see a circle on the ceiling! Remember, my light direction vector is (-1, 0, 0)!

This is driving me crazy. :)

Question: If I apply a rotation, does this change the normal vectors assigned to the wall? (I expect this is the case). Also does rotation affect the light direction vector? (I don't expect this is the case).

Thank you.

[Edited by - yhbae on November 15, 2010 3:17:55 AM]

##### Share on other sites
Well I've looked up and down your code and at your image but I'm completely baffled by your result, I have no idea how you are getting that image from that code.

Do you have more than one light in the scene? The light doesn't look like a spotlight at all, it's actually brighter outside the spotlight cone than inside it, so I'm not really sure how that's possible. I think there must be something wrong elsewhere in your application that you haven't shown or your data is corrupted or something, because I just can't explain that from the code I'm seeing. Sorry I know this must be frustrating, but believe me that it is not usually this difficult!

Quote:
 Question: If I apply a rotation, does this change the normal vectors assigned to the wall? (I expect this is the case). Also does rotation affect the light direction vector? (I don't expect this is the case).

Yes, the normal vector is also transformed by the rotation. For the light direction, it is affected by rotations before you specify the direction, not after.

So this: ( I know the syntax is illegal, but it illustrates the point)
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPOT_DIRECTION, [-1,0,0]);glRotate(180,0,1,0);

defines a light direction in the negative x axis, while this:

glRotate(180,0,1,0);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPOT_DIRECTION, [-1,0,0]);

defines a light direction down the positive x axis.

1. 1
2. 2
3. 3
4. 4
Rutin
18
5. 5

• 11
• 21
• 12
• 12
• 11
• ### Forum Statistics

• Total Topics
631405
• Total Posts
2999890
×