#android #opengl-es #opengl-es-lighting
#Android #opengl-es #opengl-es-освещение
Вопрос:
Я изучаю интересную проблему, с которой я столкнулся при использовании OpenGL lighting на Android. Я работаю над 3D-средством просмотра, в котором вы можете добавлять 3D-объекты и манипулировать ими. Вы также можете установить источник света с различными атрибутами. Проблема, с которой я столкнулся со своим Зрителем, заключалась в том, что подсветка 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) и материал каждый раз, когда я рисую квадрат.
Комментарии:
1. Было бы очень полезно увидеть фрагмент кода шейдера, который вы используете для затенения объектов, и откуда берутся его параметры.
2. Поскольку я использую OpenGL ES 1.1 в обоих примерах, я не использую шейдеры. ES 1.1 использует конвейер фиксированных функций. Я собираюсь обновить сообщение небольшим количеством кода, в котором я передаю параметры в OpenGL.
Ответ №1:
Эффект во втором примере (с квадратами) скорее связан с нелокальным средством просмотра по умолчанию, которое использует OpenGL. По умолчанию вектор обзора в пространстве для глаз (вектор от вершины к камере, используемый для вычисления зеркальной подсветки) просто принимается за (0, 0, 1)-вектор вместо нормализованного положения вершины. Это приближение верно только в том случае, если вершина находится в середине экрана, но становится все более и более неправильным, чем дальше вы продвигаетесь к границе srceen.
Чтобы изменить это и позволить OpenGL использовать реальный вектор от вершины к камере, просто используйте glLightModel
функцию, особенно
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
Я не уверен, что это также является причиной вашей первой проблемы (со сферой), но, возможно, просто попробуйте.
РЕДАКТИРОВАТЬ: кажется, вы не можете использовать GL_LIGHT_MODEL_LOCAL_VIEWER
в OpenGL ES. В этом случае нет никакого способа обойти эту проблему, кроме переключения на OpenGL ES 2.0 и, конечно, выполнения всех вычислений освещения самостоятельно.
Комментарии:
1. Это именно то, о чем мы подумали после некоторого обсуждения, и мы также поняли, что это недоступно в OpenGL ES. На самом деле это не имеет большого значения, поскольку в реальном приложении я буду использовать OpenGL ES 2.0. Я просто хотел сравнить, как он отображает свет с помощью фиксированного конвейера, потому что с OpenGL ES 2.0 я столкнулся с некоторыми странными ситуациями. Но в этом случае ES 1.1 мне не очень помогает. В любом случае спасибо!
2. Кстати, мы также попробовали это на компьютере с Windows с OpenGL (не ES), и именно в этом и заключалась проблема. Как только мы изменили модель освещения, она выглядела правильно. Просто для дальнейшего использования.
Ответ №2:
Вероятно, ваш источник света движется, когда вы перемещаете свой объект.
Взгляните на этот ответ http://www.opengl.org/resources/faq/technical/lights.htm#ligh0050
Комментарии:
1. В его текущей настройке свет всегда будет направлен на камеру, что кажется именно тем, что он хочет, учитывая текст его вопроса.