joken-前端工程师

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::
  404 随笔 :: 39 文章 :: 8 评论 :: 20万 阅读

在 Three.js 中实现全景看车内车外功能,可以通过加载两张不同的全景图(一张代表车外视角,另一张代表车内视角),并根据用户交互动态切换这两张全景图来实现。以下是详细的实现步骤和关键概念。


结论

通过加载两张全景图(车外和车内),结合用户交互(如点击按钮或热点)动态切换场景背景,可以实现全景看车内车外的效果。


详细展开

1. 核心原理

  • 使用两张不同的全景图分别表示车外和车内视角。
  • 根据用户交互(如点击按钮或热点),动态切换场景的背景纹理。

2. 实现步骤

(1) 创建场景、相机和渲染器
// 创建场景
const scene = new THREE.Scene();

// 创建透视相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
(2) 加载两张全景图

分别加载车外和车内的全景图,并将初始背景设置为车外视角。

// 加载全景图
const loader = new THREE.TextureLoader();

let currentTexture; // 当前显示的纹理

// 车外全景图
const outsideTexture = loader.load('outside_panorama.jpg'); // 替换为你的车外全景图路径

// 车内全景图
const insideTexture = loader.load('inside_panorama.jpg'); // 替换为你的车内全景图路径

// 设置初始背景为车外视角
currentTexture = outsideTexture;
scene.background = currentTexture;
(3) 添加相机控制器

使用 OrbitControls 实现用户视角的自由旋转。

// 引入 OrbitControls
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

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

// 禁用缩放和平移,仅允许旋转
controls.enableZoom = false;
controls.enablePan = false;

// 设置初始视角
camera.position.set(0, 0, 0); // 相机位于场景中心
(4) 切换车内外视角

通过按钮或热点交互,动态切换场景背景。

// 切换视角函数
function switchView(toInside) {
    if (toInside) {
        scene.background = insideTexture; // 切换到车内视角
    } else {
        scene.background = outsideTexture; // 切换到车外视角
    }
}

// 添加按钮切换视角
const toggleButton = document.createElement('button');
toggleButton.textContent = '切换视角';
toggleButton.onclick = () => {
    if (scene.background === outsideTexture) {
        switchView(true); // 切换到车内
    } else {
        switchView(false); // 切换到车外
    }
};
document.body.appendChild(toggleButton);
(5) 渲染循环

创建一个渲染循环以持续更新画面。

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
animate();
(6) 响应窗口大小变化

确保当窗口大小改变时,相机和渲染器能够正确调整。

window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

完整示例代码

以下是一个完整的代码示例:

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

// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 加载全景图
const loader = new THREE.TextureLoader();

let currentTexture; // 当前显示的纹理

// 车外全景图
const outsideTexture = loader.load('outside_panorama.jpg'); // 替换为你的车外全景图路径

// 车内全景图
const insideTexture = loader.load('inside_panorama.jpg'); // 替换为你的车内全景图路径

// 设置初始背景为车外视角
currentTexture = outsideTexture;
scene.background = currentTexture;

// 创建控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableZoom = false; // 禁用缩放
controls.enablePan = false;  // 禁用平移

// 设置相机位置
camera.position.set(0, 0, 0);

// 切换视角函数
function switchView(toInside) {
    if (toInside) {
        scene.background = insideTexture; // 切换到车内视角
    } else {
        scene.background = outsideTexture; // 切换到车外视角
    }
}

// 添加按钮切换视角
const toggleButton = document.createElement('button');
toggleButton.textContent = '切换视角';
toggleButton.onclick = () => {
    if (scene.background === outsideTexture) {
        switchView(true); // 切换到车内
    } else {
        switchView(false); // 切换到车外
    }
};
document.body.appendChild(toggleButton);

// 渲染循环
function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
animate();

// 响应窗口大小变化
window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

相关延展

1. 添加热点交互

可以在全景图中添加热点(如箭头图标),用户点击后切换到车内或车外视角。

示例代码:
// 创建热点
const hotspotGeometry = new THREE.SphereGeometry(0.1, 32, 32);
const hotspotMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const hotspot = new THREE.Mesh(hotspotGeometry, hotspotMaterial);
hotspot.position.set(1, 1, -2); // 设置热点位置
scene.add(hotspot);

// 热点点击事件
window.addEventListener('click', (event) => {
    const mouse = new THREE.Vector2();
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    const raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(mouse, camera);

    const intersects = raycaster.intersectObjects(scene.children);
    if (intersects.length > 0 && intersects[0].object === hotspot) {
        console.log('点击了热点');
        switchView(scene.background === outsideTexture); // 切换视角
    }
});

2. 优化性能

  • 使用高效的纹理格式(如 JPEG 或 WebP)减少加载时间。
  • 如果需要加载大量数据,可以使用懒加载技术。

总结

通过加载两张全景图(车外和车内),结合用户交互动态切换场景背景,可以轻松实现全景看车内车外的功能。Three.js 提供了强大的工具和灵活性,能够满足各种复杂需求,例如热点交互和动态加载等。

posted on   joken1310  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示