Почему мой шейдерный свет GLSL перемещается по сцене вместе с объектами, на которые он светит? - PullRequest
4 голосов
/ 25 августа 2011

Я следую учебнику по OpenGL ES 2.0 и комбинирую его с учебником по освещению GLSL , которое я нашел, используя удобный чайник из Юты из developer.apple.com.

После долгих потрясений и экспериментов у меня заварен чайник на экране в меру правильно, вращаясь вокруг всех трех осей с помощью «затенения мультфильмов» из учебного пособия по освещению. В геометрии есть несколько глюков из-за того, что я просто рисую весь список вершин в виде треугольных полос (если вы посмотрите в файл teapot.h, там будет встроен '-1', где я должен начать новые треугольные полоски, но это только данные испытаний и не имеют отношения к моей проблеме).

Что меня действительно смущает, так это то, как расположить источник света на сцене. В моем коде Objective-C у меня есть вектор с плавающей точкой 3 , который содержит {0,1,0}, и я передаю его в шейдер, чтобы затем рассчитать интенсивность света.

Почему свет появляется в сцене тоже? Я имею в виду, что свет действует так, как будто он прикреплен к чайнику невидимой палочкой, всегда указывая на одну и ту же сторону, независимо от того, в каком направлении смотрит чайник.

Это вершинный шейдер

attribute vec4 Position;
attribute vec4 SourceColor;
attribute vec3 Normal;

uniform mat4 Projection;
uniform mat4 Modelview;

varying vec3 normal;

void main(void) {
    normal = Normal;
    gl_Position = Projection * Modelview * Position;
}

«Положение» задается кодом Obj-C и является вершинами для объекта, «Норма» - это список нормалей как из массива вершин (VBO), так и «Проекция» и «Вид модели» рассчитываются следующим образом :

(CC3GLMatrix из библиотеки Cocos3D, упомянутой в учебном пособии GLES, связанном выше)

CC3GLMatrix *projection = [CC3GLMatrix matrix];
float h = 4.0f * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:1 andFar:100];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);

CC3GLMatrix *modelView = [CC3GLMatrix matrix];
[modelView populateFromTranslation:CC3VectorMake(0, 0, -7)];
[modelView scaleBy:CC3VectorMake(30, 30, 30)];

_currentRotation += displayLink.duration * 90;
[modelView rotateBy:CC3VectorMake(_currentRotation, _currentRotation, _currentRotation)];

glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);

И я установил свет в сцене, выполнив

float lightDir[] = {1,0,1};
glUniform3fv(_lightDirUniform, 1, lightDir);

Фрагмент шейдера выглядит так

varying lowp vec4 DestinationColor; // 1
varying highp vec3 normal;
uniform highp vec3 LightDir;


void main(void) {
    highp float intensity;
    highp vec4 color;
    intensity = dot(LightDir,normal);
    if (intensity > 0.95)
        color = vec4(1.0,0.5,0.5,1.0);
    else if (intensity > 0.5)
        color = vec4(0.6,0.3,0.3,1.0);
    else if (intensity > 0.25)
        color = vec4(0.4,0.2,0.2,1.0);
    else
        color = vec4(0.2,0.1,0.1,1.0);

    gl_FragColor = color;
}

Пытаясь решить эту проблему, я сталкиваюсь с кодом, который ссылается на (несуществующий в GLES) gl_LightSource и gl_NormalMatrix, но не знает, что поместить в эквиваленты, которые я должен передать в шейдеры из своего кода. , Ссылки на «пространство глаза», «пространство камеры», «пространство мира» и т. Д. Сбивают с толку, я знаю, что, вероятно, мне следует конвертировать вещи между ними, но не понимаю, почему и как (и где - в коде или в шейдере ?)

В каждом кадре мне нужно изменить источник света? Код для настройки выглядит слишком упрощенно. На самом деле я не двигаю чайник, вместо этого я перемещаю всю сцену - свет и все вокруг?

1 Ответ

5 голосов
/ 25 августа 2011

Прежде всего, некоторые определения:

  • мировое пространство: пространство, в котором определяется весь ваш мир. По соглашению это статическое пространство, которое никогда не движется.

  • просмотр пространства / пространства камеры / пространства глаза: пространство, в котором определяется ваша камера. Обычно это положение и поворот относительно мирового пространства

  • пространство модели:пространство, в котором определяется ваша модель. Как и пространство камеры, обычно это положение и поворот относительно мирового пространства

  • световое пространство: то же, что пространство модели

В простых примерах (и, я полагаю, в ваших) модель пространства и мировое пространство совпадают.Кроме того, OpenGL сам по себе не имеет понятия мирового пространства, что не означает, что вы не можете его использовать.Это удобно, когда вы хотите, чтобы в вашей сцене независимо перемещалось более одного объекта.

Теперь то, что вы делаете со своим объектом перед рендерингом, - это создание матрицы, которая преобразует вершины модели в пространство вида.отсюда «modelViewMatrix».

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

Это делается путем вычисления чего-то вроде:

_lightDirUniform = inverseMatrix(model) * inverseMatrix(light) * lightPosition;

Положение освещения преобразуется изсвет в мир, а затем в модельное пространство.Если у вас нет мирового пространства, просто не используйте трансформацию модельного пространства, и все будет в порядке.

...