在 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 提供了强大的工具和灵活性,能够满足各种复杂需求,例如热点交互和动态加载等。
前端工程师、程序员
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!