Как правильно использовать освещение в JOGL? - PullRequest
0 голосов
/ 30 мая 2018

Ниже приведена небольшая демонстрация проблемы, с которой я столкнулся в моем реальном проекте.

Мой метод отображения выглядит следующим образом:

@Override
public void display(GLAutoDrawable drawable) {
    gl2.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);

    gl2.glEnable(GL2.GL_DEPTH_TEST);
    gl2.glEnable(GL2.GL_LIGHTING);

    gl2.glMatrixMode(GL2.GL_MODELVIEW);
    gl2.glLoadIdentity();

    gl2.glMatrixMode(GL2.GL_PROJECTION);
    gl2.glLoadIdentity();

    gl2.glMatrixMode(GL2.GL_MODELVIEW);
    glu.gluLookAt(10, 10, 11, 10, 10, 9, 0, 1, 0);
    gl2.glMatrixMode(GL2.GL_PROJECTION);
    glu.gluPerspective(90, 1, 0.1, 1000.1);
    gl2.glMatrixMode(GL2.GL_MODELVIEW);

    gl2.glRotated(angle++, 0, 1, 0);

    light();

    wall1();
    wall2();
    wall3();

    gl2.glFlush();
}

Источник света расположен в серединепейзаж:

private void light() {
    float[] position = { 10, 10, 20, 1 };
    gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, position, 0);

    gl2.glEnable(GL2.GL_LIGHT0);
}

пейзаж состоит из трех стен:

private void wall1() {
    float[] colors = { 0, 1, 0, 1 };
    gl2.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE, colors, 0);

    gl2.glBegin(GL2.GL_QUADS);

    for (int i = 0; i < 20; i++) {
    for (int j = 0; j < 20; j++) {
        gl2.glNormal3d(0, 0, 1);
        gl2.glVertex3d(i, j, 0);

        gl2.glNormal3d(0, 0, 1);
        gl2.glVertex3d(i + 1, j, 0);

        gl2.glNormal3d(0, 0, 1);
        gl2.glVertex3d(i + 1, j + 1, 0);

        gl2.glNormal3d(0, 0, 1);
        gl2.glVertex3d(i, j + 1, 0);
    }
    }

    gl2.glEnd();
}

private void wall2() {
    float[] colors = { 0, 1, 0, 1 };
    gl2.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE, colors, 0);

    gl2.glBegin(GL2.GL_QUADS);

    for (int i = 0; i < 20; i++) {
    for (int j = 0; j < 40; j++) {
        gl2.glNormal3d(-1, 0, 0);
        gl2.glVertex3d(20, i, j);

        gl2.glNormal3d(-1, 0, 0);
        gl2.glVertex3d(20, i + 1, j);

        gl2.glNormal3d(-1, 0, 0);
        gl2.glVertex3d(20, i + 1, j + 1);

        gl2.glNormal3d(-1, 0, 0);
        gl2.glVertex3d(20, i, j + 1);
    }
    }

    gl2.glEnd();
}

private void wall3() {
    float[] colors = { 0, 1, 0, 1 };
    gl2.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE, colors, 0);

    gl2.glBegin(GL2.GL_QUADS);

    for (int i = 0; i < 20; i++) {
    for (int j = 0; j < 20; j++) {
        gl2.glNormal3d(0, 0, -1);
        gl2.glVertex3d(20 - i, j, 40);

        gl2.glNormal3d(0, 0, -1);
        gl2.glVertex3d(20 - i - 1, j, 40);

        gl2.glNormal3d(0, 0, -1);
        gl2.glVertex3d(20 - i - 1, j + 1, 40);

        gl2.glNormal3d(0, 0, -1);
        gl2.glVertex3d(20 - i, j + 1, 40);
    }
    }

    gl2.glEnd();
}

Наконец, результат выглядит так:

result

Вы можете видеть, что большая стена (wall2) в центре освещена, как и ожидалось, в то время как две маленькие стены слева (wall1) и справа (wall3) кажутсяполучить максимальный свет, который мне не кажется реалистичным.

Как мне решить эту проблему?

Заранее спасибо!

1 Ответ

0 голосов
/ 30 мая 2018

Устаревшая стандартная модель освещения в OpenGL супер элементарна.Он будет использовать как расстояние, так и угол, чтобы уменьшить количество света, получаемого поверхностью от вашего источника света.В этом случае дальние концы большей поверхности получают меньше света, чем меньшие поверхности, потому что свет находится под более острым углом.

Другая проблема заключается в том, что OpenGL рассчитает значение освещения для каждой вершины и затем интерполирует значения длякаждый пиксель, что дает разные результаты в зависимости от размера и расположения граней и их вершин.

Да, это выглядит нереально, что является одной из многих причин, по которым вам не следует использовать устаревшие и устаревшие функции.Если вы застряли с использованием устаревших функций OpenGL, вы застряли с таким плохим освещением.

Вы можете поиграть с GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION и GL_QUADRATIC_ATTENUATION, чтобы получить наилучший результат для конкретного рендерингасцены, или вы можете попробовать использовать точечные светильники вместо позиционных источников света, но вы, вероятно, никогда не получите идеальное решение.См. документы для glLight .

Вы также можете попытаться изменить размер и расположение ваших граней / вершин, чтобы подтолкнуть результат интерполяции к тому, что вы хотите.

Однако правильным решением было бы реализовать собственное пиксельное освещение с помощью шейдеров или использовать стороннюю библиотеку, обеспечивающую правильное освещение.

...