OpenGL ES 1.1 странные проблемы с освещением

Я изучаю интересную проблему с освещением OpenGL на Android. Я работаю над 3D Viewer, где вы можете добавлять и управлять 3D-объектами. Вы также можете установить свет с различными атрибутами. Проблема, с которой я столкнулся при работе со своим средством просмотра, заключалась в том, что выделение на трехмерных объектах от источника света (это точечный источник света) вели себя странно. Если источник света находится точно в той же точке, что и камера, выделение будет двигаться в направлении, противоположном ожидаемому. (Таким образом, если вы переместите объект влево, выделение также переместится на левую сторону объекта, а не вправо, что я и ожидал.)

Подсветка внизу слева, тогда как я ожидаю, что она будет справа

Итак, чтобы еще больше сузить проблему, я создал небольшое примерное приложение, которое визуализирует только квадрат, а затем поворачиваю этот квадрат вокруг положения камеры (начала координат), где также размещается свет. Это должно привести к тому, что все квадраты будут обращены непосредственно к камере, чтобы они были полностью выделены. Результат выглядел так:

Осветительные приборы

Может ли быть так, что эти артефакты появляются из-за искажения, которое вы получаете на границе из-за проекции?

На первом изображении расстояние между сферой и камерой составляет около 20 единиц, а размер сферы составляет около 2. Если я подвину свет ближе к объекту, то подсветка будет выглядеть намного лучше, как я и ожидал, На втором изображении радиус, в котором расположены квадраты, составляет 25 единиц. Я использую OpenGL ES 1.1 (так как я изо всех сил пытался заставить его работать с шейдерами в ES 2.0) на Android 3.1

Вот часть кода, который я использую:

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 ответа

Решение

Эффект во втором примере (с квадратами) скорее связан с нелокальным средством просмотра по умолчанию, которое использует OpenGL. По умолчанию вектор обзора пространства глаза (вектор от вершины до камеры, используемый для вычисления зеркального выделения) просто считается (0, 0, 1)-вектором вместо нормализованной позиции вершины. Это приближение является правильным только в том случае, если вершина находится в середине экрана, но становится все более и более неправильным по мере того, как вы двигаетесь к границе объекта.

Чтобы изменить это и позволить OpenGL использовать реальный вектор от вершины до камеры, просто используйте glLightModel функция, особенно

glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

Я не уверен, что это также является причиной вашей первой проблемы (со сферой), но, возможно, просто попробуйте.

РЕДАКТИРОВАТЬ: Кажется, вы не можете использовать GL_LIGHT_MODEL_LOCAL_VIEWER в OpenGL ES. В этом случае нет способа обойти эту проблему, кроме как перейти на OpenGL ES 2.0 и, конечно, самостоятельно выполнить все вычисления освещения.

Ваш свет, вероятно, движется, когда вы перемещаете свой объект.

Посмотрите на этот ответ http://www.opengl.org/resources/faq/technical/lights.htm

Другие вопросы по тегам