阿卡不拉阿卡不拉
Vue3
阿卡的博客
Vue3
阿卡的博客
  • CSS

    • ✨flex 布局 👌
  • Vue3

    • 快速入门

      • 搭建工程 👌
      • 模板语法
      • 响应式基础
      • 响应式常用 API
      • 计算属性
      • 类与样式绑定
      • 条件和列表渲染
      • 事件处理
      • 表单处理
      • 生命周期
      • 侦听器
      • 组件介绍
      • Props
      • 自定义事件
      • 组件v-model
      • 插槽
      • 前端路由介绍
      • KeepAlive内置组件
      • 状态管理库
      • 组件库介绍
    • 深入本质

      • 虚拟DOM本质
      • 模板的本质
      • 组件树和虚拟DOM树
      • 数据拦截的本质
      • 响应式数据的本质
      • 响应式的本质
      • 响应式和组件渲染
      • 实现响应式系统 1
      • 实现响应式系统 2
      • 图解EFFECT
      • 实现响应式系统 3
      • 手写computed
      • 手写watch
      • 指令的本质
      • 插槽的本质
      • v-model的本质
      • setup 语法标签
      • 组件生命周期
      • keepalive 生命周期
      • keepalive的本质
      • key的本质
    • 细节补充

      • 【Vue】属性透传
      • 【Vue】依赖注入
      • 【Vue】组合式函数 👌
      • 【Vue】自定义指令
      • 【Vue】插件
      • 【Vue】Transition
      • 【Vue】TransitionGroup
      • 【Vue】Teleport
      • 【Vue】异步组件
      • 【Vue】Suspense
      • 【Router】路由模式
      • 【Router】路由零碎知识
      • 【Router】路由匹配语法
      • 【Router】路由组件传参
      • 【Router】内置组件和函数
      • 【Router】导航守卫
      • 【Router】过渡特效
      • 【Router】滚动行为
      • 【Router】动态路由
      • 【State】通信方式总结
      • 【State】Pinia 自定义插件
      • 【场景】封装树形组件
      • 【场景】自定义 ref 实现防抖
      • 【场景】懒加载
      • 【场景】虚拟列表
      • 【场景】虚拟列表优化
      • 【第三方库】VueUse
      • 【第三方库】vuedragable
      • 【第三方库】vue-drag-resize
      • 【第三方库】vue-chartjs
      • 【第三方库】vuelidate
      • 【第三方库】vue3-lazyload
      • 【场景】Websocket 聊天室
      • 【Vite】✨ 认识 Vite👌
      • 【Vite】配置文件 👌
      • 【Vite】✨ 依赖预构建 👌
      • 【Vite】构建生产版本 👌
      • 【Vite】环境变量与模式
      • 【Vite】CLI
      • 【Vite】Vite 插件
  • 笔面试

    • HTML

      • HTML 面试题汇总
      • 文档声明
      • 语义化
      • W3C 标准组织
      • SEO
      • iframe
      • 微格式
      • 替换元素
      • 页面可见性
    • CSS

      • CSS 面试题汇总
      • CSS 单位总结
      • 居中方式总结
      • 隐藏元素方式总结
      • 浮动
      • 定位总结
      • BFC
      • CSS 属性计算过程
      • CSS 层叠继承规则总结
      • @import 指令
      • CSS3 calc 函数
      • CSS3 媒体查询
      • 过渡和动画事件
      • 渐进增强和优雅降级
      • CSS3 变形
      • 渐进式渲染
      • CSS 渲染性能优化
      • 层叠上下文
      • CSS3 遮罩
    • JavaScript

      • JavaScript 面试题汇总
      • ✨ let、var、const 的区别
      • JS中的数据类型
      • 包装类型
      • 数据类型的转换
      • 运算符
      • ✨ 原型链
      • ✨ this 指向
      • ✨ 垃圾回收与内存泄漏
      • ✨ 执行栈和执行上下文
      • ✨ 作用域和作用域链
      • ✨ 闭包
      • DOM 事件的注册和移除
      • DOM 事件的传播机制
      • 阻止事件默认行为
      • 递归
      • ✨ 属性描述符
      • class 和构造函数区别
      • 浮点数精度问题
      • 严格模式
      • ✨ 函数防抖和节流
      • ✨ WeakSet 和 WeakMap
      • ✨ 深浅拷贝
      • 函数柯里化
      • Node 事件循环
      • 尺寸和位置
      • ✨ 事件循环 👌
    • Promise

      • ✨Promise 面试题考点 👌
      • ✨Promise 基础 👌
      • ✨Promise 的链式调用 👌
      • ✨Promise 的静态方法 👌
      • ✨async 和 await👌
    • 浏览器

      • 浏览器面试题汇总
      • ✨ 浏览器的渲染流程
      • ✨ 资源提示关键词
      • 浏览器的组成部分
      • IndexedDB
      • ✨ File API
      • ✨ 浏览器缓存
      • ✨ 浏览器跨标签页通信
      • Web Worker
    • 网络

      • 网络面试题汇总
      • 五层网络模型 👌
      • 常见请求方法 👌
      • ✨cookie👌
      • 面试题
      • 加密
      • ✨JWT👌
      • ✨ 同源策略及跨域问题 👌
      • 文件上传
      • ✨ 输入 url 地址之后
      • 文件下载
      • ✨ session
      • ✨ TCP
      • ✨ CSRF 攻击
      • ✨XSS 攻击 👌
      • ✨ 网络性能优化
      • 断点续传
      • 域名和 DNS
      • ✨SSL、TLS、HTTPS 的关系
      • ✨ HTTP 各版本差异 👌
      • HTTP 缓存协议
      • ✨ WebSocket
    • 工程化

      • CMJ 和 ESM
      • npx
      • ESLint
    • Vue2

      • Vue 面试题汇总相关
      • 组件通信方式总结
      • 虚拟 DOM
      • v-model
      • 数据响应式原理
      • diff
      • 生命周期详解
      • computed
      • 过滤器
      • 作用域插槽
      • 过度和动画
      • 优化
      • keep-alive
      • 长列表优化
      • 其他 API
      • 模式和环境变量
      • 更多配置
      • 更多命令
      • 嵌套路由
      • 路由切换动画
    • Vue3

      • ✨ Vue3 整体变化 👌
      • ✨ Vue3 响应式变化 👌
      • ✨ nextTick 实现原理 👌
      • 两道代码题 👌
      • Vue 运行机制
      • 渲染器核心功能
      • 事件绑定与更新
    • Cypress

      • Cypress 测试框架面试题
    • 项目

      • FOFA 实习项目

        • /interview/project/fofa/FOFA%E5%AE%9E%E4%B9%A0%E9%A1%B9%E7%9B%AE%E9%9D%A2%E8%AF%95%E7%82%B9.html
      • 低代码问卷系统

        • 低代码问卷项目面试点
      • VR 全景看房

        • VR 全景看房项目面试点
  • TS

    • 快速入门

      • Playground 👌
      • 安装与运行 👌
      • 开发相关配置 👌
      • TS 常见类型 👌
      • 类型声明 👌
  • 工具库

    • 常用第三方工具库
    • JQuery
    • Lodash
    • Animate.css
    • Axios
    • MockJS
    • Moment
    • ECharts
  • 其他知识点

    • ✨ 前端项目打包流程与编译概念详解
    • ✨ 懒加载 👌
    • ✨ 前端路由的核心原理 👌

Q1: 请介绍一下 Three.js 的核心组件,以及它们在 VR 看房项目中的作用?

口头回答

面试官您好,Three.js 是一个基于 WebGL 的 JavaScript 3D 图形库,它的核心组件主要包括场景(Scene)、相机(Camera)、渲染器(Renderer)、几何体(Geometry)、材质(Material)、光源(Light)等。在我们的 VR 看房项目中,这些组件发挥了关键作用:

1. 场景(Scene) 场景是所有 3D 对象的容器,相当于一个虚拟的 3D 世界。在我们项目中,所有的房间、导航图标、信息点都被添加到同一个场景中进行统一管理。

2. 相机(Camera) 我们使用透视相机(PerspectiveCamera)来模拟人眼视角,实现第一人称的沉浸式体验。相机的位置变化实现了房间之间的切换,旋转控制实现了 360° 全景浏览。

3. 渲染器(Renderer) 使用 WebGLRenderer 将场景和相机的数据渲染到 HTML 画布上,并通过 requestAnimationFrame 实现实时渲染循环。

4. 几何体(Geometry) 主要使用立方体几何体(BoxGeometry)创建房间空间,通过翻转 Z 轴使纹理朝向内部,形成房间内部视角。

5. 材质(Material) 使用基础材质(MeshBasicMaterial)配合纹理贴图,为每个房间的六个面分别加载对应的全景图片,创建沉浸式的房间环境。

6. 精灵(Sprite) 虽然不是传统核心组件,但在我们项目中大量使用精灵对象创建导航图标和信息点,它们始终面向相机,确保良好的交互体验。

项目中的具体实现细节

1. 场景创建

// 在 App.vue 中创建全局场景
const scene = new THREE.Scene();

2. 相机设置

// 创建透视相机,75度视野角,适合VR体验
const camera = new THREE.PerspectiveCamera(
    75, // 视野角度(FOV)
    window.innerWidth / window.innerHeight, // 宽高比
    0.1, // 近裁剪面
    1000 // 远裁剪面
);

// 将相机位置设置在几何体内部
camera.position.set(0, 0, 0.01);

3. 渲染器配置

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

// 渲染循环
const render = () => {
    renderer.render(scene, camera);
    requestAnimationFrame(render);
};

4. 房间几何体实现(Room.ts)

// 创建10x10x10的立方体作为房间
const boxGeometry = new THREE.BoxGeometry(10, 10, 10);
// 翻转Z轴,使纹理朝向内部
boxGeometry.scale(1, 1, -1);

// 为立方体的六个面分别创建材质
const boxMaterial: THREE.MeshBasicMaterial[] = [];
imageList.forEach((item) => {
    const texture = new THREE.TextureLoader().load(textureUrl + item);
    boxMaterial.push(new THREE.MeshBasicMaterial({ map: texture }));
});

// 创建网格对象并添加到场景
const box = new THREE.Mesh(boxGeometry, boxMaterial);
box.position.copy(position);
box.rotation.copy(euler);
scene.add(box);

5. 导航精灵实现(RoomSprite.ts)

// 使用Canvas动态生成导航图标纹理
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d")!;
canvas.width = 1024;
canvas.height = 1024;
ctx.fillStyle = "rgba(100, 100, 100, 0.7)";
ctx.fillRect(0, 256, canvas.width, canvas.height / 2);
ctx.font = "bold 200px Arial";
ctx.fillStyle = "white";
ctx.fillText(text, canvas.width / 2, canvas.height / 2);

// 创建精灵材质和精灵对象
const spriteMaterial = new THREE.SpriteMaterial({
    map: new THREE.CanvasTexture(canvas),
    transparent: true,
});
const sprite = new THREE.Sprite(spriteMaterial);

6. 信息点精灵实现(InfoSprite.ts)

// 使用纹理加载器加载信息点图标
const infoSpriteMaterial = new THREE.SpriteMaterial({
    map: new THREE.TextureLoader().load(url),
    transparent: true,
});

const infoSprite = new THREE.Sprite(infoSpriteMaterial);
infoSprite.position.copy(position);
infoSprite.scale.set(scale, scale, scale);
infoSprite.userData = userData; // 存储信息点数据
scene.add(infoSprite);

7. 射线投射交互

// 使用射线投射实现精确的3D空间交互
const pointer = new THREE.Vector2();
const raycaster = new THREE.Raycaster();

// 将鼠标位置归一化为设备坐标
pointer.x = (e.clientX / window.innerWidth) * 2 - 1;
pointer.y = -(e.clientY / window.innerHeight) * 2 + 1;

// 从相机发射射线
raycaster.setFromCamera(pointer, camera);

// 检测射线与物体的相交
const intersects = raycaster.intersectObjects(spriteList);
if (intersects.length > 0) {
    // 处理交互逻辑
}

8. 相机控制系统

// 实现第一人称视角的鼠标控制
container.value.addEventListener("mousemove", (e) => {
    if (mouseDown) {
        camera.rotation.y += e.movementX * 0.002;
        camera.rotation.x += e.movementY * 0.002;
        camera.rotation.order = "YXZ"; // 使用YXZ顺序符合第一人称视角
    }
});

9. 响应式设计

// 窗口大小变化时更新相机和渲染器
window.addEventListener("resize", () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
});

技术亮点

  1. 几何体翻转技术:通过 boxGeometry.scale(1, 1, -1) 翻转 Z 轴,使立方体纹理朝向内部,创造房间内部视角

  2. 多材质应用:为立方体的六个面分别应用不同的全景图片纹理,实现 360° 全景效果

  3. 精灵对象优化:使用 Sprite 对象创建始终面向相机的导航图标和信息点,确保良好的用户体验

  4. 射线投射交互:利用 Raycaster 实现精确的 3D 空间点击和悬停检测

  5. 相机控制优化:使用 YXZ 旋转顺序,符合人类直觉的第一人称视角控制

  6. 动态纹理生成:使用 Canvas API 动态生成导航图标纹理,提高灵活性和性能

这些 Three.js 核心组件的合理运用,使我们成功实现了一个流畅、沉浸式的 VR 看房体验。

最近更新:: 2025/7/23 03:47
Contributors: AK