Three.js实现3D室内全景看房

一、环境准备

要搭建一个使用 Vite 的前端项目,并使用 yarn 来管理依赖,首先需要安装一些必要的软件和库。以下是详细步骤:

1. 安装 Node.js
Vite 需要 Node.js 运行时环境。请确保你已经安装了 Node.js。如果没有,请访问 Node.js 官方网站 下载并安装最新版本。

2. 安装 Yarn
Yarn 是一个快速、可靠且安全的依赖管理工具。如果你还没有安装 Yarn,可以使用 npm(Node.js 自带的包管理工具)来安装 Yarn。

npm install -g yarn

3. 创建一个 Vite 项目
使用 Yarn 创建一个 Vite 项目。请确保你在正确的目录下运行以下命令(项目名称 可以替换为你想要的项目名):

yarn create vite 项目名称

运行这个命令后,Vite 会提示你选择一个模板(如 vanilla、vue、react 等),选择你需要的模板即可。

4. 安装项目依赖
进入项目目录并安装依赖:

cd 项目名称
yarn install

5. 启动开发服务器
安装依赖完成后,启动开发服务器:

yarn dev

这将启动一个开发服务器,并在浏览器中打开项目。

6.临时解决方案:使用 npm

如果 Yarn 仍然无法正常工作,可以考虑直接使用 npm 进行项目管理。

安装依赖:

npm install

启动开发服务器:

npm run dev

二、项目创建

首先我们先搭建一个项目,我选择使用vite来进行项目的搭建,执行命令如下:

yarn create vite iHome(项目名称)

这样一个基本的项目就搭建成功了,目录如下所示

然后,下载一下three.js工具,执行如下命令

npm install three

页面中引入

import * as THREE from "three";

三、代码实现

先搭建一个立体图形,并画出辅助线,如下所示:

代码实现:

import * as THREE from "three";  // 引入 Three.js 库
import { useEffect } from "react";  // 引入 React 中的 useEffect 钩子
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";  // 引入 OrbitControls 控制器

function App() {
  useEffect(() => {
    // 创建透视摄像机,参数分别是视场角(垂直方向)、纵横比、近裁剪面和远裁剪面
    const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
    camera.position.z = 1;  // 设置摄像机位置

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

    // 创建立方体的几何体,指定宽度、高度、深度
    const geometry = new THREE.BoxGeometry(0.4, 0.4, 0.4);
    const material = new THREE.MeshNormalMaterial();  // 创建标准的网格基础材质

    const mesh = new THREE.Mesh(geometry, material);  // 创建网格对象,将几何体和材质组合起来

    // 创建辅助坐标轴对象,用于显示场景中的坐标轴方向
    const ax = new THREE.AxesHelper();
    scene.add(ax);  // 将辅助坐标轴添加到场景中

    const renderer = new THREE.WebGLRenderer({ antialias: true });  // 创建 WebGL 渲染器,启用抗锯齿
    renderer.setSize(window.innerWidth, window.innerHeight);  // 设置渲染器的大小
    renderer.setAnimationLoop(animation);  // 设置渲染循环的回调函数
    document.body.appendChild(renderer.domElement);  // 将渲染器的 DOM 元素添加到文档中

    // 渲染循环的回调函数,每帧执行一次,用于更新和渲染场景
    function animation(time) {
      // 可以根据时间来旋转网格对象
      // mesh.rotation.x = time / 2000;
      // mesh.rotation.y = time / 1000;

      renderer.render(scene, camera);  // 使用摄像机和场景进行渲染
    }

    new OrbitControls(camera, renderer.domElement);  // 创建 OrbitControls 控制器,用于交互式地控制摄像机视角

  }, []);  // useEffect 的依赖数组为空,表示只在组件挂载时运行一次

  return <div className="App"></div>;  // 返回一个空的 div 元素作为组件的根元素
}

export default App;  // 导出组件 App

然后给立体图形中添加照片,实现如下效果

这是从上面看的俯视图,它可以进行一个旋转,需要注意的是:图片一定要按照顺序来,六方体顺序如下:前后,上下,左右

该实现的主要思路是使用 Three.js 在 React 组件中创建一个可交互的 3D 场景,其中包含一个应用了纹理的六面体几何体。以下是具体的实现思路:

  1. 引入必要的库和资源:

    • THREE:Three.js 的主库,用于创建和操作 3D 对象。
    • useEffect:React 的钩子,用于在组件挂载后执行副作用操作。
    • OrbitControls:Three.js 的控件模块,用于添加鼠标交互以控制摄像机视角。
    • 六面体每个面的纹理图片路径。
  2. 定义纹理加载函数:

    • loadTexture 函数:接收图片的 URL,使用 THREE.TextureLoader 加载图片纹理,创建一个 THREE.MeshBasicMaterial 材质对象,并返回该材质对象。
  3. useEffect 中初始化 3D 场景:

    • 创建透视摄像机(THREE.PerspectiveCamera),设置视场角度、纵横比、近裁剪面和远裁剪面,调整摄像机位置。
    • 创建一个场景(THREE.Scene),这是所有 3D 对象的容器。
    • 加载六个面的纹理,创建一个 4x4x4 的立方体几何体(THREE.BoxGeometry),并将纹理应用到几何体上,创建一个网格对象(THREE.Mesh),然后将其添加到场景中。
    • 创建 WebGL 渲染器(THREE.WebGLRenderer),设置渲染器的尺寸,并将渲染器的 DOM 元素添加到 HTML 文档中。
    • 创建渲染循环,调用渲染器的 render 方法渲染场景。
    • 创建 OrbitControls 控件,允许用户使用鼠标交互控制摄像机视角。
  4. 返回一个空的 div 元素:

    • 由于 3D 场景的渲染直接操作 DOM,这里不需要在 JSX 中添加其他内容,只返回一个空的 div 元素。

通过上述步骤,完成了一个基本的 3D 室内全景看房功能,实现了对 3D 场景的加载、纹理应用、交互控制和渲染。代码如下:

import * as THREE from "three";  // 引入 Three.js 库
import { useEffect } from "react";  // 引入 React 中的 useEffect 钩子
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";  // 引入 OrbitControls 控制器
import back from '../src/img/back.png'  // 引入背面纹理图片路径
import bottom from '../src/img/bottom.png'  // 引入底面纹理图片路径
import front from '../src/img/front.png'  // 引入前面纹理图片路径
import left from '../src/img/left.png'  // 引入左面纹理图片路径
import right from '../src/img/right.png'  // 引入右面纹理图片路径
import top from '../src/img/top.png'  // 引入顶面纹理图片路径
 
function App() {
 
  // 定义一个加载纹理的函数,接收图片的 URL,返回一个纹理材质对象
  const loadTexture = (url) => {
    const loader = new THREE.TextureLoader();  // 创建纹理加载器对象
    const texture = loader.load(url);  // 加载图片纹理
    const material = new THREE.MeshBasicMaterial({  // 创建基础网格材质,使用加载的纹理作为贴图
      map: texture,  // 指定贴图
      side: THREE.DoubleSide,  // 设置材质的双面显示
    });
    return material;  // 返回创建的纹理材质对象
  }
 
  useEffect(() => {
    const camera = new THREE.PerspectiveCamera(  // 创建透视摄像机
      70,  // 视场角度
      window.innerWidth / window.innerHeight,  // 纵横比
      0.01,  // 近裁剪面
      10  // 远裁剪面
    );
    camera.position.z = 1;  // 设置摄像机位置
 
    const scene = new THREE.Scene();  // 创建场景
 
    // 准备六面体的纹理数组,每个面使用不同的纹理材质
    const textures = [
      loadTexture(back),
      loadTexture(front),
      loadTexture(top),
      loadTexture(bottom),
      loadTexture(left),
      loadTexture(right),
    ];
    const geometry = new THREE.BoxGeometry(4, 4, 4);  // 创建一个 4x4x4 的立方体几何体
 
    const mesh = new THREE.Mesh(geometry, textures);  // 创建网格对象,使用六面体几何体和纹理数组
    scene.add(mesh);  // 将网格对象添加到场景中
 
    // 创建 WebGL 渲染器,启用抗锯齿
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);  // 设置渲染器尺寸
    renderer.setAnimationLoop(animation);  // 设置渲染循环的回调函数
    document.body.appendChild(renderer.domElement);  // 将渲染器的 DOM 元素添加到页面中
 
    // 渲染循环的回调函数,用于更新和渲染场景
    function animation(time) {
      // 可以根据时间来旋转网格对象
      // mesh.rotation.x = time / 2000;
      // mesh.rotation.y = time / 1000;
 
      renderer.render(scene, camera);  // 使用摄像机和场景进行渲染
    }
 
    new OrbitControls(camera, renderer.domElement);  // 创建 OrbitControls 控制器,用于交互式地控制摄像机视角
 
  }, []);  // useEffect 的依赖数组为空,表示只在组件挂载时运行一次
 
  return <div className="App"></div>;  // 返回一个空的 div 元素作为组件的根元素
}
 
export default App;  // 导出组件 App
posted @ 2024-07-05 20:18  酒剑仙*  阅读(127)  评论(0)    收藏  举报