PDA

View Full Version : Lighting a Triangle Fan



geekygenius
01-18-2012, 04:25 PM
So, I have been building a dynamic terrain renderer, and it was going well until I needed to add lighting. I am new to OpenGL, and I have no idea what is causing the problem, but I have a few ideas.

Here is my code so far, it is written in Java using LWJGL.
<div class="ubbcode-block"><div class="ubbcode-header">Click to reveal.. <input type="button" class="form-button" value="Show me!" onclick="toggle_spoiler(this, 'Yikes, my eyes!', 'Show me!')" />]<div style="display: none;">


package geekygenius.nutrality;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.*;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import org.lwjgl.opengl.GL11;

public class DeafultMapRenderer implements MapRenderer {
private final float HEIGHT_MOD = .5f;

public void initilizeRenderer(Map map, int width, int height) {
glMatrixMode(GL11.GL_PROJECTION);
glLoadIdentity();
gluPerspective(80f, (float) width / height, .1f, 100f);
//glOrtho(0, width, height, 0, .1, 1000);
glMatrixMode(GL11.GL_MODELVIEW);
glRotatef(-30, 1.0f, 0.0f, 0.0f);
glTranslatef(-(width / 64), 0, -10);

setUpLighting(width, height);

// Debug crap
map.setHeightRange(10, 5, 2, 2, 2);
map.setType(10, 5, BlockType.SEA);

// Wire frame mode
//glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
}

public void render(Map map) {
// Clear the screen and depth buffer
glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

// set the color of the quad (R,G,B,A)
glColor3f(0.1f, 0.8f, 0.1f); // Green

// Allocate some memory for the verticies
float[][] verticies = new float[6][3];
float[] normal = new float[3];

for (int x = 0; x < map.getWidth(); x++) {
for (int y = 0; y < map.getHeight(); y++) {
// TODO replace with ctual textures/shaders
if (map.getType(x, y) == BlockType.LAND) {
glColor3f(0.1f, 0.8f, 0.1f); // Green
} else if (map.getType(x, y) == BlockType.SEA) {
glColor3f(0.1f, 0.1f, 0.8f); // Blue
}

// Calculate verticies now, so we don't have to re calculate
// when finding normals
verticies[0] = new float[] {x + .5f,y + .5f,average(map.getHeight(x, y), map.getHeight(x + 1, y),
map.getHeight(x, y + 1),map.getHeight(x + 1, y + 1))* HEIGHT_MOD };
verticies[1] = new float[] { x, y,map.getHeight(x, y) * HEIGHT_MOD };
verticies[2] = new float[] { x + 1, y,map.getHeight(x + 1, y) * HEIGHT_MOD };
verticies[3] = new float[] { x + 1, y + 1,map.getHeight(x + 1, y + 1) * HEIGHT_MOD };
verticies[4] = new float[] { x, y + 1,map.getHeight(x, y + 1) * HEIGHT_MOD };
verticies[5] = verticies[1];// Wrap it around

glBegin(GL_TRIANGLE_FAN);
glVertex3f(verticies[0][0], verticies[0][1], verticies[0][2]);
glVertex3f(verticies[1][0], verticies[1][1], verticies[1][2]);
for (int v = 2; v < 6; v++) {// v for vertex
glVertex3f(verticies[v][0], verticies[v][1],verticies[v][2]);

normal = getNormal(verticies[0][0], verticies[v - 1][0],verticies[v][0],
verticies[0][1],verticies[v - 1][1], verticies[v][1],
verticies[0][2], verticies[v - 1][2],verticies[v][2]);// Normal for top section

//normal = new float [] {0.0f, 0.0f, 1.0f};
glNormal3f(normal[0], normal[1], normal[2]);
}
glEnd();
}
}
}

private void setUpLighting(int width, int height) {
glShadeModel(GL_FLAT);

glEnable(GL_LIGHTING);

float lightPosition[] = { height, 0f, 4f, 0.0f };
FloatBuffer lPos = ByteBuffer.allocateDirect(16).order(ByteOrder.nati veOrder()).asFloatBuffer();
lPos.put(lightPosition).flip();

/*
FloatBuffer lightColor = ByteBuffer.allocateDirect(16).asFloatBuffer();
lightColor.mark();
lightColor.put(new float[] { .5f, .5f, .5f, 1f });
lightColor.reset();
*/
float lightDiffuse[] = { .2f, .2f, .2f, 1.0f };
FloatBuffer lDif = ByteBuffer.allocateDirect(16).order(ByteOrder.nati veOrder()).asFloatBuffer();
lPos.put(lightDiffuse).flip();
glLight(GL_LIGHT0, GL_DIFFUSE, lDif);

FloatBuffer position = ByteBuffer.allocateDirect(16).asFloatBuffer();
position.mark();
position.put(new float[] { height, 0f, 4f, 0.0f });
position.reset();
glLight(GL_LIGHT0, GL_POSITION, lPos);
glEnable(GL_LIGHT0);


//GL11.glLight(GL11.GL_LIGHT0, GL11.GL_AMBIENT, ambient);

//glLight(GL_LIGHT1, GL_DIFFUSE, ambient);
//glLight(GL_LIGHT1, GL_SPECULAR, ambient);


//glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5f);
//glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5f);
//glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.2f);

//glLightModel(GL_LIGHT_MODEL_AMBIENT, lDif);
//glLightModeli(GL11.GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

}

private float average(int a, int b, int c, int d) {
return (a + b + c + d) / 4;
}

private float[] getNormal(float x1, float x2, float x3, float y1, float y2,
float y3, float z1, float z2, float z3) {
float nx1 = (y3 - y1) * (z2 - z1) - (y2 - y1) * (z3 - z1);
float ny1 = (z3 - z1) * (x2 - x1) - (z2 - z1) * (x3 - x1);
float nz1 = (x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1);
float fac1 = (float) Math.sqrt((nx1 * nx1) + (ny1 * ny1) + (nz1 * nz1));
nx1 /= fac1;
ny1 /= fac1;
nz1 /= fac1;
return new float[] { nx1, ny1, nz1 };
}
}

[/QUOTE]</div>

Essentially what is does is renders triangle fan squares to try and get an end result similar to Transport tycoon. If I enable wire-frame mode, and disable lighting, I get this next image, which is the target result as far as meshes go. [IMAGE1] (http://dl.dropbox.com/u/43893607/OpenGL/openglexample1.PNG)

However, if I turn on lighting, I get a dimly lit mesh, or plane (depending if wire-frame is on or not). It looks something like this: [IMAGE2] (http://dl.dropbox.com/u/43893607/OpenGL/openglexample2.PNG) The bottom half has been brightened so the rendered portion without lighting can be seen easier.

I don't know what is causing this, I've probably forgot something obvious that I didn't know existed yet. I have tried tinkering with a few different things, and left them commented, but I can't guarentee every combination was tried. Anyways, thanks for taking the time to read my post and post an answer if you did!

-geekygenius

awhig
01-18-2012, 04:51 PM
In your TRIANGLE_FAN rendering code,

compute the normals first and do glNormal() followed by glVertex() and check.

geekygenius
01-18-2012, 07:27 PM
I still get the same results as before. Maybe something is wrong with my lighting?

awhig
01-19-2012, 09:54 AM
Are you calling to set up lighting before rendering your triangle fan?

Your code only describes the class methods. Just check the sequence used to call your methods.

Also, call glNormal() before glVertex to assign normals to the vertices.

geekygenius
01-19-2012, 11:34 PM
I got textures to work properly, and I think they are applied the same way as normals, before the vertex. Yes, I checked, and the methods are being called at the appropriate times.

BionicBytes
01-20-2012, 12:07 PM
There are several reasons why fixed function lighting can go wrong.
Firstly the polygon winding may be wrong for some of the vertices and this may be flipping the normals.
Secondly the mesh may not be tessellated enough for lighting.
Thirdly your lighting setup may be wrong and the most common cause of issues is not calling glLightv immediately after setting the modelview matrix (ie after glulookat)

geekygenius
01-20-2012, 04:45 PM
So, I re-ordered the gl calls, according to the way you described earlier, and it works lust how it should! Thanks!