当前位置: 首页 > news >正文

3D看房实现房屋的切换

作为3D看房的补充,在这里,我们讲一下如何实现房屋的切换,我这里提供两种思路,

  • 切换贴图,
  • 切换场景,

接下我们按照较复杂的场景切换来讲,切换贴图也就水到渠成:

  1. 初始化场景:创建多个场景,并根据需求切换。
  2. 处理点击事件:通过射线投射(Raycasting)检测点击位置与对象的交点。
  3. 动态更新场景:根据点击事件的结果切换场景或执行其他逻辑。

以下是详细的实现步骤和代码示例:


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 - 1mouse.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].objectconsole.log('点击的对象:', clickedObject)// 如果点击的是立方体,则切换到场景2if (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 - 1mouse.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].objectconsole.log('点击的对象:', clickedObject)// 如果点击的是立方体,则切换到场景2if (clickedObject === cube1) {console.log('切换到场景2')currentScene = scene2}}
}// 监听画布点击事件
window.addEventListener('click', onCanvasClick)// 渲染循环
function animate() {requestAnimationFrame(animate)// 渲染当前场景renderer.render(currentScene, camera)
}
animate()

关键点说明

  1. 场景切换

    • 使用一个变量(如 currentScene)来跟踪当前活动的场景。
    • 在点击事件中,根据条件切换 currentScene 的值。
  2. 射线投射(Raycasting)

    • 使用 THREE.Raycaster 和鼠标位置计算点击的对象。
    • 根据点击结果执行逻辑(如切换场景或高亮对象)。
  3. 渲染循环

    • 在渲染循环中,始终渲染 currentScene,以确保显示正确的场景。

注意事项

  • 只读属性问题

    • 如果你遇到类似 hotspot.name = 'hotspot-1' 的错误,请检查 hotspot 是否被冻结或标记为只读。
    • 解决方法包括避免直接修改只读属性,或者创建新的对象来更新值。
  • 性能优化

    • 如果场景中有大量对象,可以通过优化射线投射的检测范围(如仅检测特定对象组)来提高性能。
http://www.lryc.cn/news/574723.html

相关文章:

  • 五种 IO 模式的简单介绍 -- 阻塞 IO,非阻塞 IO,信号驱动 IO,IO 多路复用,异步 IO
  • Spring Data REST极速构建REST API
  • 【ArcGIS】土地资源单项评价
  • API 调试工具校验 JSON Mock 接口(二):有参验证
  • 四色(定理/猜想)染色算法小软件Version1.11 2025.6.24 开发者:孝感动天/卧冰求鲤
  • 神经网络的本质 逻辑回归 python的动态展示
  • 蓝桥杯嵌入式学习(cubemxkeil5)
  • 从零开始学习Spring Cloud Alibaba (一)
  • PYTHON从入门到实践4-数据类型
  • 大模型时代的创业机遇
  • 快速搭建企业级私有仓库:Docker + Nexus3 私服指南
  • 数据结构知识点总结--绪论
  • 02-StarRocks数据导入导出FAQ
  • 域名 SSL证书和IP SSL证书有什么区别?
  • 15:00开始面试,15:06就出来了,问的问题有点变态。。。
  • OSS大数据分析集成:MaxCompute直读OSS外部表优化查询性能(减少数据迁移的ETL成本)
  • 内存泄漏系列专题分析之二十四:内存泄漏测试Camera相机进程内存指标分布report概述
  • C++【生存游戏】开发:荒岛往事 第一期
  • 机器学习×第十三卷:集成学习上篇——她不再独断,而是召集小队贴贴你
  • Leetcode-2563. 统计公平数对的数目
  • prometheus 配置邮件告警
  • Unity2D 街机风太空射击游戏 学习记录 #13 射击频率道具 最高分
  • 如何使typora图片不居中留白?
  • 【网络安全】从IP头部看网络通信:IPv4、IPv6与抓包工具 Wireshark 实战
  • WinUI3入门11:改变鼠标形状 设置光标
  • 鸿蒙应用开发中的状态管理:深入解析AppStorage与LocalStorage
  • 基于Qt C++的影像重采样批处理工具设计与实现
  • jenkinsfile调用groovy
  • 服务器安装指南
  • 从iOS到Flutter:我的转型之路与技术成长启示