А Звездное поле Была ли одна из первых вещей, которые я построил, когда учится программировать. Теперь было довольно некоторое время, и я начал изучать программирование шейдеров с 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”