vue3 three ts 全景图

4 篇文章 0 订阅

实现方式有两种 一种为球形,一种为方形
球形需要一张完整的全景图
方形的需要六张各个面可以拼接的一整套图(东,南,西,北,上,下)

球形实现

<template>
  <div>
    <div
      class="main"
      ref="box"
      @click.stop="clickCanvas"
      style="
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        align-content: center;
      "
    >
      <h1 v-if="loading">loading...</h1>
      <i
        v-if="loading"
        style="
          font-size: 36px;
          margin: 12px 0 8px;
          transition: transform 0.3s ease-in-out;
          will-change: transform;
        "
        ><svg
          viewBox="0 0 1024 1024"
          width="1em"
          height="1em"
          aria-hidden="true"
          focusable="false"
          class="anticon-loading"
        >
          <path
            d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
          ></path></svg
      ></i>
    </div>
  </div>
</template>
<script lang="ts">
import {
  WebGLRenderer, //渲染器
  Scene, //场景
  PerspectiveCamera, //相机
  SphereGeometry, //材质
  DoubleSide, //渲染两个面
  Mesh, //组合
  MeshBasicMaterial, //球体 全景用
  TextureLoader, //加载器  内部使用ImageLoader来加载文件
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; //镜头控制
import { defineComponent, ref, onMounted, watch } from "vue";
import Stats from "three/examples/jsm/libs/stats.module.js"; //性能监控插件
export default defineComponent({
  setup() {
    const loading = ref(true);
    //提前创建好调试插件
    const box = ref<HTMLElement | null>(null); //ref获取dom
    const scence: Scene = new Scene(); //场景
    const camera = new PerspectiveCamera( //新建相机
      120, //摄像机视锥体垂直视野角度
      window.innerWidth / window.innerHeight, //摄像机视锥体长宽比
      0.1, //摄像机视锥体近端面
      10000 //摄像机视锥体远端面
    );
    const stats = Stats(); //性能监控
    var orbitControls: OrbitControls; //摄像机控制
    var rander: WebGLRenderer; //渲染器
    var sphereGeometry: Mesh<SphereGeometry, MeshBasicMaterial>;

    // 渲染器方法
    function randerFun() {
      rander = new WebGLRenderer({ antialias: true, alpha: true }); //新建渲染器 antialias 否执行抗锯齿
      rander.setClearColor(0xffffff, 1); //更改渲染器颜色为默认
    }
    randerFun();

    //新建场景
    function scenceFun() {
      scence.name = "场景"; //场景名字
      camera.name = "相机"; //相机名字
      camera.position.set(-200, 30, 400); //相机位置
      orbitControls = new OrbitControls(camera, rander.domElement); //相机控制插件 实现拖拽渲染
      orbitControls.autoRotate = true;
    }
    scenceFun();

    // 全景开始
    function sphereGeometryFun() {
      let img3D = new TextureLoader().load("/img/3d.jpg");
      sphereGeometry = new Mesh(
        new SphereGeometry(1000, 32, 32),
        new MeshBasicMaterial({ map: img3D, side: DoubleSide })
      );
      scence.add(sphereGeometry);
      sphereGeometry.position.y = 500;
      camera.position.set(0, 250, 0);
    }
    sphereGeometryFun();

    //aim定时执行 动画
    var aim = () => {
      stats.update(); //刷新性能监控
      orbitControls.update();
      rander.render(scence, camera); //更新试图
      requestAnimationFrame(aim); //定时器 到时间调用自己
    };

    watch(loading, (e) => {
      if (!e) {
        box.value?.append(rander.domElement);
        document.body.appendChild(stats.dom);
        aim();
      }
    });
    //生命周期 页面加载完
    onMounted(() => {
      rander.setSize(window.innerWidth, window.innerHeight); //更改渲染大小
      loading.value = false;
    });
    //使画布动态大小
    window.onresize = () => {
      camera.aspect = window.innerWidth / window.innerHeight; //更改比例
      camera.updateProjectionMatrix(); //更新摄像机投影矩阵
      rander.setSize(window.innerWidth, window.innerHeight); //更改场景大小
    };
    return {
      box,
      loading,
    };
  },
});
</script>
.anticon-loading {
  display: inline-block;
  animation: loadingCircle 1s linear infinite;
}
@keyframes loadingCircle {
  100% {
    transform: rotate(1turn);
  }
}
* {
  padding: 0;
  margin: 0;
}
.main {
  height: 100%;
  width: 100%;
}

方形实现

<template>
  <div>
    <div
      class="main"
      ref="box"
      @click.stop="clickCanvas"
      style="
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        align-content: center;
      "
    >
      <h1 v-if="loading">loading...</h1>
      <i
        v-if="loading"
        style="
          font-size: 36px;
          margin: 12px 0 8px;
          transition: transform 0.3s ease-in-out;
          will-change: transform;
        "
        ><svg
          viewBox="0 0 1024 1024"
          width="1em"
          height="1em"
          aria-hidden="true"
          focusable="false"
          class="anticon-loading"
        >
          <path
            d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
          ></path></svg
      ></i>
    </div>
  </div>
</template>
<script lang="ts">
import {
  WebGLRenderer, //渲染器
  Scene, //场景
  PerspectiveCamera, //相机
  DoubleSide, //渲染两个面
  Mesh, //组合
  BoxGeometry, //球体 全景用
  TextureLoader, //加载器  内部使用ImageLoader来加载文件
  MeshBasicMaterial,
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; //镜头控制
import { defineComponent, ref, onMounted, watch } from "vue";
import Stats from "three/examples/jsm/libs/stats.module.js"; //性能监控插件
export default defineComponent({
  setup() {
    const loading = ref(true);
    //提前创建好调试插件
    const box = ref<HTMLElement | null>(null); //ref获取dom
    const scence: Scene = new Scene(); //场景
    const camera = new PerspectiveCamera( //新建相机
      120, //摄像机视锥体垂直视野角度
      window.innerWidth / window.innerHeight, //摄像机视锥体长宽比
      0.1, //摄像机视锥体近端面
      10000 //摄像机视锥体远端面
    );
    const stats = Stats(); //性能监控
    var orbitControls: OrbitControls; //摄像机控制
    var rander: WebGLRenderer; //渲染器
    var boxGeometry: Mesh<BoxGeometry>;
    var img3D: MeshBasicMaterial[] = [];
    // 渲染器方法
    function randerFun() {
      rander = new WebGLRenderer({ antialias: true, alpha: true }); //新建渲染器 antialias 否执行抗锯齿
      rander.setClearColor(0xffffff, 1); //更改渲染器颜色为默认
    }
    randerFun();

    //新建场景
    function scenceFun() {
      scence.name = "场景"; //场景名字
      camera.name = "相机"; //相机名字
      camera.position.set(0, 0, 1); //相机位置
      orbitControls = new OrbitControls(camera, rander.domElement); //相机控制插件 实现拖拽渲染
      orbitControls.autoRotate = true;
    }
    scenceFun();

    //正方体 全景开始
    function boxGeometryFun() {
      img3D.push(
        new MeshBasicMaterial({
          map: new TextureLoader().load("/img/3d/posx.jpg"),
          side: DoubleSide,
        })
      );
      img3D.push(
        new MeshBasicMaterial({
          map: new TextureLoader().load("/img/3d/negx.jpg"),
          side: DoubleSide,
        })
      );
      img3D.push(
        new MeshBasicMaterial({
          map: new TextureLoader().load("/img/3d/posy.jpg"),
          side: DoubleSide,
        })
      );

      img3D.push(
        new MeshBasicMaterial({
          map: new TextureLoader().load("/img/3d/negy.jpg"),
          side: DoubleSide,
        })
      );

      img3D.push(
        new MeshBasicMaterial({
          map: new TextureLoader().load("/img/3d/posz.jpg"),
          side: DoubleSide,
        })
      );
      img3D.push(
        new MeshBasicMaterial({
          map: new TextureLoader().load("/img/3d/negz.jpg"),
          side: DoubleSide,
        })
      );
      boxGeometry = new Mesh(new BoxGeometry(1000, 1000, 1000), img3D);
      scence.add(boxGeometry);
    }
    boxGeometryFun();

    //aim定时执行 动画
    var aim = () => {
      stats.update(); //刷新性能监控
      orbitControls.update();
      rander.render(scence, camera); //更新试图
      requestAnimationFrame(aim); //定时器 到时间调用自己
    };

    watch(loading, (e) => {
      if (!e) {
        box.value?.append(rander.domElement);
        document.body.appendChild(stats.dom);
        aim();
      }
    });
    //生命周期 页面加载完
    onMounted(() => {
      rander.setSize(window.innerWidth, window.innerHeight); //更改渲染大小
      loading.value = false;
    });
    //使画布动态大小
    window.onresize = () => {
      camera.aspect = window.innerWidth / window.innerHeight; //更改比例
      camera.updateProjectionMatrix(); //更新摄像机投影矩阵
      rander.setSize(window.innerWidth, window.innerHeight); //更改场景大小
    };
    return {
      box,
      loading,
    };
  },
});
</script>
.anticon-loading {
  display: inline-block;
  animation: loadingCircle 1s linear infinite;
}
@keyframes loadingCircle {
  100% {
    transform: rotate(1turn);
  }
}
* {
  padding: 0;
  margin: 0;
}
.main {
  height: 100%;
  width: 100%;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑕、疵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值