简体   繁体   English

OpenGL ES 1.1奇怪的照明问题

[英]OpenGL ES 1.1 strange lighting problems

I am examining an interesting problem I'm facing with OpenGL lighting on Android. 我正在研究Android上的OpenGL照明面临的一个有趣问题。 I'm working on a 3D Viewer where you can add and manipulate 3D objects. 我正在使用3D查看器,您可以在其中添加和操作3D对象。 You can also set a light with different attributes. 您还可以设置具有不同属性的灯光。 The problem I was facing with my Viewer was that the highlight on the 3D objects from the light (it is a point light) behaved strangely. 我的查看器面临的问题是灯光(这是点光源)在3D对象上的高光表现异常。 If the light source was in the exact same point as the camera, the highlight would move in the opposite direction you would expect. 如果光源与相机位于同一点,则高光将朝您期望的相反方向移动。 (So if you move the object to the left, the highlight moves to the leftedge of the object as well, instead of the right, which is what I was expecting.) (因此,如果将对象向左移动,高光也将移动到对象的左边缘,而不是右边,这正是我所期望的。)

突出显示在左下方,而我希望它在右侧

So to further narrow the problem down I've created a small sample application that only renders a square and then I rotate that square around the camera position (the origin), which is also where the light is placed. 因此,为了进一步缩小问题的范围,我创建了一个小的示例应用程序,该应用程序仅渲染一个正方形,然后围绕相机位置(原点)(也就是放置光源的位置)旋转该正方形。 This should result in all squares facing the camera directly, so that they would be completely highlighted. 这应该使所有正方形都直接面对相机,以便将它们完全突出显示。 The result though looked like that: 结果看起来像这样:

灯光

Can it be that these artifacts appear because of the distortion you get on the border due to the projection? 这些伪影是否可能是由于投影导致您在边界上得到的失真而出现的?

In the first image the distance between the sphere and the camera is about 20 units and the size of the sphere is about 2. If I move the light closer to the object the highlight looks a lot better, in the way I'm expecting it. 在第一个图像中,球体与摄影机之间的距离约为20个单位,球体的大小约为2个单位。如果我将光移近物体,则高光看起来会好很多,这与我预期的方式相同。 In the second image the radius in which the squares are located is 25 units. 在第二张图像中,正方形所在的半径为25个单位。 I'm using OpenGL ES 1.1 (since I was struggling to get it to work with shaders in ES 2.0) on Android 3.1 我正在Android 3.1上使用OpenGL ES 1.1(因为我一直在努力使其与ES 2.0中的着色器一起使用)

Here is some of the code I'm using: 这是我正在使用的一些代码:

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

I'm setting the light in the beginning, when the activity is started (in onSurfaceCreated) and the material everytime I draw a square. 在开始活动时(在onSurfaceCreated中)和每次我绘制一个正方形的材质时,我都会在开始时设置灯光。

The effect in your second example (with the squares) is rather due to the default non-local viewer that OpenGL uses. 在第二个示例中(带有正方形)的效果是由于OpenGL使用的默认非本地查看器。 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. 默认情况下,仅将眼睛空间视图矢量(从顶点到相机的矢量,用于镜面高光计算)取为(0,0,1)-矢量,而不是归一化的顶点位置。 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 要更改此设置并让OpenGL使用从顶点到相机的真实矢量,只需使用glLightModel函数,尤其是

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. 我不确定这是否也是您遇到的第一个问题(与球体有关)的原因,但也许可以尝试一下。

EDIT: It seems you cannot use GL_LIGHT_MODEL_LOCAL_VIEWER in OpenGL ES. 编辑:似乎您不能在OpenGL ES中使用GL_LIGHT_MODEL_LOCAL_VIEWER In this case there is no way around this problem, except switching to OpenGL ES 2.0 and doing all lighting computations yourself, of course. 当然,在这种情况下,除了切换到OpenGL ES 2.0并自己进行所有光照计算外,没有其他方法可以解决此问题。

Your light is probably moving when you're moving your object. 当您移动物体时,灯光可能正在移动。

Take a look at this answer http://www.opengl.org/resources/faq/technical/lights.htm#ligh0050 看看这个答案http://www.opengl.org/resources/faq/technical/lights.htm#ligh0050

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM