LWJGL中的绘制法线与照明混乱 [英] Drawing normals in LWJGL messes with lighting

查看:100
本文介绍了LWJGL中的绘制法线与照明混乱的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题很简单:在LWJGL中绘制法线会导致光源仅应用于模型,直到初始化后手动对其进行更新.这是照明初始化:

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}));

这是我绘制法线的代码(从Standford Bunny模型加载):

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);
}

我在这里做错了什么?当我禁用法线时,除模型外,其他所有物体都可以正常照明.但是,当我启用它们时,兔子会收到光,但是其他表面都没有.

解决方案

在OpenGL中启用照明后,所有多边形将根据其法线进行照明.如果没有为多边形提供法线,则该对象的法线将默认为vec3 {0, 0, 1}.基本上,启用照明,绘制模型,然后禁用照明并绘制场景的其余部分.

计算按面法线是相当容易的,这是我写的一些getNormal()函数:

//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文档]

[另一个类似的问题]

[关于交叉产品的更多信息]

但是...按面的法线看起来有点...糟糕.如果要获得更平滑的结果,则应使用每个顶点的法线.区别在于:

每脸:

每个顶点:

请确保不要对多维数据集,多维数据集是平坦的而不是弯曲的东西使用按面法线. 逐顶点"法线用于要使某些东西看起来更平滑和逼真的情况(皮肤,土豆,枕头等)的情况.

要计算每个顶点的法线,基本上可以对连接的多边形的所有法线求平均,如下所示:

如果碰巧使模型看起来全黑或面对您的零件不可见,请尝试颠倒将点放入getNormal()函数的顺序(或否定法线,该错误是由于以下事实造成的:法线朝内,而不是朝外.

希望这对您有所帮助!

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.

解决方案

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!

这篇关于LWJGL中的绘制法线与照明混乱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆