причина
Прошлой ночью я не мог уснуть, и меня вдруг вдохновило VR-видео с иностранного видеосайта. Потребовалось 40 минут, чтобы написать это маленькое демо и поделиться им с вами.
визуализация
принцип
Сначала используем сферу
Сгенерируйте текстурный блок для каждого кадра видео и расширьте его во фрагментном шейдере в соответствии с uv сферы
Положение камеры помещается в исходное положение
использоватьrAf
Обновите средство визуализации
Подготовить материалы
Подготовка видео материала
Первым делом скачиваем панорамное видео научным путем с неизвестного сайта (как отечественного, так и зарубежного). Откройте его с помощью vlc player, это выглядит так:
Код
Сначала мы представляем три и собственный трековый контроллер
import * as THREE from "three/build/three.module";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
Добавьте следующий DOM в html
<div class="player">
<div>
<button @click="$refs.video.play()">播放</button>
</div>
<video
preload
ref="video"
controls
loop
style="width: 100%; visibility: hidden; position: absolute"
:src="src"
></video>
<canvas
style="width: 80%; height: 823px"
width="1920"
height="823"
ref="canvas"
></canvas>
</div>
Инициализировать текстуру видео
initVideoTexture() {
this.videoTexture = new THREE.VideoTexture(this.$refs.video);
this.videoTexture.needsUpdate = true;
this.videoTexture.updateMatrix();
}
Здесь мы используем видеотекстуру, поставляемую с Three.js. Вы также можете реализовать ее самостоятельно. Создайте закадровый холст, передайте видео в drawImage и создайте его экземпляр через Texture. Не забудьте установить для свойства needUpdate значение true.
initScene() {
this.scene = new THREE.Scene();
}
initCamera() {
this.camera = new THREE.PerspectiveCamera(45, 1024 / 768, 1, 1000);
this.camera.position.z = 30;
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.maxDistance = 100;
this.controls.update();
// const helper = new THREE.CameraHelper(this.camera);
// this.scene.add(helper);
this.scene.add(this.camera);
}
Инициализировать сетку
Обратите внимание, что здесь, чтобы определить материал, который мы хотим использоватьuniforms
Да ладно, объект текстуры, который мы только что инициализировали, передается, здесь мы используем tex_0 в качестве имени переменной, которую мы используем.
initMesh() {
this.geometry = new THREE.SphereGeometry(100, 32, 16);
this.material = new THREE.ShaderMaterial({
wireframe: false,
side: THREE.DoubleSide,
map: this.videoTexture,
uniforms: {
tex_0: new THREE.Uniform(this.videoTexture),
},
vertexShader: require("@/components/v.glsl").default,
fragmentShader: require("@/components/f.glsl").default,
});
this.mesh = new THREE.Mesh(this.geometry, this.material);
}
тиковая функция
update() {
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(this.update);
}
смонтированная функция
Поскольку я использую vue SFC, напишите это в смонтированном хуке
mounted() {
this.initRenderer();
this.initScene();
this.initVideoTexture();
this.initMesh();
this.initCamera();
this.addMeshToScene();
this.update();
}
реализация шейдера
вершинный шейдер
Здесь мы используем матрицу MVP, которая поставляется с three.js, для преобразования входящих координат вершин в мир, а затем передаем наш uv фрагментному шейдеру через переменную v_uv, определяемую ключевым словом Variing.
precision highp float;
varying vec2 v_uv;
void main() {
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(position.xyz, 1.0);
v_uv = uv;
}
фрагментный шейдер
Обратите внимание, что поскольку нормаль сферы по умолчанию направлена изнутри наружу, отображение координат нашей UV-текстуры также направлено наружу. происходит переворачивание текстур в шаре, что явно неправильно, поэтому нам нужно сесть и перевернуть координаты uv, что очень просто, достаточно использовать 1.0 - v_uv.x
precision highp float;
varying vec2 v_uv;
uniform sampler2D tex_0;
void main() {
vec4 texColor = texture2D(tex_0, vec2(1. - v_uv.x, v_uv.y));
gl_FragColor = texColor;
}
Таким образом, наше панорамное видео реализуется. Я поставил демоgiteeО, какие у вас есть идеи, вы также можете подтвердить меня в частном порядке ~~