HTML5 круговая панорама на three.js

в 17:57, , рубрики: javascript, three.js, Демосцена, панорамы, метки: , ,

    В последнее время все чаще можно наткнуться на круговую панораму в интернете. Взять к примеру тот же сырный домик. Это эффектная штучка возможно вскоре станет обыкновенным делом для сайтов ресторанов, гостиниц, отелей и т. п. Однако, что делать, если существуют проблемы с flash на компьютере? Это реальная ситуация, которая возникла у меня на работе, по причине жесткой политики безопасности IT-отдела.
   &nbspВ этой небольшой статье я расскажу вам о трудностях, которые встретил на пути создания интерактивной панорамы на WebGL + THREE.js.

Определим требования к панораме:

  • используем WebGL, так как Canvas панорамы просто ужас, и еще новый IE поддерживает;
  • Просмотр панорамы путем перетаскиванием зажатой кнопки мыши;
  • Активные элементы призванные обратить внимание и сообщить информацию;
  • Возможность посмотреть несколько панорам на одной странице.

    Что бы понять, как это реализовать, предлагаю представить следующее: «Мы находимся в центре сферы, на внутреннюю поверхность которой нанесена текстура панорамы. Мы — это камера, которая может поворачиваться и смотреть вверх или вниз. На внутренней поверхности сферы ( „у“ поверхности, как оказалось ) находятся элементы, и когда мы наводим на них мышку, появляется окошко с информацией».

Cфера

    Существует как минимум два варианта реализации панорамы: кубическая и сферическая. Я выбрал сферическую, так как размещение визуально одинаковых активных элементов предполагает равноудаленное расстояние от центра. За прототип возьмем существующий образец панорамы с сайта разработчика библиотеки. Он нам полностью подходит за одним исключением. Это сфера с текстурой вывернутая на изнанку. Трудно представить как это может выглядеть.

mesh.scale.x = -1;

    К сожалению, одна эта деталь ставит полный крест на возможности добавления элементов. Суть в том, что получить хоть какую то информацию об объекте в пространстве при помощи указателя, надо «выстрелить» лучом (Raycaster) из точки указателя в направление вектора, только в данном случае луч не ударится о стенку сферы, потому как камера (логичная точка начала) не находится внутри. Сделано это потому, что текстура натягивается только с внешней стороны, но теперь есть возможность это исправить просто добавив свойство side в объект материи сферы:

mesh = new THREE.Mesh( new THREE.SphereGeometry( 500, 60, 40 ), new THREE.MeshBasicMaterial( { 
    map: THREE.ImageUtils.loadTexture( 'textures/2294472375_24a3b8ef46_o.jpg' )
    side: THREE.BackSide
 } ) );

Кстати, это типичное создание объекта в мире THREE.js. Как правило создается геометрия объекта, материал ( текстура ), а потом добавляется на сцену.

Элементы

Теперь надо подумать о том, что из себя будут представлять те самые активные элементы. В идеале ими должны быть плоские спрайты, всегда отображающиеся лицом к камере. Да, да именно так :)

image

    Но здесь нас ждет сюрприз. В THREE.js существует два «класса» для рендеринга: WebGLRenderer и CanvasRenderer. И два типа простых объектов: Particle (частица) и Sprite. WebGL работает с Sprite, а Canvas с Particle. При этом нам необходим именно WebGL, а объект Sprite не имеет объема в пространстве. То есть по нему невозможно попасть мышкой.
    Что ж возьмем и с имитируем эти самые спрайты при помощи 3D объекта с геометрией плоскости ( PlaneGeometry):

var itemGeometry = new THREE.PlaneGeometry(35, 35),
      pointMapHovered = THREE.ImageUtils.loadTexture( "img/information-hover.PNG" ),
      pointMap = THREE.ImageUtils.loadTexture( "img/information-unhover.PNG" );

point = new THREE.Mesh( itemGeometry, new THREE.MeshBasicMaterial({
          map: pointMap,
          transparent:true  //планка квадратная, не думаю, что кому-нибудь понравятся черные углы
        }) );

    Хочу обратить ваше внимание, почему именно так: закеширована геометрия точки и текстура, а материал будет каждый раз создаваться заново. Дело в том, что при наведении мышки на точку, мы будем подменять текстуру на более яркую, к примеру, но если MeshBasicMaterial закеширована и является для всех общей, загораться будут все. Насчет наведения мышкой, все просто — берем отсюда.
    Последняя важная часть, которая вызвала затруднения — это перерасчет координат области панорамы на странице на координаты WebGL пространства для точного выделения точек. Визуально элементы видны, но их координаты на страничке не совпадают с координатами 3D пространства. На StackOverFlow нашелся ответ.

Данные

     Так как предполагается возможность просматривать много панорам на одной странице, лучше все данные поместить в JSON. Примерно так:

{
"points": [
                  {
                   "coords": {
                       "x": 302.0282521739266,
                       "y": -32.30522607035554, 
                       "z": 389.86440214968525
                    },
                       "header": "Заголовок",
                       "body": "Описание."
                 },
            ],
"texture": "panorama.jpg",
"name": "название панорамы"
}

    Что бы просматривать разные панорамы, мы будем подменять текстуру сферы, удалять точки и по координатам выстраивать новые.

Что получилось

Приглашаю посмотреть

Демо

Заранее прошу прощения за использованные материалы. Описание хлебобулочного завода #7, как и его название придумано из головы, любые совпадения случайны и не имеют никакой связи с реальностью. ссылка

Автор: DIvan4ik

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js