Уместно ли сейчас делать веб-панораму?

внешний интерфейс прямая трансляция WebGL three.js

Веб-панорамы часто использовались для просмотра улиц и 360-градусных панорам в условиях ограниченной пропускной способности в прошлом. Это может дать пользователям возможность погрузиться в себя и свободно просматривать окружающие объекты с помощью простых операций. С введением некоторыми операторами бесплатных потоковых сервисов, таких как King Card, и популяризацией среды 4G использование большого трафика постепенно продвигается. Например, можем ли мы превратить статичные панорамные изображения с низким трафиком в динамические панорамные видео в реальном времени? При определенной скорости сети и пропускной способности это может быть достигнуто. Позже давайте посмотрим, как реализовать панорамное видео в Интернете. Сначала взгляните на пример gif:

gif

tl;dr;

  • Технология Panorama с использованием three.js
  • Введение в принципы UV-мэппинга
  • Принципы 3D-координат и управление движением
  • Введение в веб-гироскопы
  • Введение в простую библиотеку iv-panorama

На основе Three.js

Панорамное видео основано на 3D-пространстве, а в Интернете технология, которая может легко коснуться 3D-пространства, — это WebGL. Для простоты здесь используется непосредственно библиотека Three.js. Конкретный принцип работы заключается в сопоставлении воспроизводимого видеоэлемента с пространством текстуры и вставке его непосредственно на сферическую поверхность с помощью UV-наложения. Упрощенный код:

let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1100); 
// 添加相机


camera.target = new THREE.Vector3(0, 0, 0); 
// 设置相机的观察位置,通常在球心

scene = new THREE.Scene();
let  geometry = new THREE.SphereBufferGeometry(400, 60, 60);
// 在贴图的时候,让像素点朝内(非常重要)
geometry.scale(-1, 1, 1);

// 传入视频 VideoEle 进行绘制
var texture = new THREE.VideoTexture(videoElement);

var material = new THREE.MeshBasicMaterial({ map: texture });
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);


renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio); // canvas 的比例
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);

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

Поле зрения камеры

Конкретный код:

let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1100); 

Перспективная камера в основном используется здесь для имитации эффекта человеческого глаза. Установите соответствующий эффект поля зрения.Диапазон здесь также должен определяться в соответствии с диаметром сферы, обычно 2 * радиус + 100, если он больше диаметра сферы.

Настройки параметров для геометрических сфер

let  geometry = new THREE.SphereBufferGeometry(400, 60, 60);
// 在贴图的时候,让像素点朝内(非常重要)
geometry.scale(-1, 1, 1);

На самом деле есть две части, которые необходимо объяснить выше.

  • В настройке параметра сферы есть три важных значения атрибута Формат API:SphereBufferGeometry(radius, widthSegments, heightSegments,...).
    • радиус: Задайте радиус сферы. Чем больше радиус, тем больше содержимое, отрисовываемое видео на холсте. Значение параметра является соответствующим.
    • Сегменты ширины/высоты: количество срезов, которое в основном используется для контроля того, на сколько треугольных срезов сфера делится не более чем по двум измерениям ширины и высоты.Чем выше текстура, тем четче края и углы. Однако она не бесконечно высока, и в то же время имеет место высокая потеря производительности.
  • Во время геометрического рисования пиксели оси X поворачиваются внутрь посредством преобразования координат, чтобы у пользователя не возникало эффекта выпуклости и увеличения. Конкретный код:geometry.scale(-1, 1, 1).

УФ-картирование

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

  • УФ-картирование
  • 3D мобильный

Здесь мы в основном исследуем детали UV-мэппинга. Основная цель UV-мэппинга — преобразовать 2D-изображения в 3D-объекты Наиболее классическое объяснение:

Коробка — это трехмерный объект, такой же, как квадратная сетка поверхности («сетка»), который добавляется в сцену. Если разрезать коробку по боковым швам или сгибам, то коробку можно расстелить на столе.Когда мы смотрим на стол сверху вниз, мы можем думать, что U – это направление влево и вправо, а V – направление вверх. и вниз. Изображение на коробке В 2D координатах. Мы используем UV для обозначения «системы координат текстуры» вместо XY, которая обычно используется в 3D-пространстве. При повторной сборке коробки определенные координаты UV на картоне сопоставляются с пространственным положением коробки (X Y Z) Это то, что делает компьютер при наложении 2D-изображения на 3D-объект.

image.png-544.6kB
from Чжэцзянский исследовательский отчет

Здесь мы подробно объясним через код. Нам нужно завершить текстуру и прикрепить следующий спрайт к кубу.

sprite

from iefreer

cube

Здесь мы сначала загружаем изображение в пространство текстуры:

var material = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('images/texture-atlas.jpg') } );

Итак, теперь у нас есть такая область текстурного пространства:

此处输入图片的描述

Эта часть контента на самом деле включает в себя знание WebGL. Пространство текстуры и физическое пространство не вместе. Синтаксис GLSL в WebGL заключается в сопоставлении содержимого текстуры с поверхностью указанной области треугольника с помощью соответствующих правил.

Здесь следует отметить, что в текстурном пространстве нет так называемой минимальной треугольной области, а здесь адаптирована только треугольная область, разделенная в физическом пространстве. Для простоты мы настроили boxGeometry на использование только сегментов с единицей измерения 1, уменьшив количество треугольников, которые необходимо разделить.

Таким образом, нужно вставить 12 треугольных областей. Здесь нам нужно использоватьVector2Давайте вручную разделим область текстурного пространства.По сути, при отображении это отображение фиксированных точек физического пространства и фиксированных точек текстурного пространства один за другим, чтобы шаги связывания текстуры и реализуется физическое пространство.

Потому что в Three.jsgeometry.faceVertexUvsПри разделении физического пространства порядок определенных треугольников разложения граней делится в соответствии с направлением против часовой стрелки в соответствии с порядковым номером, как показано на следующем рисунке:

此处输入图片的描述

Согласно определению приведенного выше рисунка, мы можем получить значения координат поверхности каждого геометрического объекта, сопоставленного с текстурным пространством, которые можно разделить на:

left-bottom = [0,1,3]
right-top = [1,2,3]

Итак, нам нужно определить значения координат текстуры:

face1_left = [new THREE.Vector2(0, 0),new THREE.Vector2(.5, 0),new THREE.Vector2(0, .333)]
face1_right = [new THREE.Vector2(.5, 0),new THREE.Vector2(.5, .333),new THREE.Vector2(0, .333)]

//... 剩下 10 个面

Конкретный формат API отображения UV с фиксированной точкой:

geometry.faceVertexUvs[ 0 ][ faceIndex ][ vertexIndex ]

Затем определите отображение конкретного лица как:

geometry.faceVertexUvs[0][0] = face1_left;
geometry.faceVertexUvs[0][0] = face1_right;
//...剩下 10 个面

Если вы написали собственный код WebGL, вам должно быть легко понять, как работает UV-отображение.

Принцип трехмерного движения

Здесь важно отметить, что Web Panorama — это не WebVR. Панорама не обладает эффектом погружения в виртуальную реальность, она включает только вращение в трех измерениях без перемещения на расстояние.

В приведенном выше описании упоминаются два понятия трехмерности и угла поворота, что легко напоминает нам систему координат, изучаемую в «Математике средней школы» — сферическую систему координат (здесь по умолчанию используется правосторонняя система координат) .

球坐标

  • φ - угол с положительной осью z
  • ∂ - угол с положительной осью x
  • p - расстояние по прямой линии точки в пространстве от начала координат

Формула расчета:

formula

Теперь, применительно к веб-панораме, мы можем знать несколько известных условий:

  • p: размер радиуса определенной сферы (SphereBufferGeometry)
  • Δφ: пользователь перемещается на расстояние по оси Y
  • Δ∂: пользователь перемещается с оси x

p Это константа, а Δφ и Δ∂ — значения, определяемые пользовательским вводом. Здесь нужен алгоритм для унификации соглашения. Основное содержание алгоритма управления:

∆x/∆y пальца пользователя на оси плоскости x/y преобразуется в ∆φ/∆∂ по определенному соотношению

Если принять во внимание гироскоп, то это:

∆x/∆y пальца пользователя на оси плоскости x/y преобразуется в ∆φ/∆∂ по определенному соотношению, а значение угла ∆φ'/∆∂' поворота пользователя на оси x/y ось, соответственно, и угол обзора Углы объединяются для вычисления результата.

Для более широкой совместимости мы объясним здесь на основе описания второго алгоритма. Изменение ∆φ/∆∂ выше в основном отражает изменение нашего поля зрения.

gif

В Threejs используется для управления полем зрения камеры. Итак, как мы можем контролировать поле зрения в ThreeJS? Вот минимальный код:

phi = THREE.Math.degToRad(90 - lat);
theta = THREE.Math.degToRad(-lon);
camera.position.x = distance * Math.sin(phi) * Math.cos(theta);
camera.position.y = distance * Math.cos(phi);
camera.position.z = distance * Math.sin(phi) * Math.sin(theta);

Это в основном имитирует земные координаты:

  • lat означает широту: значение, измененное пользователем, скользящим вверх и вниз, или вращением телефона вверх и вниз
  • lon обозначает долготу: значение, измененное пользователем влево и вправо, или вращением телефона влево и вправо

Конкретное содержание:

image.png-17.9kB

В обычной практике есть два способа изменить размеры панорамного вида: один — непосредственно смахиванием рукой, а другой — вращением в соответствии с гироскопом.

Проще говоря, мониторингtouchа такжеorientationСобытие, вручную измените значение широты/долготы в соответствии с информацией о триггере. Однако здесь есть оговорка:

Направление широты может достигать максимум (-90,90), в противном случае это вызовет эффект переворота экрана, что очень плохо.

Давайте попрактикуемся в коде соответственно.

Добавьте сенсорное управление

Связанные с касанием события в сети могут сказать вам, например, до тех пор, пока вы не сломаетесь, сколькими пальцами пользователь коснулся экрана? Какой именно жест пользователя на экране (swipe,zoom)?

Здесь для простоты мы используем только расстояние скольжения одного пальца в качестве данных перспективного движения камеры. Конкретный код:

swipe(e=>{
	lat += y * touchYSens;
	lon += x * touchXSens;
	
	lat = Math.max(-88, Math.min(88, lat));
})
  • touchYSens/touchXSens используется для управления чувствительностью, которую можно настроить самостоятельно, например, 0,5.
  • x/y: расстояние, на которое палец перемещается за одно движение
  • Math.max(-88, Math.min(88, lat)): управление значением широты диапазона движения

Добавить управление гироскопом

Веб-доступ к информации гироскопа в основном осуществляется черезdeviceorientationсобытие приобретено. Он предоставит соответствующие параметры гироскопа, альфа, бета, гамма. Если вы не понимаете его внутренних принципов, вы в принципе не будете его использовать, просто взглянув на его параметры. Конкретные принципы см.:Ориентация гироскопа API.

Проще говоря, параметры гироскопа в стандартном случае, а у мобильного телефона две координаты:

  • Земные координаты x/y/z: постоянная ориентация в любом случае
  • Координаты плоскости мобильного телефона x/y/z: эквивалентны направлению, определяемому экраном мобильного телефона.

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

此处输入图片的描述

  • x: указывает ориентацию восток-запад, X указывает на восток
  • y: указывает ориентацию север-юг, а положительный Y указывает на север
  • z: перпендикулярно центру земли, Z указывает вверх

Точкой отсчета мобильного телефона является плоскость мобильного телефона, а также три системы координат X/Y/Z.

  • X: параллельно экрану вправо
  • Y: параллельно экрану вверх
  • Z: положительный перпендикулярно экрану телефона вверх

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

В остальном см.API гироскопаВот и все. Здесь давайте посмотрим непосредственно на то, как изменить угол камеры через гироскоп:

lat -= beta * betaSens;
lon += gamma * gammaSens;

lat = Math.max(-88, Math.min(88, lat));

beta — поворачивать телефон вверх и вниз, а lon — поворачивать телефон влево и вправо. Каждый раз, возвращая значение изменения ориентации, оно применяется к результату изменения определенной широты и долготы.

Для прямой 3D-трансляции есть еще много моментов, таких как щелчок по панораме, переключение панорамы и так далее. Если вы хотите вручную построить компонент панорамной прямой трансляции, в этом нет необходимости, здесь команда Now IVWeb предоставляет компонент iv-panorama, который предоставляет множество удобных функций, таких как сенсорное управление, управление гироскопом, панорама изображения, панорама видео и другие. функции.

Введение в iv-панораму

iv-panorama — плеер, специально разработанный командой IVWEB для горячих точек панорамных прямых трансляций. В настоящее время Интернет не особенно дружелюбен к виртуальной реальности, но для панорамного видео узкое место в производительности панорамного видео постепенно исчезает при условии замены машин. Его основные особенности:

  • Зависит от Three.js и должен быть предварительно смонтирован на объекте окна.
  • Гибкая настройка, встроенная поддержка гироскопа и сенсорного управления.
  • Поддержка динамической настройки параметров чувствительности
  • Используйте синтаксис ES6
  • Совместимость с React, jQuery (простой подсчет)

Адрес проекта:iv-panorama. Этот проект очень прост в использовании, есть два режима панорамы, один для фото, а другой для видео:

import VRPlayer from 'iv-panorama';

new VRPlayer({
        player: {
            url: '/test/003.mp4'
        },
        container:document.getElementById('container')
    });
    
// image

let panorama = new VRPlayer({
    image: {
            url: './banner.png'
        },
        container:document.getElementById('container')
    });

Ресурсы панорамы размещеныgithubСклад имеется, а желающие могут посмотреть его на деле.