离线创建第一个threejs项目

概述

我们采用下载threejs源码包的方式本地离线创建一个threejs项目。

本笔记对应的threejs版本为r172,由于threejs版本更迭较快,所以请采用指定版本。

知识储备

1.importmap类型脚本

在现代前端开发中,importmap 是一种用于管理 JavaScript 模块导入的新特性,它允许开发者在浏览器中直接映射模块的名称到具体的 URL,而无需依赖打包工具(如 Webpack 或 Rollup)。这对于使用 ES 模块(ESM)以及加载第三方库(比如 Three.js)非常有用,尤其是在原生浏览器环境中。

1.1 什么是importmap

importmap 是一种通过 <script type="importmap"> 标签定义的 JSON 对象,用于告诉浏览器如何解析 ES 模块的导入路径。它可以映射模块的名称(或路径)到实际的 URL。

基本语法如下:

<script type="importmap">
{
  "imports": {
    "模块名": "模块URL"
  }
}
</script>

模块名:你在代码中 import 时使用的名称(例如 three)。

模块URL:模块的具体地址,通常是一个 CDN 链接或本地文件路径。

1.2 实际案例

我们拿threejs官网的案例来举例

{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/three@0.172.0/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.172.0/examples/jsm/"
  }
}
  • “three”:映射 Three.js 的核心模块,指向 three.module.js,这是 ES 模块格式的核心文件。

  • “three/addons/”:映射 Three.js 的附加模块(如控制器、加载器等),这些模块位于 examples/jsm/ 目录下。通过这种方式,可以直接导入 OrbitControls 等模块。

在使用时我们需要配合type="module"的脚本,例如:

<!-- 使用 type="module" 的脚本 -->
<script type="module">
    // 导入 Three.js 核心模块
    import * as THREE from 'three';
    // 加载控制器(例如 OrbitControls)
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
</script>

<script type="module"> 表明这是一个 ES 模块脚本,可以使用 import 语法。

源码下载

我们可以前往如下地址获取最新的threejs源码。

网页:https://threejs.org/

github地址:https://github.com/mrdoob/three.js/

1.网页获取

在这里插入图片描述

点击download获取源码压缩包,压缩包名为three.js-master.zip,与github最新发行版的内容一致。

注意事项:网页版下载的源码包时最新的发行版,如果要使用特定版本的threejs需要前往github下载。

2.github下载

访问github,从如下位置访问各发行版

在这里插入图片描述

您可以下载最新的发行版,也可以寻找特定版本下载,找到相应版本号,下载Assets中的压缩包,两个压缩包内容一致,只是压缩方式不同,根据自身系统选择一个即可。

在这里插入图片描述

源码使用

解压源码,得到如下结构:

在这里插入图片描述

解压得到build目录,我们需要使用的就是其中的three.module.js文件。

注意:three.module.js依赖three.core.js,所以至少要这两个文件。

当然也可以直接访问整个build目录。

html使用源码

我们先用importmap引入需要用到的源码,例如

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>第一个场景</title>
    <script type="importmap">
      {
        "imports": {
          "three": "../../build/three.module.js"
        }
      }
    </script>
  </head>
  <body>
  </body>
</html>

引入路径参考您自己的文件布局。

然后设置js脚本,用于构建threejs项目代码,注意:

1.项目脚本的引入要在包文件之后,因为html中js按顺序执行。

2.项目脚本要使用module类型,这样才可以使用import语法。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>第一个场景</title>
    <script type="importmap">
      {
        "imports": {
          "three": "../../build/three.module.js"
        }
      }
    </script>
  </head>
  <body>
    <!-- 注意引用顺序 -->
    <!-- 本版本基于threejs 174-->
    <script type="module" src="./demo.js"></script>
  </body>
</html>

简易threejs工程

概述

我们的目标是绘制一个正方体,首先来了解一下threejs工程的四要素:

  • Scene(场景)

    场景是 Three.js 中的一个容器,用于存放所有 3D 对象(例如几何体、灯光、相机等)。它就像一个虚拟的“世界”,定义了所有对象的空间。

    所有需要在屏幕上渲染的对象(如网格、灯光)都需要添加到场景中。

    可以类比于电影拍摄的场地。

  • Objects(物体)

    是我们要放入场景中的内容,例如几何体、外部导入的模型等等。

    可以类比于电影的演员和道具。

  • Camera(相机)

    相机定义了观察场景的视角和范围,决定了从哪个角度、以什么方式看到场景。

  • Renderer(渲染器)

    渲染器负责将场景和相机中的内容绘制到屏幕上。每一次渲染(render)相当于用相机给场景拍一次照。

建议配合threejs官网的文档来学习,可以看具体的方法和API。

https://threejs.org/docs/index.html#manual/zh/introduction/Creating-a-scene

1.创建一个场景

//引入three实例
import * as THREE from "three";

//0.确定要渲染的宽高
const sizes = {
  height: 400,
  width: 800,
};

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

有了场景,我们就有了场地,下面就可以布置物体、相机等等。

2.创建一个网格

网格(Mesh)是3D建模中常用的概念,实际就是是一个具体的 3D 对象,由几何体(Geometry)和材质(Material)组成。几何体定义了形状,材质定义了外观。

几何体(Geometry)

几何体定义了一个 3D 对象的形状和结构,由顶点(vertices)和面(faces)组成。

Three.js 提供了很多内置的几何体,比如立方体(BoxGeometry)、球体(SphereGeometry)、圆柱体(CylinderGeometry)等。你也可以自定义几何体。

我们使用BoxGeometry来绘制我们的正方体,传入宽、高、深。

//2.1 物体形状--几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);

材质(Material)

材质定义了对象的外观,比如颜色、光泽、纹理等。

材质决定了一个几何体在渲染时的视觉效果。Three.js 提供了多种材质,例如:

  • MeshBasicMaterial:基础材质,不受光照影响。
  • MeshLambertMaterial:支持漫反射光照。
  • MeshPhongMaterial:支持高光和镜面反射。

我们想创建一个红色立方体,

//2.2 物体样式 -- 材质
const material = new THREE.MeshBasicMaterial({ color: "blue" });

生成网格对象

我们需要依次将几何体和材质添加到网格对象中。

//2.3 用网格模型生成物体
const cube = new THREE.Mesh(geometry, material);

将物体加入场景

为了能让物体在场景中出现,我们需要将物体放入场景中。就好比演员和道具拍电影,你总得让他们加入电影场景才行。

//2.4 将物体放入场景
scene.add(cube);

目前的完整代码

//引入three实例
import * as THREE from "three";

//0.确定要渲染的宽高
const sizes = {
  height: 400,
  width: 800,
};

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

//2.创建物体
//2.1 物体形状--几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
//2.2 物体样式 -- 材质
const material = new THREE.MeshBasicMaterial({ color: "blue" });
//2.3 用网格模型生成物体
const cube = new THREE.Mesh(geometry, material);
//2.4 将物体放入场景
scene.add(cube);

3.架设摄像机

准备好了演员和道具,我们需要把摄像机也加入场景。

three.js 里有几种不同的相机,在这里,我们使用的是 PerspectiveCamera(透视摄像机)。

第一个参数是视野角度(FOV)。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。

第二个参数是长宽比(aspect ratio)。 也就是你用一个物体的宽除以它的高的值。比如说,当你在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的。

//3.创建相机
//3.1 依次传入垂直视野范围
//3.2 渲染区域的宽/长比,确定视角范围
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height);

注意相机位置

默认物体位置是(0,0,0),相机初始位置也是(0,0,0),所以相机实际是被物体挡住了的,甚至在物体里面。

这样相机是拍不到东西的,所以需要跳整二者位置。

当你确定一切添加无误,但是只能看到黑屏却看不到物体时,就可能是相机被遮住了,或者物体不在相机内。

摄像机就好比人眼,你是看不到你身后的事物的。

//3.3 设置相机位置,因为相机默认位置也在(0,0,0),与物体默认位置重叠,我们将看不到物体
camera.position.z = 2;
camera.position.x = 1;
camera.position.y = 0;

将相机放入场景中

//3.4 把相机添加到场景
scene.add(camera);

此时完整代码

//引入three实例
import * as THREE from "three";

//0.确定要渲染的宽高
const sizes = {
  height: 400,
  width: 800,
};

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

//2.创建物体
//2.1 物体形状--几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
//2.2 物体样式 -- 材质
const material = new THREE.MeshBasicMaterial({ color: "blue" });
//2.3 用网格模型生成物体
const cube = new THREE.Mesh(geometry, material);
//2.4 将物体放入场景
scene.add(cube);

//3.创建相机
//3.1 依次传入垂直视野范围
//3.2 渲染区域的宽/长比,确定视角范围
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height);
//3.3 设置相机位置,因为相机默认位置也在(0,0,0),与物体默认位置重叠,我们将看不到物体
camera.position.z = 2;
camera.position.x = 1;

//3.4 把相机添加到场景
scene.add(camera);

4.渲染器渲染

渲染器渲染就好比拍照和放映电影。我们需要设置渲染的位置,这里有两种处理方式:

  • 1.在html中设置canvas,然后将渲染器于canvas绑定,例如:

    <canvas id="first"></canvas>
    

    渲染器绑定

    const renderer = new THREE.WebGLRenderer({
      //4.1 绑定要渲染的画布
      canvas: document.getElementById("first"),
      //4.2 确定渲染画布的大小
      sizes: sizes,
    });
    
  • 第二种是将渲染好的场景直接添加到DOM中

    const renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    
    //将渲染器添加到DOM中
    //具体DOM节点可以自己设置
    document.body.appendChild( renderer.domElement );
    

执行渲染

设置好渲染器后,我们就可以传入场景和相机进行拍照渲染了。

//4.3 将场景和摄像机放入渲染程序
// 每一次渲染就相当于用该相机给场景拍张照片
renderer.render(scene, camera);

5.最终完整代码

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>第一个场景</title>
    <script type="importmap">
      {
        "imports": {
          "three": "../../build/three.module.js"
        }
      }
    </script>
  </head>
  <body>
    <!-- 用于呈现渲染结果,我们无需设定宽高,会被内容自动撑开 -->
    <canvas id="first"></canvas>

    <!-- 注意引用顺序 -->
    <!-- 本版本基于threejs 174 -->
    <script type="module" src="./demo.js"></script>
  </body>
</html>

demo.js

//引入three实例
import * as THREE from "three";

//0.确定要渲染的宽高
const sizes = {
  height: 400,
  width: 800,
};

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

//2.创建物体
//2.1 物体形状--几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
//2.2 物体样式 -- 材质
const material = new THREE.MeshBasicMaterial({ color: "blue" });
//2.3 用网格模型生成物体
const cube = new THREE.Mesh(geometry, material);
//2.4 将物体放入场景
scene.add(cube);

//3.创建相机
//3.1 依次传入垂直视野范围
//3.2 渲染区域的宽/长比,确定视角范围
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height);
//3.3 设置相机位置,因为相机默认位置也在(0,0,0),与物体默认位置重叠,我们将看不到物体
camera.position.z = 2;
camera.position.x = 1;
camera.position.y = 0;

//3.4 把相机添加到场景
scene.add(camera);

//4.添加渲染器,
const renderer = new THREE.WebGLRenderer({
  //4.1 绑定要渲染的画布
  canvas: document.getElementById("first"),
  //4.2 确定渲染画布的大小
  sizes: sizes,
});
//4.3 将场景和摄像机放入渲染程序
// 每一次渲染就相当于用该相机给场景拍张照片
renderer.render(scene, camera);

最终成品

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值