Opengl 在LWJGL中绘制法线会使照明混乱

Opengl 在LWJGL中绘制法线会使照明混乱,opengl,lwjgl,lighting,Opengl,Lwjgl,Lighting,我的问题相当简单:在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 fl

我的问题相当简单:在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模型加载):


我做错了什么?当我禁用法线时,除了模型之外,照明在所有对象上都可以正常工作。但是,当我启用它们时,兔子会接收灯光,但其他曲面不会接收灯光。

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

但是。。。每面法线看起来有点。。。糟糕。如果希望得到更平滑的结果,则应使用逐顶点法线。区别在于:

每面:

逐顶点:

确保不要对立方体等对象使用面法线,立方体是平面的,而不是弯曲的。逐顶点法线用于希望使某些东西看起来更平滑和逼真的情况(皮肤、土豆、枕头等)

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

如果模型看起来完全是黑色的,或者面向您的部分不可见,请尝试反转将点放入getNormal()函数的顺序(或者对法线求反,错误是因为法线向内,而不是向外)


希望这有帮助

其他曲面也有法线吗?或者可能是向内的法线?不,只有法线包含在模型中。如果场景中只有模型上的法线,那么没有法线,场景的其余部分将无法正确照亮。啊,好的。你介意把它贴出来作为答案吗?这样我就可以把它标记为接受了。事实上,我还有一个问题。如何生成形状的法线?谷歌帮不上什么忙,因为我真的不知道该搜索什么。答案很好,但我该如何修改你包含的计算四边形法线的方法呢?@mproncace如果四边形是“平坦的”,你只需将四边形的前3个点放入getNormal()函数。否则,给定4个点p1、p2、p3和p4,归一化向量是(getNormal(p1、p2、p3)+getNormal(p2、p3、p4))。normalise()另外,要知道的一件好事是,wen OpenGL绘制四边形,它实际上绘制了2个三角形。图形卡是为绘制三角形而设计的。哦,我还更正了我的getNormal()函数(我记得规范化了输出向量),因此,如果您复制粘贴了它,您可能应该再次执行该操作。@mproncace您使用GLSL了吗?我建议用一个新的问题来回答这个问题,并提供更多的信息。实际上,我刚刚删除了那个评论,因为我意识到我在调用这个方法方面完全搞砸了。所以,新问题又来了。我假设当你说平均面向量时,你的意思是平均它们的坐标。然而,当我试图用这些新坐标创建一个向量时,LWJGL在尝试法线化时抛出一个错误,说它是一个零长度向量。@mproncace我的意思是平均连接面的法线,而不是面本身的坐标。对不起,误会了。
//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();
}