vue写threejs例子-全景图

307 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情


今天学习的是用vue和three.js展示全景图,很简单的一个例子,首先需要一个要展示的全景图

kandao3.jpg

下面是演示gif(较大:

20220824_103140 (1).gif

需要的资源可在threejs官方项目中找到

先写一个容器

<template>
  <div class="item">
    <div id="THREE14"></div>
  </div>
</template>

然后一个mounted方法

mounted() {
  this.initThreejs();
},

下面是initThreejs的代码

先把需要的变量都定义一下

camera - 摄像机

scene - 场景

renderer - 渲染器

onPointerDownMouseX - 鼠标按下时赋值为clientX

onPointerDownMouseY - 鼠标按下时赋值为clientY

lon - 记录鼠标移动过程中位置x的变化

onPointerDownLon - 鼠标按下时设置为lon的值

lat - 记录鼠标移动过程中位置y的变化

onPointerDownLat - 鼠标按下时设置为lat的值

phi - x方向移动的弧度

theta - y方向移动的弧度

initThreejs() {
  let camera, scene, renderer;

  let onPointerDownMouseX = 0,
    onPointerDownMouseY = 0,
    lon = 0,
    onPointerDownLon = 0,
    lat = 0,
    onPointerDownLat = 0,
    phi = 0,
    theta = 0;

  init();
  animate();
}

获取容器

const container = document.getElementById("THREE14");

创建相机

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

创建场景

scene = new THREE.Scene();

创建球体

new THREE.SphereGeometry(500, 60, 40) - 创建一个半径为500的球体

geometry.scale(-1, 1, 1) - 反转x轴上的几何图形,使所有面都指向内部

const geometry = new THREE.SphereGeometry(500, 60, 40);

geometry.scale(-1, 1, 1);

const texture = new THREE.TextureLoader().load("textures/kandao3.jpg"); // 引入材质
const material = new THREE.MeshBasicMaterial({ map: texture }); // 创建材质

const mesh = new THREE.Mesh(geometry, material); // 创建网格模型

scene.add(mesh); // 将模型添加到场景中

创建渲染器

renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth - 201, window.innerHeight);
container.appendChild(renderer.domElement);

container.style.touchAction = "none";

绑定鼠标事件

pointerdown - 不区分左右的鼠标按下事件,按下后绑定鼠标移动和按下事件

pointermove - 鼠标移动事件,移动过程中记录移动的距离

pointerup - 鼠标松开事件,松开后移除鼠标移动和按下事件的绑定

container.addEventListener("pointerdown", onPointerDown);

function onPointerDown(event) {
    if (event.isPrimary === false) return;

    onPointerDownMouseX = event.clientX;
    onPointerDownMouseY = event.clientY;

    onPointerDownLon = lon;
    onPointerDownLat = lat;

    document.addEventListener("pointermove", onPointerMove);
    document.addEventListener("pointerup", onPointerUp);
}

function onPointerMove(event) {
    if (event.isPrimary === false) return;

    lon = (onPointerDownMouseX - event.clientX) * 0.1 + onPointerDownLon;
    lat = (event.clientY - onPointerDownMouseY) * 0.1 + onPointerDownLat;
}
function onPointerUp() {
    document.removeEventListener("pointermove", onPointerMove);
    document.removeEventListener("pointerup", onPointerUp);
}

绑定滚轮事件

camera.fov - 摄像机视锥体垂直视野角度,角度越大,显示的区域就越多

THREE.MathUtils.clamp(fov, 10, 75) - 限制返回值在10-75之间,若fov在10-75之间则返回fov的值,否则返回10或75

camera.updateProjectionMatrix() - 属性发生改变后,需要调用该方法来使改变生效

document.addEventListener("wheel", onDocumentMouseWheel);

function onDocumentMouseWheel(event) {
    const fov = camera.fov + event.deltaY * 0.05;

    camera.fov = THREE.MathUtils.clamp(fov, 10, 75);

    camera.updateProjectionMatrix();
}

animate()方法:

function animate() {
    requestAnimationFrame(animate);
    update();
}

update()方法

THREE.MathUtils.degToRad - 将度转化为弧度

camera.lookAt(x, y, z) - 旋转物体使其在空间中面朝(x, y, z)。

function update() {
    lat = Math.max(-85, Math.min(85, lat));
    phi = THREE.MathUtils.degToRad(90 - lat);
    theta = THREE.MathUtils.degToRad(lon);

    const x = 500 * Math.sin(phi) * Math.cos(theta);
    const y = 500 * Math.cos(phi);
    const z = 500 * Math.sin(phi) * Math.sin(theta);

    camera.lookAt(x, y, z);

    renderer.render(scene, camera);
}