Проблемы с освещением OpenGL в Java/lwjgl

Я создал сцену с вращающимся кубом в Java/lwjgl. Если я включаю освещение, я получаю реалистичное поведение, как будто источник света находится в положении камеры, независимо от того, где я размещаю свой источник света.

Вот мой метод инициализации openGL:

private void initGL() throws LWJGLException {
    Display.create();
    Display.setFullscreen(true);
    Display.setVSyncEnabled(true);

    GL11.glViewport(0, 0, WIDTH, HEIGHT);
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GLU.gluPerspective(70, 4f / 3f, 1, 10000);
    GL11.glMatrixMode(GL11.GL_MODELVIEW);

    GL11.glEnable(GL11.GL_DEPTH_TEST);
    GL11.glDepthMask(true);

    GL11.glEnable(GL11.GL_CULL_FACE);

    // ----IMPORTANT PART----
    GL11.glEnable(GL11.GL_LIGHTING);
    GL11.glEnable(GL11.GL_LIGHT0);

    FloatBuffer position = ByteBuffer.allocateDirect(16).asFloatBuffer();
    position.mark();
    position.put(new float[] { -5f, 5f, 10f, 0f }); // even values about 10e3 for the first three parameters aren't changing anything
    position.reset();

    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, position);

    FloatBuffer ambient = ByteBuffer.allocateDirect(16).asFloatBuffer();
    ambient.mark();
    ambient.put(new float[] { 0.5f, 0.5f, 0.5f, 1f });
    ambient.reset();

    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_AMBIENT, ambient);

    // Textures...
}

С помощью этого фрагмента кода вызывается, когда я начинаю рендеринг:

private void renderGL() {
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

    for (RenderObject ro : renderObjects) {
        ro.render();
    }
}

И это рисует куб. Я думаю, что нормали правильные, если их поменять местами, лицо не будет отрисовываться, по крайней мере, в моих тестах.

public void render() {
    GL11.glEnable(GL11.GL_TEXTURE_2D);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID);
    GL11.glColor3f(1f, 1f, 1f);

    GL11.glPushMatrix();

    GL11.glTranslatef(x, y, z);
    GL11.glRotatef(rotation, 1, 1, 1);
    GL11.glTranslatef(-x, -y, -z);

    GL11.glBegin(GL11.GL_QUADS);

    GL11.glNormal3f(0, 0, -1f);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex3f(x - dx, y - dy, z - dz);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex3f(x - dx, y + dy, z - dz);
    GL11.glTexCoord2f(1, 1);
    GL11.glVertex3f(x + dx, y + dy, z - dz);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex3f(x + dx, y - dy, z - dz);

    // the other five faces

    GL11.glEnd();

    GL11.glPopMatrix();
}

Что я делаю не так с подсветкой?

EDIT: дополнительная информация об ошибке

Когда я устанавливаю последнее значение массива положения источника света в 0, вся сцена становится черной. Если установить любое другое значение, свет будет выходить из окна просмотра, как описано. Окружающий свет ничего не меняет, куб, который я хочу нарисовать, остается темным, когда источник света не работает. Я попытался поместить элементы освещения в другие позиции в коде, например. непосредственно после строки GLU.gluPerspective(70, 4f / 3f, 1, 10000); или в цикле, не меняя ни одного из описанных эффектов.


person Sibbo    schedule 01.01.2012    source источник


Ответы (1)


Что я делаю не так с подсветкой?

Положение освещения умножается на матрицу просмотра модели. Таким образом, вы должны вызывать glLightfv(GL_LIGHT_, GL_POSITION, …); сразу, когда ваша матрица просмотра модели содержит преобразование просмотра.

Технически все, что вы написали в этой функции initGL, относится к функции рисования. OpenGL — это не граф сцены, который вы инициализируете.

Обновлять:

Измените свой код следующим образом:

public void render() {
    GL11.glEnable(GL11.GL_TEXTURE_2D);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID);
    GL11.glColor3f(1f, 1f, 1f);

    GL11.glPushMatrix();

    // this is where you set up your view:
    GL11.glTranslatef(x, y, z);
    GL11.glRotatef(rotation, 1, 1, 1);
    GL11.glTranslatef(-x, -y, -z);

    // and now it's time to set the light position:
    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, position);

    GL11.glBegin(GL11.GL_QUADS);

    GL11.glNormal3f(0, 0, -1f);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex3f(x - dx, y - dy, z - dz);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex3f(x - dx, y + dy, z - dz);
    GL11.glTexCoord2f(1, 1);
    GL11.glVertex3f(x + dx, y + dy, z - dz);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex3f(x + dx, y - dy, z - dz);

    // the other five faces

    GL11.glEnd();

    GL11.glPopMatrix();
}

Затем вы должны полностью удалить initGL, переместить его код в функцию рисования, превратив его в:

public void render() {

    GL11.glViewport(0, 0, WIDTH, HEIGHT);

    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GLU.gluPerspective(70, 4f / 3f, 1, 10000);

    GL11.glMatrixMode(GL11.GL_MODELVIEW);   
    glLoadIdentity();
    GL11.glPushMatrix();

    // this is where you set up your view:
    GL11.glTranslatef(x, y, z);
    GL11.glRotatef(rotation, 1, 1, 1);
    GL11.glTranslatef(-x, -y, -z);

    // and now it's time to set the light position:
    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, position);

    // we do the rest of the light here as well
    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_AMBIENT, ambient);

    GL11.glEnable(GL11.GL_DEPTH_TEST);
    GL11.glDepthMask(true);
    GL11.glEnable(GL11.GL_CULL_FACE);

    // we enable lighting right before rendering
    GL11.glEnable(GL11.GL_LIGHTING);
    GL11.glEnable(GL11.GL_LIGHT0);    

    GL11.glEnable(GL11.GL_TEXTURE_2D);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID);

    GL11.glColor3f(1f, 1f, 1f);

    GL11.glBegin(GL11.GL_QUADS);

    GL11.glNormal3f(0, 0, -1f);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex3f(x - dx, y - dy, z - dz);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex3f(x - dx, y + dy, z - dz);
    GL11.glTexCoord2f(1, 1);
    GL11.glVertex3f(x + dx, y + dy, z - dz);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex3f(x + dx, y - dy, z - dz);

    // the other five faces

    GL11.glEnd();

    GL11.glPopMatrix();
}
person datenwolf    schedule 01.01.2012
comment
Спасибо за Ваш ответ! Метод GL11.glLight() — это lwjgl-версия метода glLightfv() в C. Пожалуйста, посмотрите мое редактирование, я думаю, что раньше я неправильно описал свою проблему. - person Sibbo; 01.01.2012
comment
@Sibbo: Вы должны установить положение света сразу после настройки матрицы view. Это не проекция. Смотрите мой ответ редактировать. - person datenwolf; 01.01.2012
comment
Итак, матрица, которую я использовал с glRotation, вращает представление вокруг куба, а не куб вокруг представления? Потому что переменные x, y и z — это координаты куба, и вращение должно вращать куб вокруг оси 1/1/1. - person Sibbo; 02.01.2012
comment
@Sibbo: Ну, технически вы перемещаете только куб. В OpenGL нет такой вещи, как камера. Но если подумать, перемещение камеры — это то же самое, что перемещение мира в обратном направлении. Матрица представления модели сочетает в себе преобразование модели и преобразование представления, следовательно, представление модели. Проекционную матрицу можно представить как линзу OpenGL. - person datenwolf; 02.01.2012
comment
Ах, спасибо :) Но я только что обнаружил свою проблему, где в другом месте кода ничего не скопировано сюда... Я неправильно создал FloatBuffers, не используя flip() и order(). Теперь все работает, но источник света вращается вместе с кубом :) но теперь я могу работать сам, спасибо. - person Sibbo; 02.01.2012
comment
@Sibbo: чтобы источник света не вращался вместе с кубом, установите положение источника света перед настройкой вращения куба. До сих пор я думал, что ты вращаешь камеру вокруг куба. - person datenwolf; 02.01.2012
comment
Вчера я немного поработал над этим, теперь я могу эффективно использовать метод push и popMatrix() :) Теперь я застрял на оптимизации, но это было бы ОТ. Спасибо за вашу помощь :) - person Sibbo; 02.01.2012