Почему мой шейдерный свет GLSL перемещается по сцене вместе с объектами, на которые он светит?

Я следую учебному пособию по 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 ответ

Решение

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

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

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

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

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

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

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

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

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

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

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

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