Подтвердить что ты не робот

Как сделать убедительный skydome?

Я пишу приложение OpenGL ES 2.0, которое отображает 3D-остров. У меня уже есть код для создания купола неба вокруг острова. Это полушарие, состоящее из треугольников, над которыми лежал остров с точкой z вверх.

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

Но в конечном итоге мне нужен купол, который также отображает:

  • Солнце (которое проходит по небу) Луна (включая фазу)
  • Звезды (ночью)
  • Отдаленная земля как статическая текстура
  • Различные цвета для имитации ночи, рассвета, сумерек, дня

Мне нужно сделать это достаточно эффективно, так как это закончится на Android, хотя на данный момент он работает в тестовом жгуте. Таким образом, солнце, луна и звезды, например, будут просто текстурами, хотя их точки могут быть построены с разумной точностью.

У меня уже есть код для создания купола и код для построения солнца против даты и времени. Так что в основном это шейдеры, которые мне нужны, и то, с чем они поставляются.

Есть ли какой-нибудь пример, демонстрирующий эти вещи? Я нашел много, которые делают базовые кубические карты или ограниченный материал, но не до уровня сложности, в которой я нуждаюсь. Очевидно, поскольку это OpenGL ES 2.0, это нужно делать в шейдерах.

Шейдер для моего существующего купола неба создает 2 слоя перлинского шума для имитации облаков. Текстура непрерывно обтекает, поэтому я могу вычислить смещение u на основе угла вершины купола в плоскость xy (путем подачи x и y в atan) и смещения v с использованием вершины купола z.

Вершинный шейдер демонстрирует, как я это делаю:

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

attribute vec4 aVertex;

uniform mat4 uPMVMatrix;
uniform float uTime;
uniform float uSkyDomeRadius;

const float PI = 3.1415926535897932384626433832795;

varying vec2 texCoord0, texCoord1;

void main()
{
    vec2 centre = vec2(600., 600.);

    gl_Position = uPMVMatrix * aVertex;

    float slow_time = uTime / 100.;

    vec2 dome_point = aVertex.xy - centre;
    float tex_u = atan(dome_point.x, dome_point.y);// / (.25 * PI);
    float tex_v = aVertex.z / (uSkyDomeRadius * .5);

    texCoord0 = vec2(tex_u / 2.0 + slow_time, tex_v / 2.0);
    texCoord1 = vec2(tex_u + slow_time / 2.0, tex_v);
}

Я также использую время для смещения u бит каждого кадра, чтобы облака двигались. Это отлично работает, за исключением того, что atan переходит от -PI к PI, и внезапно значения texCoord0 и texCoord1 интерполяторы фрагментарного фрагмента разделены большим расстоянием, которое шунтирует интерполяцию.

Лучший способ описать это состоит в том, что если у меня есть 16 треугольников на моей базе, то интерполяция от 0/16 до 1/16 работает, от 1/16 до 2/16 работает и так далее. Но когда я добираюсь до 15/16 до 0/16, интерполятор идет назад, и большая вариация заставляет фрагмент-шейдер повторять текстуру снова и снова в небольшом пространстве, ведущем к полосам, как показано.

Interpolation goes haywire as angle goes into reverse

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

Рабочий пример с источником был бы большим, особенно если он решает эти проблемы.

4b9b3361

Ответ 1

Проблема заключается в том, что вы используете одни и те же вершины под углом 0 ° и 360 °. Итак, теперь у вас есть треугольник, где первая вершина имеет координату текстуры 15/16, 0, а вторая - 0, 0 вместо 1,0. Чтобы исправить это, вам нужно открыть сферу, чтобы у вас была пара вершин в одинаковых пространственных положениях, одна для 0 ° и одна для 360 °. Таким образом, две вершины могут иметь разные координаты текстуры, и не будет никаких нарушенных текстур.

Чтобы повернуть их, вы должны использовать режимы обертывания, убедитесь, что текстурная упаковка настроена на повторение. Если вы его не изменили, его следует настроить правильно, но его можно установить с помощью функции glTexParameter, параметры GL_TEXTURE_WRAP_S и GL_TEXTURE_WRAP_T, а значение должно быть GL_REPEAT. Тогда, если значение текстуры > 1, оно не обернется, а повторит текстуру. Теперь вам нужно только указать вершины в начале сферы (для вершин в 0 °) от тех, что на конце (для вершин на 360 °), чтобы вы могли исправить tex_u, вам, вероятно, понадобится дополнительный атрибут для этого.