2
votes

My issue is fairly straightforward: Drawing normals in LWJGL causes the light source to only apply to the model until it is manually updated after initialization. Here's the lighting initialization:

static Vector3f lightPosition = new Vector3f(-500f, -100f, 500f);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_LIGHT0);
GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, asFloatBuffer(new float[]{0.05f, 0.05f, 0.05f, 1f}));
GL11.glLight(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, asFloatBuffer(new float[]{1.5f, 1.5f, 1.5f, 1f}));

And here's my code for drawing the normals (loaded from the Standford Bunny model):

for (Face f : bunnyModel.faces){
Vector3f n1 = bunnyModel.normals.get((int)f.normal.x - 1);
GL11.glNormal3f(n1.x, n1.y, n1.z);
Vector3f v1 = bunnyModel.vertices.get((int)f.vertex.x - 1);
GL11.glVertex3f(v1.x, v1.y, v1.z);
Vector3f n2 = bunnyModel.normals.get((int)f.normal.y - 1);
GL11.glNormal3f(n2.x, n2.y, n2.z);
Vector3f v2 = bunnyModel.vertices.get((int)f.vertex.y - 1);
GL11.glVertex3f(v2.x, v2.y, v2.z);
Vector3f n3 = bunnyModel.normals.get((int)f.normal.z - 1);
GL11.glNormal3f(n3.x, n3.y, n3.z);
Vector3f v3 = bunnyModel.vertices.get((int)f.vertex.z - 1);
GL11.glVertex3f(v3.x, v3.y, v3.z);
}

What am I doing wrong here? When I disable normals, lighting works fine on everything but the model. But when I enable them, the bunny receives light, but no other surfaces do.

1
Do the other surfaces have normals as well? or possibly inward-pointing normals?Abaab
No, the only normals are contained within the model.Max Roncace
If the only normals in the scene are the ones on the model, then the rest of the scene will not be lit correctly without normals.Abaab
Ah, okay. Would you mind posting that as an answer so I can mark it as accepted?Max Roncace
Actually, I have another question. How do I generate normals for shapes? Google isn't exactly helping, as I don't really know what to search for.Max Roncace

1 Answers

2
votes

When lighting is enabled in OpenGL, all polygons will be lit according to their normals. If no normals are given to a polygon, that object's normal will default to the vec3 {0, 0, 1}. Basically, enable lighting, draw your model, then disable lighting and draw the rest of your scene.

Calculating per-face normals is fairly easy, here is a little getNormal() function I wrote:

//Feel free to use this for whatever you want, no licenses applied or anything.

//p1, p2, p3 - Vertices of triangle
public Vector3f getNormal(Vector3f p1, Vector3f p2, Vector3f p3) {

    //Create normal vector we are going to output.
    Vector3f output = new Vector3f();

    //Calculate vectors used for creating normal (these are the edges of the triangle).
    Vector3f calU = new Vector3f(p2.x-p1.x, p2.y-p1.y, p2.z-p1.z);
    Vector3f calV = new Vector3f(p3.x-p1.x, p3.y-p1.y, p3.z-p1.z);

    //The output vector is equal to the cross products of the two edges of the triangle
    output.x = calU.y*calV.z - calU.z*calV.y;
    output.y = calU.z*calV.x - calU.x*calV.z;
    output.z = calU.x*calV.y - calU.y*calV.x;

    //Return the resulting vector.
    return output.normalise();
}

[OpenGL Documentation]

[Another similar question]

[More on the cross product]

But... per-face normals can look sort of... bad. If you want a smoother result, you should use per-vertex normals. Here's the difference:

Per-Face: You can see the triangles...

Per-Vertex: enter image description here

Make sure not to use per-face normals for things like cubes, cubes are flat, not curved. Per-Vertex normals are to be used in situations where you want to make something look more smooth and realistic (skin, potato, pillow, etc.).

For calculating per-vertex normals, you basically average all the normals of the joined polygons like so:

It's de average

If you happen to get the model looking entirely black or the parts facing you are invisible, try reversing the order that you put the points into the getNormal() function (or negating the normal, the error is due to the fact that the normal is facing inward, not outward).

Hoped this helped!