Отказ от ответственности: я бэкендщик бывший.
Предлагаю представить, что в каждой точке пространства находится число, обозначающее расстояние от этой точки до ближайшей поверхности (стены, кота) в метрах. В этом месте ваш ум может начать придумывать ненужные вопросы, ударьте его. Просто куча чисел висит в воздухе, загораживает. На стенах нули, на потолке тоже ноли, к центу увеличиваются. Не в размере. А в центре ~1.3, или какая там высота потолков. И ничего больше нет, кроме чисел. Это signed distance field.
Про signed distance field я знаю две вещи:
1. Мы можем научиться писать функцию, которая будет создавать его из пустоты и линейной алгебры.
2. Мы знаем, как его красиво визуализировать.
Второе не интересно, остановимся на первом: надо написать функцию, которая будет принимать на вход точку в пространстве (в виде вектора, vec3(1, 6, -4.22)), и возвращать расстояние от этой точки до ближайшего из наших… с вами… объектов. Функция с одним параметром типа vec3, у ней внутре описана куча объектов сцены: земля, сфера, мандельбульб, и мы берём, и прям по каждому:
— а ты далеко от этого вектора, земля?
— я земля, я не очень далеко
— хмм, а ты, сфера, от этой точки дальше земли, или ближе?
— оо, я сфера, я чуть ближе
— ммм, да, ты плохая девочка, позже к тебе вернусь. А ты, мандельбульб, как ты расположен?
— а я мандельбульб, я ближе всех
и возвращаем расстояние до мандельбульба, загородил.
Потом чтобы построить картинку, нужно будет вызвать эту функцию много-много раз в разных точках, а в каких точках — знает функция с реализацией сабжевого реймаршинга, она будет лежать рядом с нашей, алгоритм внизу под спойлером, не важно.
Домик на бейсике рисовали?
Чтобы не треснуло, работать должно на видеокарте, всё-равно напокупали, майнеры мамкины. Будем использовать three.js и коробку, обтянутую тугим ShaderMaterial. Чтобы не морочиться с настройкой сцены и движком, над three.js есть aframe, который леньсоздатьpackagejson импортируем с цдн. Aframe — это такое юнити для бедных вэба. Очень мощная штука. Там компонент создаёшь просто, и всё, можно ни о чём не думать. А, и не будем же мы по такой ерунде свой дев сервер поднимать? Вот glitch, вот проект, в проекте пример, надеюсь, он заработает больше, чем у половины. Я бы ещё это в iframe обернул, чтобы вам не приходилось уходить с хабра, но не нашёл, как это сделать. А зато по ссылке сразу нужный файлик и нужная строчка открываются, и можно там Show нажать, и посмотреть, как выглядит. 2k19…
К этому теперь изи прикручивается networked-aframe и получается p2p ммо с войсчатом в браузере. Оффтоп.
Вызываем sdf(vec3(0,0,0)), получаем d — минимальное расстояние от… ну, там такой вирту виртуальный экран… в который пырит виртуальная камера… и это не та камера, которая основная камера. Это ещё одна камера внутри raymarching шейдера. Она рендерит на текстуру, которой обтянут куб, а куб потом рендерится основной камерой. Это не так важно. Короче для каждого пикселя на виртуальном экране сначала посчитали минимальное расстояние в нуле. В любую сторону на этом расстоянии нет ничего, как и в любую другую сторону.
Дальше откладываем отсюда (от каждого пикселя) в направлении от камеры расстояние d, и вызываем sdf там. Если получаем слишком маленькое d, значит попали куда-то, возвращаем сумму расстояний как результат. Если не получаем — продолжаем, пока не получим, или не улетим слишком далеко. В результате имеем для каждого пикселя по расстоянию. Имея расстояние, можно посчитать нормаль в точке касания. Нормаль — это перпендикуляр к поверхности, там чё-то считается какая-то плотность поля в трёх местах рядом, и градиент этого поля, благодаря его свойствам, вроде как должен совпадать с нормалью. Просто не нужно об этом думать, есть функция getNornal. Имея нормаль, придумываем координаты источника света, и по ним двоим считаем диффузное освещение в этой точке. Число [0,1]. Если большой угол — так свет ложится, маленький — по-другому. И его (диффузное освещение) уже можно выводить на экран, получится красивое трёхмерное затенённое (но без теней). Для теней надо стрельнуть ещё и из этой точки, да в сторону источника света. Если не долетит — значит умножаем диффузное освещение на .1, получается тень.
Вот тут красиво, и видео есть.
Вот и всё, что я знаю про raymarching.
ссылка на оригинал статьи https://habr.com/ru/post/462229/
Добавить комментарий