или создавайте 3D-миры, используя HTML, CSS и JS.
В прошлом году я сделал демо , который показывает, как можно использовать 3D-преобразования CSS для создания 3D-пространства.
Демо представляло собой техническую демонстрацию того, чего можно было достичь с помощью CSS на тот момент, но мне хотелось посмотреть, как далеко я смогу зайти, поэтому я работал над новая версия с еще более сложными моделями, реалистичным освещением, тенями и обнаружением столкновений.
В этом посте описано, как я это сделал и какие методы использовал.
Создание 3D-объектов
В современных 3D-движках объекты хранятся в виде набора точек (или векторов), каждая из которых имеет значения X, Y и Z, обозначающие ее положение в трехмерном пространстве.Например, квадрат будет определяться четырьмя векторами, по одному на каждый угол.
Каждым из векторов можно манипулировать индивидуально, перемещая его по осям X, Y и Z, тем самым позволяя квадрату растягиваться в разные формы.
Модуль 3D-рендеринга будет использовать эти векторы и множество умных математических вычислений для рисования 3D-объекта на 2D-экране.
С CSS-преобразованиями все наоборот. Мы не можем определить произвольные формы с помощью набора точек; наши руки связаны HTML-элементами, которые всегда имеют квадратную форму и имеют двумерные свойства, такие как верх, лево, ширина и высота, указывающие их положение и размеры.
Но во многом это значительно упрощает работу с 3D, так как в этом случае нет сложной математики — вам просто нужно применить CSS-преобразование, чтобы повернуть элемент вокруг осей, и все готово! Создание объектов из квадратов на первый взгляд может показаться ограниченным методом, но вы можете создать их удивительное количество, особенно когда начнете экспериментировать с альфа-каналами PNG. На картинке ниже вы можете увидеть, как верхняя часть бочки и колесо кажутся круглыми, несмотря на то, что они сделаны из квадратов.
пример 3D-объектов, полностью созданных из квадрата элементы
Все объекты создаются с помощью JavaScript с использованием набора методов создания примитивной геометрии.
Самый простой объект, который можно создать, — это самолет, который по сути представляет собой обычный элемент. Самолеты можно добавлять в наборы, обертывать над ними позволяет всему объекту вращаться и перемещаться как единое целое.
Труба представляет собой набор плоскостей, вращающихся вокруг осей, а бочка — это труба с плоскостью вверху и плоскостью внизу.
Этот пример показывает, что говорится на практике, взгляните на вкладку JS.
Свет
Освещение было самой сложной задачей в этом проекте.Не буду врать, математика меня чуть не сломала, но оно того стоило, потому что свет придавал невероятное ощущение глубины и атмосферы плоскому и безжизненному пространству.
скриншот комнаты без освещения
Как я уже говорил, объект в обычном 3D-движке определяется серией векторов.
Для расчета света эти векторы используются для расчета «нормали», которую можно использовать для определения количества света, отраженного от центральной точки поверхности объекта.
Это создает проблему при создании 3D-объектов с использованием элементов HTML, поскольку этих векторов не существует. Итак, первое препятствие — это написание набора методов для расчета четырех векторов (по одному на каждый угол) для элемента, преобразованного с помощью CSS, на основе которых можно рассчитать свет. Как только я это определил, я сразу же начал экспериментировать с разными способами освещения объектов.
В своем первом эксперименте я использовал несколько фоновых изображений, чтобы имитировать свет, падающий на поверхность, путем объединения линейный градиент с картинкой.
В эффекте используется градиент, который начинается и заканчивается одним и тем же значением RGBA, создавая сплошной блок цвета.
Изменение значения альфа-канала позволяет основному изображению проявляться сквозь цветовой блок, создавая иллюзию затенения.
пример использования градиента для затенения текстуры
Чтобы добиться максимально темного эффекта на изображении выше, я применил следующие стили:
На практике эти стили не объявляются заранее; они рассчитываются динамически и применяются непосредственно к атрибуту стиля элемента с помощью JavaScript. Эта техника называется плоской штриховкой.element { background: linear-gradient(rgba(0,0,0,.
8), rgba(0,0,0,.
8)), url("texture.png"); }
Это эффективный метод затенения, но в результате вся поверхность имеет одинаковую детализацию.
Например, если я создам 3D-стену, отступающую на определенное расстояние, она будет закрашена одинаково по всей длине.
Мне хотелось сделать что-то более реалистичное.
Второй штурм освещения
Чтобы имитировать реальное освещение, поверхности должны затемняться по мере удаления от источника света, и если на поверхность падает несколько таких источников, их следует затенять соответствующим образом.Для плоской затененной поверхности мне нужно было рассчитать только свет, падающий на центральную точку, но теперь мне нужно измерить свет в различных точках поверхности, чтобы определить, насколько освещенной или затененной должна быть каждая точка.
Математика требовала создания этой световой информации так же, как и в случае с плоской штриховкой.
Я пытался создать радиальный градиент от легкой информации до использования ее на сайте линейный градиент моя предыдущая попытка.
Результаты были более реалистичными, но несколько источников света по-прежнему оставались проблемой, поскольку наложение нескольких градиентов друг на друга постепенно затемняло нижележащие текстуры.
Если бы CSS поддерживал смешивание изображений и режимы наложения (смешивание уже в пути), можно было бы заставить работать радиальные градиенты.
Решением было использовать элемент для программного создания новой текстуры, которую можно использовать в качестве карты освещения.
Используя вычисленную информацию об освещении, я смог нарисовать наборы черных пикселей, каждый из которых менял альфа-канал в зависимости от количества света, который должен падать на поверхность в данной точке.
В конце концов я использовал холст.toDataURL() метод кодирования изображения, которое использовалось вместо него линейный градиент мой первый эксперимент. Повторив этот процесс для каждой поверхности, я воспроизвел реалистичный эффект освещения для всего экспериментального пространства.
Расчет и рисование таких текстур – тяжелая работа.
Размер потолка и пола подвала составляет 1000x2000 пикселей, поэтому создание текстуры, покрывающей всю эту площадь, не очень практично, поэтому я измеряю свет только каждые 12 пикселей, что дает карту освещения в 12 раз меньше, чем поверхность.
будет охватывать.
Монтаж размер фона: 100% заставляет браузер масштабировать текстуру с помощью билинейной (или аналогичной) фильтрации, чтобы карта освещения покрывала всю нужную нам поверхность.
Эффект масштабирования создает результат, который почти идентичен карте освещения, созданной для каждого пикселя.
Пример правила стиля фона, которое будет использоваться для определения карты освещения и поверхности, будет выглядеть примерно так: element {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAyCAYAAAAqRkmtAAACiUlEQVRoQ9VZa0vEQAy8+/8/yPcbFVFEEREREcS/4eNSmpKmmU12t/XYD6W3beGmk8kk2a5Xq9XR5vjeHD+B47d/xjrTtdSxud3dl+d+OTmt+yvDmX4c9n8eAbtVoAeCyRRYBknMb4XRfRVyC6wEqYFK0Cj0HG4OfSr8HG56ZhR6AhoJO2u4JPxInxK4BDYCyYu9YOglk/xbsymvy8RhpjlrNEArqWRCrWlBQEsYRWC98EfAmlm/W8FoBKzWp2aT11KbZugJ6NKMzpJMFlANPJX1Wpdyjdj0NKozv9PoTjD0pRYVDb2b9VGgVtZHNKrLpuelEzb5DRhoRKel1alGox1wGfpmgFIYPbCIUa+MRiuTpdMJox7QrSdTM/bUlOFzZ7SERqM+6pbQZpqSZtq8ZhrnZkaRZoa7ZsblZjYgjgM1vmYClYOd1+LBnpRM9iQItLTFQ/0o6vLhXH9aCTTaOWnAehp1K9NZP4rUbufo2UnP9ajV82b6Tg70FudiZtKtHmrtoiOIpU9PpzD0Fwoo2n6sbZo9gJJZcwq9DGi0JpFyhjuoU7pxtSCjtXP9aDfv2gFaOoJofaKst5JJ+ukwM91kMirtyMp0a5MsOtyZicSobxMaLd3K0dZksZlt+HcZoUdsImZTY0g20PtA6OeypohFQR99MCqTDnnqA0NKp7My+ggYjerz34A+LQRUsolCrnWaNPznSqCoeyo1e/bV0T4+LV4KgCJwJAPNZI41WfV+MPzXAFDLluY2e83kqDoR2jcD6ByJhJoRrUtea31OgL4roCU9aORDWMRDIav0Fh890JR3lnz/1GVU1nsGlJX1n4UaRQkV6ZpQ+Uwm05ej0TkSycp8i2Hoo3+utUtvDhk9pwAAAABJRU5ErkJggg==") 0 0 / 100% 100%, url("texture.png") 0 0 / auto auto;
}
Что создает освещенную поверхность:
изображение карты освещения небольшого разрешения, масштабированное и наложенное на текстуру
Наложение тени
Использование холста для освещения позволяет реализовать отображение теней.Логика применения теней оказывается довольно простой.
Организация поверхностей на основе их расстояния от источника света позволила мне не только создать карту освещения для поверхности, но и определить, была ли предыдущая поверхность освещена текущим источником света.
При необходимости я мог бы указать, чтобы соответствующий пиксель на карте освещения находился в тени.
Этот метод позволяет использовать одно изображение как для освещения, так и для затенения.
скриншот получившейся комнаты с освещением и тенями
Обнаружение столкновений
Карта высот используется для обнаружения столкновений — на изображении ниже для обозначения высоты объектов на нем используется цвет. Белый цвет представляет самую глубокую позицию, а черный - самую высокую из возможных позиций, которых может достичь игрок.Когда игрок перемещается по уровню, я конвертирую его положение в 2D-координаты и использую их для проверки цвета на карте высот. Если цвет светлее последней позиции игрока, он падает; если цвет немного темнее, игрок может залезть на объект или запрыгнуть на него.
Если цвет значительно темнее, игрок останавливается, я использую это для определения стен и препятствий.
Это изображение нарисовано от руки, но выглядит так же, как созданное динамически.
изображение карты высот и ее связь с уровнями
Что дальше?
Что ж, полноценная игра будет логичным следующим шагом — будет интересно посмотреть, насколько масштабируемы эти методы.На данный момент я начал работать над прототипом.
CSS3-рендерер для вкусного Три.
js который использует те же методы для рендеринга геометрии и света, созданных реальным 3D-движком.
первоисточник Теги: #CSS #HTML #Кит Кларк #CSS #HTML
-
Sony Ищет Новых Тестеров Игр
19 Oct, 24 -
Игры На Одевание И Другие Игры Для Девочек
19 Oct, 24 -
Строительство И Строительные Материалы
19 Oct, 24 -
Персонализированная Поисковая Система
19 Oct, 24 -
Шутеры, Несовместимые С Ibm-Pc
19 Oct, 24