Three.js 全景图浏览

思路:

1. 创建球体,背(双)面贴图,视角位于球体中心;
2. 创建立方体,六面贴图,视角位于立方体中心。

 

1. 首先需要一张高分辨率的全景图,要不然会糊。

下面是推荐的国外全景图网站,可以下载用于调试:

        Poly Haven 全景图片icon-default.png?t=N7T8https://polyhaven.com/hdris

2. 立方体贴图需要注意要按照顺序进行贴图:

可以使用以下工具进行图片切割:

GitHub:全景图至立方体贴图icon-default.png?t=N7T8https://github.com/jaxry/panorama-to-cubemap

下载时可以看到已经自动命名好了,就不需要再去额外考虑:

 3.代码:

<template>
    <div ref="fullView"></div>
</template>

<script setup>
import * as THREE from 'three'
import TWEEN from "@tweenjs/tween.js";
import { ref, onMounted } from "vue";
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

/********************** 创建3D场景 ***********************/
const scene = new THREE.Scene();


/********************** 创建光源 ***********************/
//添加光源
const ambiLight = new THREE.AmbientLight(0x333333);
scene.add(ambiLight);


/********************** 创建相机 ***********************/
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 3000);
camera.position.set(0, 1500, 0);


/********************** 创建渲染器对象 ***********************/
const renderer = new THREE.WebGLRenderer();
//设置three.js渲染区域的尺寸(像素px)
renderer.setSize(window.innerWidth, window.innerHeight); 
renderer.setClearColor(0xC0C0C0, 1);  // 设置背景色

/********************** 创建轨道控制器 ***********************/
const controls = new OrbitControls(camera, renderer.domElement);


/********************** 创建球体全景图 ***********************/
// 创建球体
const geometry = new THREE.SphereGeometry(300, 50, 50);
// 设置材质贴图
const material = new THREE.MeshBasicMaterial({ // 此材质不受光照影响
    map: new THREE.TextureLoader().load('sky.png',() => { rotateEnter() }), //贴图,加载进场动画
    side: THREE.BackSide, //背面贴图,也可以设为 THREE.DoubleSide 双面贴图,不过内部图像方向应该会反过来
});
// 加入到场景中
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);


/********************** 创建正方体全景图 ***********************/
// const geometry = new THREE.BoxGeometry(300, 300, 300);
// // 6张全景图的名称
// const pathArr = ['px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png'];
// // 声明一个数组,用来存储六张全景图对应的纹理对象Texture
// const materialArr = [];
// pathArr.forEach((src, idx) => {
//   let textureLoader = new THREE.TextureLoader();
//   let material = new THREE.MeshBasicMaterial({
//     map: textureLoader.load(src, () => { 
//         if(idx == pathArr.length - 1) {
//             rotateEnter() 
//         }
//     }),
//     side: THREE.BackSide, //背面贴图
//   });
//   materialArr.push(material)
// });
// const mesh = new THREE.Mesh(geometry, materialArr);
// scene.add(mesh);


/********************** 动画旋转进场 ***********************/
const rotateEnter = () => {
    let tween = new TWEEN.Tween({ fov: camera.fov, y: camera.position.y })
    .to({ fov: 70, y: 0 }, 3000) // 动画时间为3s
    .easing(TWEEN.Easing.Sinusoidal.InOut)
    .onUpdate((e) => {
        // 更新相机位置和视角大小
        camera.position.y = e.y;
        camera.fov = e.fov;
        // // 旋转效果
        mesh.rotation.y += 0.05;
        // // 将从上到下的视角 调整为 平行视角
        if(e.y < 500) {
            camera.lookAt(new THREE.Vector3(0, 0, 90));
        }
    })
    .onComplete(() => {
        TWEEN.remove(tween);
        // 更新相机矩阵
        camera.updateProjectionMatrix();
        controls.update();
    })
    .start();
}


/********************** 挂载及渲染 ***********************/
const fullView = ref(null);
onMounted(()=>{
    fullView.value.appendChild(renderer.domElement);
})
const renderScene = () => {
    renderer.render(scene, camera);
    requestAnimationFrame(renderScene);
    TWEEN.update();
}
renderScene();

</script>

<style lang="scss" scoped>
</style>

猜你喜欢

转载自blog.csdn.net/weiliangLAN/article/details/141157279