OpenGL ES 1.1奇怪的灯光问题

时间:2011-10-30 22:42:12

标签: android opengl-es opengl-es-lighting

我正在研究一个有趣的问题,我在Android上面对OpenGL照明。我正在使用3D Viewer,您可以在其中添加和操作3D对象。您还可以设置具有不同属性的灯光。我在观察者面前遇到的问题是,光线上的3D物体上的高光(它是一个点光源)表现得很奇怪。如果光源与相机处于完全相同的位置,则高光将以您期望的相反方向移动。 (因此,如果您将对象移动到左侧,则突出显示也会移动到对象的leftedge,而不是右侧,这正是我所期待的。)

The highlight is on the bottom left whereas i'd expect it to be on the right side

因此,为了进一步缩小问题范围,我创建了一个小样本应用程序,它只渲染一个正方形,然后围绕摄像机位置(原点)旋转该正方形,这也是光源所在的位置。这应该导致所有方格直接面向相机,以便它们完全突出显示。结果虽然看起来像那样:

Lighting

由于投影导致边界变形,是否会出现这些瑕疵?

在第一张图像中,球体和相机之间的距离约为20个单位,球体的大小约为2.如果我将光线移近物体,则高光看起来要好得多,就像我'我期待着它。 在第二幅图像中,正方形所在的半径为25个单位。 我在Android 3.1上使用OpenGL ES 1.1(因为我很难让它与ES 2.0中的着色器一起使用)

以下是我正在使用的一些代码:

public void onDrawFrame(GL10 gl) {
    // Setting the camera
    GLU.gluLookAt(gl, 0, 0, 0, 0f, 0f, -1f, 0f, 1.0f, 0.0f);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();

    for (int i = 0; i < 72; i++) {
        gl.glPushMatrix();
        gl.glRotatef(5f * i, 0, 1, 0);
        gl.glTranslatef(0, 0, -25);
        draw(gl);
        gl.glPopMatrix();
    }
}

public void draw(GL10 gl) {
    setMaterial(gl);
    gl.glEnable(GL10.GL_NORMALIZE);
    gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

    gl.glFrontFace(GL10.GL_CCW);

    // Enable the vertex and normal state
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
    gl.glNormalPointer(GL10.GL_FLOAT, 0, mNormalBuffer);

    gl.glDrawElements(GL10.GL_TRIANGLES, mIndexBuffer.capacity(), GL10.GL_UNSIGNED_SHORT, mIndexBuffer);

    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);

}

// Setting the light
private void drawLights(GL10 gl) {
    // Point Light
    float[] position = { 0, 0, 0, 1 };
    float[] diffuse = { .6f, .6f, .6f, 1f };
    float[] specular = { 1, 1, 1, 1 };
    float[] ambient = { .2f, .2f, .2f, 1 };

    gl.glEnable(GL10.GL_LIGHTING);
    gl.glEnable(GL10.GL_LIGHT0);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();

    gl.glLightfv(GL10.GL_LIGHT0, GL_POSITION, position, 0);
    gl.glLightfv(GL10.GL_LIGHT0, GL_DIFFUSE, diffuse, 0);
    gl.glLightfv(GL10.GL_LIGHT0, GL_AMBIENT, ambient, 0);
    gl.glLightfv(GL10.GL_LIGHT0, GL_SPECULAR, specular, 0);
}

private void setMaterial(GL10 gl) {
    float shininess = 30;
    float[] ambient = { 0, 0, .3f, 1 };
    float[] diffuse = { 0, 0, .7f, 1 };
    float[] specular = { 1, 1, 1, 1 };

    gl.glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse, 0);
    gl.glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient, 0);
    gl.glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular, 0);
    gl.glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
}   

我在开始时设置灯光,当活动开始时(在onSurfaceCreated中)和每次绘制正方形时的材质。

2 个答案:

答案 0 :(得分:1)

第二个示例中的效果(使用方块)更多是由于OpenGL使用的默认非本地查看器。默认情况下,眼睛空间视图矢量(从顶点到相机的矢量,用于镜面反射高光计算)仅被视为(0,0,1) - 矢量,而不是标准化的顶点位置。这种近似只有在顶点位于屏幕中间时才是正确的,但是当你移动到srceen的边界时越来越不正确。

要更改此设置并让OpenGL使用从顶点到相机的真实矢量,只需使用glLightModel功能,尤其是

glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

我不确定这是否也是您第一个问题的原因(使用球体),但也许只是尝试一下。

编辑:您似乎无法在OpenGL ES中使用GL_LIGHT_MODEL_LOCAL_VIEWER。在这种情况下,除了切换到OpenGL ES 2.0并自己进行所有照明计算之外,没有办法解决这个问题。

答案 1 :(得分:0)

当你移动物体时,你的光线可能正在移动。

看一下这个答案http://www.opengl.org/resources/faq/technical/lights.htm#ligh0050