2

我正在研究我在 Android 上使用 OpenGL 照明时遇到的一个有趣问题。我正在开发一个 3D 查看器,您可以在其中添加和操作 3D 对象。您还可以设置具有不同属性的灯光。我的查看器面临的问题是来自灯光(它是点光源)的 3D 对象上的高光表现异常。如果光源与相机位于完全相同的点,则高光将向您预期的相反方向移动。(因此,如果您将对象移动到左侧,突出显示也会移动到对象的左边缘,而不是我所期望的右侧。)

亮点在左下角,而我希望它在右侧

因此,为了进一步缩小问题范围,我创建了一个仅渲染正方形的小型示例应用程序,然后我围绕相机位置(原点)旋转该正方形,这也是放置灯光的位置。这应该会导致所有方块都直接面向相机,这样它们就会被完全突出显示。结果看起来像这样:

灯光

会不会是因为投影导致边框变形而出现这些伪影?

在第一张图像中,球体和相机之间的距离约为 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 中)以及每次我绘制正方形时的材质。

4

2 回答 2

1

The effect in your second example (with the squares) is rather due to the default non-local viewer that OpenGL uses. By default the eye-space view vector (the vector from vertex to camera, used for the specular highlight computation) is just taken to be the (0, 0, 1)-vector, instead of the normalized vertex position. This approximation is only correct if the vertex is in the middle of the screen, but gets more and more incorrect the farther you move to the boundary of the srceen.

To change this and let OpenGL use the real vector from the vertex to the camera, just use the glLightModel function, especially

glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

I'm not sure if this is also the cause for your first problem (with the sphere), but maybe, just try it.

编辑:看来你不能GL_LIGHT_MODEL_LOCAL_VIEWER在 OpenGL ES 中使用。在这种情况下,除了切换到 OpenGL ES 2.0 并自己进行所有光照计算之外,没有办法解决这个问题。

于 2011-11-09T13:39:47.750 回答
0

当您移动物体时,您的灯光可能正在移动。

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

于 2011-11-09T11:48:53.310 回答