Drawing normals in LWJGL messes with lighting

不问归期 提交于 2019-12-07 23:59:40

问题


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:


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:

Per-Vertex:

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:

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!



来源:https://stackoverflow.com/questions/15777757/drawing-normals-in-lwjgl-messes-with-lighting

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!