Рубрики
Без рубрики

Воссоздание классического Starfield в GLSL & Three.js

Звездное поле было одним из первых вещей, которые я построил, когда учится программировать. Это было довольно некоторое время … Помечено GLSL, Thrijs, JavaScript.

А Звездное поле Была ли одна из первых вещей, которые я построил, когда учится программировать. Теперь было довольно некоторое время, и я начал изучать программирование шейдеров с GLSL и Threy.js. Поэтому я решил, почему не вернуться туда, куда все это началось!

Если вы спешите и просто хотите увидеть, что я собрал вместе, вы можете посмотреть на Последний продукт здесь и просмотр репозитория GitHub здесь Действительно

(Я бы бросил Гиф, но вы не могли сделать то, что происходит 🤷♂️)

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

Кроме того, есть много скучного кода прокладки, чтобы все запустить, поэтому все GLSL здесь перефразированы для вашего удовольствия (и мое собственное здравомыслие). Посмотрите на Репозиторий для реального кода.

Часть 1 – Классический подход

Давайте начнем с самых прямых способов сделать это, грубый GLSL-порт того, что вы можете написать в JavaScript:

// Loop through all the stars we want
for (int i = 0; i < STAR_COUNT; i++) {
    // Give the star a random position
    vec2 star = vec2((random(i) - 0.5) * 2.0, (random(i) - 0.5) * 2.0);

    // Get the direction from the center to the star, and scale it by time and a random offset
    star = normalize(star) * mod(time + random(float(i) * 16.0), 1.414214);

    // If the star is within 0.1% if the viewport size then draw it as white
    if (distance(screenPosition, star) < 0.001) {
        color = vec3(1, 1, 1);
        break;
    }
}

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

for (let pixel of screen) {
    for (let star of stars) {
        ...code
    }
}

Это ужасно неэффективно!

Так как мы можем сделать это более исполнителю, и, возможно, сделать его еще лучше?

Часть 2 – Давайте сделаем это лучше!

Для того, чтобы сделать эту вещь потрясающе, нам нужно будет исправить самую большую проблему. Итерация более сотен звезд.

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

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

Поскольку «ломтики» не будут двигаться, мы могли бы карту Экранпозиция на ломтике и выяснить, какую звезду обрабатывать:

vec2 direction = normalize(floor(normalize(screenPosition) * STAR_DENSITY) / STAR_DENSITY)

Мы можем определить Star_density Для количества ломтиков мы хотим.

Теперь вместо использования Я Чтобы выяснить смещение звезд, мы можем конвертировать направление С точки зрения поплавка и использовать это вместо этого:

// I'm using `scale` because `distance` is a built-in method
float scale = mod(time + random(direction.x + direction.y * 10.0), 1.414214);

С направление и а масштаб Мы теперь определили нашу звезду, используя полярные координаты, используя только Экранпозиция Действительно

Теперь мы можем сделать наш проверкой расстояние, как это:

if (abs(scale - distance(screenPosition, vec3(0, 0, 0)) < 0.001) {
    ...
}

🎉 TADA, миссия достигнута! Теперь мы не только улучшенные производительность, но создали супер густую визуализацию Starfield, которую вы не могли делать в JavaScript!

Спасибо за чтение, я надеюсь, что вам понравилось статью, я стремлюсь сделать больше из них (надеюсь, лучше) Так что, если у вас есть какие-либо отзывы, пожалуйста, дайте мне знать!

Оригинал: “https://dev.to/jessesolomon/recreating-a-classic-starfield-in-glsl-three-js-ii”