IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> threejs全景图片展示 -> 正文阅读

[游戏开发]threejs全景图片展示

关于代码

基于threejs的全景照片示例改了一下,并做简单封装。threejs的全景示例有cube和equirectangular两种,这里因为全景图片是一整张而不是多张图片拼合,故使用equirectangular。

关于全景图片

全景照片的来源是mapillary,访问需要梯子。
通过mapillary的#api爬取了照片文件和信息,相关教程有空发。
重点是这两个字段,一个是点位坐标一个是初始角度,可以用于照片的拍摄点定位和全景展示初始镜头朝向
在这里插入图片描述
图片本身是jpg,注意不是多张图片拼合的全景,而是一整张照片。
全景图片示例

show me the code

使用TS编写,js自行更改

import * as THREE from "three";

const Panorama = {
  scene: new THREE.Scene(),
  /**
   * 刷新图片
   * @param imgPath
   */
  updateMesh: function (imgPath: string) {
    // 这里每次都会重置参数,不想重置就把下面注释掉
    this.resetParams();
    const mesh = this.scene.getObjectByName("pano") as THREE.Mesh;
    // 刷新
    const material = mesh.material as THREE.MeshBasicMaterial;
    material.map = null;
    const texture = new THREE.TextureLoader().load(imgPath);
    material.map = texture;
  },
  /**
   * 初始化
   * @param container dom元素
   * @param imgPath 图像路径
   * @param compassAngle 照片朝向,0-360角度 正北方为0,顺时针为正
   */
  init: function (
    container: HTMLElement,
    imgPath: string,
    compassAngle: number
  ) {
    const _t = this;
    const scene = this.scene;
    // 透视投影相机
    // fov, aspect, near, far
    const camera = new THREE.PerspectiveCamera(
      95,
      container.offsetWidth / container.offsetHeight,
      1,
      1100
    );

    const texture = new THREE.TextureLoader().load(imgPath);
    // 基本材质 不响应光源
    const material = new THREE.MeshBasicMaterial({ map: texture });
    // 球体
    // radius半径, segmentsWidth经度上的切片数, segmentsHeight纬度上的切片数
    const geometry = new THREE.SphereGeometry(500, 60, 40);
    // invert the geometry on the x-axis so that all of the faces point inward
    geometry.scale(-1, 1, 1);

    // 网格
    const mesh = new THREE.Mesh(geometry, material);
    mesh.name = "pano";
    scene.add(mesh);

    const renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio(window.devicePixelRatio);
    // 设定渲染器宽高
    renderer.setSize(container.offsetWidth, container.offsetHeight);
    container.appendChild(renderer.domElement);

    container.style.touchAction = "none";

    container.addEventListener("pointerdown", onPointerDown);

    container.addEventListener("wheel", onDocumentMouseWheel);

    container.addEventListener("resize", onWindowResize);

    function onWindowResize() {
      camera.aspect = container.offsetWidth / container.offsetHeight;
      camera.updateProjectionMatrix();

      renderer.setSize(container.offsetWidth, container.offsetHeight);
    }

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

      _t.isUserInteracting = true;

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

      _t.onPointerDownLon = _t.lon;
      _t.onPointerDownLat = _t.lat;

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

    function onPointerMove(event: PointerEvent) {
      if (event.isPrimary === false) return;
      _t.lon =
        (_t.onPointerDownMouseX - event.clientX) * 0.1 + _t.onPointerDownLon;
      _t.lat =
        (_t.onPointerDownMouseY - event.clientY) * 0.1 + _t.onPointerDownLat;
    }

    function onPointerUp(event: PointerEvent) {
      if (event.isPrimary === false) return;

      _t.isUserInteracting = false;

      container.removeEventListener("pointermove", onPointerMove);
      container.removeEventListener("pointerup", onPointerUp);
    }

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

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

      camera.updateProjectionMatrix();
    }

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

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

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

      camera.lookAt(x, y, z);

      renderer.render(scene, camera);
    }

    animate();
  },
  resetParams: function () {
    this.isUserInteracting = false;
    this.onPointerDownMouseX = 0;
    this.onPointerDownMouseY = 0;
    this.lon = 0;
    this.onPointerDownLon = 0;
    this.lat = 0;
    this.onPointerDownLat = 0;
    this.phi = 0;
    this.theta = 0;
  },
  isUserInteracting: false,
  onPointerDownMouseX: 0,
  onPointerDownMouseY: 0,
  lon: 0,
  onPointerDownLon: 0,
  lat: 0,
  onPointerDownLat: 0,
  phi: 0,
  theta: 0,
};

export { Panorama };

使用示例

找个合适的地方放一个容器

<div id="pano-container"></div>

引入刚才的全景工具(ThreeExt.ts)

import { Panorama as PanoFn } from "./ThreeExt.ts";

为了节约资源,只有第一次加载的时候会初始化容器,后面更换照片会调用updateMesh方法。

初始化

const container = document.getElementById(
  "pano-container"
) as HTMLDivElement;
PanoFn.init(container, 你的照片路径, 你的照片初始角度);

刷新照片

PanoFn.updateMesh(新的照片路径);

清除

先清空场景,再清空容器元素

PanoFn.scene.clear();
const container = document.getElementById(
  "pano-container"
) as HTMLDivElement;
container.innerHTML = "";
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:59:23  更:2022-09-21 01:00:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/8 11:14:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码