作为3D看房的补充,在这里,我们讲一下如何实现房屋的切换,我这里提供两种思路,
- 切换贴图,
- 切换场景,
接下我们按照较复杂的场景切换来讲,切换贴图也就水到渠成:
- 初始化场景:创建多个场景,并根据需求切换。
- 处理点击事件:通过射线投射(Raycasting)检测点击位置与对象的交点。
- 动态更新场景:根据点击事件的结果切换场景或执行其他逻辑。
以下是详细的实现步骤和代码示例:
1. 初始化多个场景
首先,我们需要创建多个场景。每个场景可以包含不同的对象、灯光和相机设置。
import * as THREE from 'three'
// 创建场景1
const scene1 = new THREE.Scene()
scene1.background = new THREE.Color(0x0000ff) // 蓝色背景
const cube1 = new THREE.Mesh(
new THREE.BoxGeometry(),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
)
cube1.position.set(0, 0, 0)
scene1.add(cube1)
// 创建场景2
const scene2 = new THREE.Scene()
scene2.background = new THREE.Color(0x00ff00) // 绿色背景
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(1, 32, 32),
new THREE.MeshBasicMaterial({ color: 0xffff00 })
)
sphere.position.set(0, 0, 0)
scene2.add(sphere)
// 当前场景
let currentScene = scene1
2. 处理点击事件
使用射线投射(Raycasting)检测用户点击的对象。如果点击了特定对象,则可以触发场景切换或其他逻辑。
// 相机和渲染器
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.z = 5
const renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
// 射线投射器
const raycaster = new THREE.Raycaster()
const mouse = new THREE.Vector2()
// 点击事件处理函数
function onCanvasClick(event: MouseEvent) {
// 计算标准化设备坐标
mouse.x = (event.clientX / window.innerWidth) * 2 - 1
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
// 设置射线投射器
raycaster.setFromCamera(mouse, camera)
// 检测当前场景中的交点
const intersects = raycaster.intersectObjects(currentScene.children)
if (intersects.length > 0) {
const clickedObject = intersects[0].object
console.log('点击的对象:', clickedObject)
// 如果点击的是立方体,则切换到场景2
if (clickedObject === cube1) {
console.log('切换到场景2')
currentScene = scene2
}
}
}
// 监听画布点击事件
window.addEventListener('click', onCanvasClick)
3. 渲染循环
在渲染循环中,确保渲染当前场景的内容。
function animate() {
requestAnimationFrame(animate)
// 渲染当前场景
renderer.render(currentScene, camera)
}
animate()
4. 完整代码示例
以下是完整的代码示例,展示了如何初始化多个场景、处理点击事件并动态切换场景:
import * as THREE from 'three'
// 创建场景1
const scene1 = new THREE.Scene()
scene1.background = new THREE.Color(0x0000ff) // 蓝色背景
const cube1 = new THREE.Mesh(
new THREE.BoxGeometry(),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
)
cube1.position.set(0, 0, 0)
scene1.add(cube1)
// 创建场景2
const scene2 = new THREE.Scene()
scene2.background = new THREE.Color(0x00ff00) // 绿色背景
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(1, 32, 32),
new THREE.MeshBasicMaterial({ color: 0xffff00 })
)
sphere.position.set(0, 0, 0)
scene2.add(sphere)
// 当前场景
let currentScene = scene1
// 相机和渲染器
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.z = 5
const renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
// 射线投射器
const raycaster = new THREE.Raycaster()
const mouse = new THREE.Vector2()
// 点击事件处理函数
function onCanvasClick(event: MouseEvent) {
// 计算标准化设备坐标
mouse.x = (event.clientX / window.innerWidth) * 2 - 1
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
// 设置射线投射器
raycaster.setFromCamera(mouse, camera)
// 检测当前场景中的交点
const intersects = raycaster.intersectObjects(currentScene.children)
if (intersects.length > 0) {
const clickedObject = intersects[0].object
console.log('点击的对象:', clickedObject)
// 如果点击的是立方体,则切换到场景2
if (clickedObject === cube1) {
console.log('切换到场景2')
currentScene = scene2
}
}
}
// 监听画布点击事件
window.addEventListener('click', onCanvasClick)
// 渲染循环
function animate() {
requestAnimationFrame(animate)
// 渲染当前场景
renderer.render(currentScene, camera)
}
animate()
关键点说明
场景切换:
- 使用一个变量(如
currentScene
)来跟踪当前活动的场景。 - 在点击事件中,根据条件切换
currentScene
的值。
- 使用一个变量(如
射线投射(Raycasting):
- 使用
THREE.Raycaster
和鼠标位置计算点击的对象。 - 根据点击结果执行逻辑(如切换场景或高亮对象)。
- 使用
渲染循环:
- 在渲染循环中,始终渲染
currentScene
,以确保显示正确的场景。
- 在渲染循环中,始终渲染
注意事项
只读属性问题:
- 如果你遇到类似
hotspot.name = 'hotspot-1'
的错误,请检查hotspot
是否被冻结或标记为只读。 - 解决方法包括避免直接修改只读属性,或者创建新的对象来更新值。
- 如果你遇到类似
性能优化:
- 如果场景中有大量对象,可以通过优化射线投射的检测范围(如仅检测特定对象组)来提高性能。