Local Server and build tools

创建好一个html文件后,浏览器打开此时为了安全考虑浏览器会限制网页的功能(例如摄像头)。处理限制问题的方式是使用构建工具或者捆绑(bundler)。

构建工具可以使用:vite、webpack, gulp, parcel

vite优点:

  • 安装快
  • 运行快
  • 不易出错

vite构建工具会对html/css/javascript做构建、优化、缓存破坏、源映射、运行于本地服务器

vite可以添加插件以处理多个特征例如对GLSL文件的支持、React功能的支持.

运行vite时需要Node.js环境。

Node

Node.js® 是一个免费、开源、跨平台的 JavaScript 运行时环境(不需要在浏览器上运行javascript),它让开发人员能够创建服务器、 Web 应用、命令行工具和脚本。

Node.js可以让javascript脱离浏览器网页运行。

  • 安装:https://nodejs.org/en

  • 查看版本:node -v

  • 创建一个Nodejs项目:

    • 建立一个文件夹

    • 在文件夹中: npm init -y

    • 在文件夹下会生成package.json文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      {
      "name": "exercise", //项目名
      "version": "1.0.0",
      "description": "",
      "main": "index.js", //入口文件
      "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "type": "commonjs"
      }
  • 给项目安装插件

    • Vite: npm install vite

      • 项目目录中多了一个node_modules目录(存放所有安装的插件库和插件依赖的库)

      • package.json文件被修改

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        {
        "name": "exercise",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "type": "commonjs",
        "dependencies": { //依赖
        "vite": "^8.0.7" //^代表可容忍的版本
        }
        }
      • 多了一个package-lock.json文件,包含了使用np m安装依赖时的信息。如果有package-lock.json文件npm会尝试使用完全相同的版本,而不是容忍版本。该文件是可选的,存在时其他开发者会得到确切的版本,不存在时会得到容忍版本。

      • json文件的目的是为了项目分享,而不需要直接给其他开发者所有依赖库node_modules

    • Three.js: npm install three

npm:nodejs 包管理工具。

在安装的 nodejs 的时候,npm 也会跟着一起安装,它是包管理工具。

npm 管理 nodejs 中的第三方插件。他的作用与Ruby中的 bundler及Java中的maven相同,都是对第三方依赖进行管理的。

nvm:nodejs 版本管理工具。

也就是说:一个 nvm 可以管理很多 node 版本和 npm 版本。

WebGL

WebGL是一个JavaScript API

  • 可以快速渲染(render)三角形

  • 可以在画布上展示结果

  • 兼容当前的浏览器

  • 使用GPU渲染:一旦几何上的点被放置好(我们看不到点构成的东西),GPU就开始并行的画这些点构成的三角形中的每一个像素使我们看到东西。

    image-20260408192451224
  • 着色器shaders: 命令集合,包含放置点,给像素涂色等

  • 我们需要给着色器信息,包括变换、相机坐标、点的位置、上色等信息

  • 原生的WebGL处理这些内容十分复杂,所以使用Three.js框架帮我们处理WebGL流程。

Three.js

Three.js是一个JavaScript库,MIT授权,是WebGL的上层框架

基础内容

Vite构建项目

1、创建index.html

image-20260408213029039

vscode中输入!会自动生成代码框架

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>03 - First Three.js Project</title>
</head>
<body>
<h1>Soon to be a Three.js Website</h1>
</body>
</html>

不要直接打开index.html文件,违背了初衷(在本地服务器运行该文件,而不是直接使用浏览器)

2、修改package.json配置文件

回到package.json文件修改scripts中的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"name": "exercise",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": { //此处用vite构建和运行
"dev": "vite", //运行命令 开发脚本
"build": "vite build" //构建命令 构建脚本
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"vite": "^8.0.7"
}
}

3、在终端运行dev和build命令(为什么是dev和build因为我们在json文档中起的名字是这两个,可以换成别的)

要在package.json同级目录中运行下面的命令

npm run dev或者npm run build

这个脚本告诉我们:1)触发了vite,2)而vite是依赖关系dependencies中的一部分, 3)vite依赖在node_module目录中

4、复制生成的URL并粘贴到自己的浏览器中

image-20260408215607908

当前终端被卡住用来运行服务器

项目中创建其他javascript脚本

image-20260409171201863

script.js

1
console.log('JavaScript is working!')

index.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>03 - First Three.js Project</title>
</head>
<body>
<h1>Soon to be a Three.js Website</h1>
<script type="module" src="./script.js"></script>
</body>
</html>

script标签中type属性字段用于导入模块,否则script.js中的功能导入不进去。

打开网页的DevTools(F12或者cmd+option+I)

image-20260409185606218

vite使用热重载,保存脚本后自动更新

当vite启动服务器占用终端,如何安装three.js依赖

  • 打开一个新的终端
  • 关掉当前服务器

安装threejs依赖

npm install three

three插件被放到node_modules中,而package.json和package-lock.json包含该依赖的引用

从three依赖包(插件)中导入three.js

在js文件中输入

1
2
3
import * as THREE from 'three' //和python的顺序不一样,其中three是node_module中的three插件包,不需要写出路径例如./node_module/three, node,js(vite)会帮你取到, 模块的别名THREE
//使用模块THREE
console.log(THREE)

THREE模块中包含大多数Three.js中的类和属性

使用THREE模块中的类

  • 实例化

    1
    2
    const scene = new THREE.Scene()
    const sphereGemometry = new THREE.SphereGeometry(1.5, 32, 32)

创建4件东西

  • Scene
  • Objects
    • Mesh:是一个包含几何形状Geometry和材料Material的组建
      • Geometry: BoxGeometry
      • Material: MeshBasicMaterial, 属性包括
        • color:1)0xff0000, 2)‘#ff0000’, 3)‘red’, 4)THREE.Color类的实例
      • 创建Mesh:THREE.Mesh(geometry, material)
    • transform变换组件:
      • position: three.js 中z是前后,x是左右, y是上下
      • rotation
      • scale
    • scene.add(mesh): 将物体网格放入场景中
  • Camera: 没有相机就无法渲染物体,物体就看不到,当渲染时要使用的相机视角,可以有多个相机但只使用其中一个。
    • PerspectiveCamera 主要的参数
      • field of view:视野,透视点的张角
      • aspect ratio: 画布宽高比
    • transform变换组件:
      • position
      • rotation
      • scale
    • 相机加入场景
  • Renderer: 渲染从相机的视角看到的场景,将结果画到画布上(即要求渲染器用相机对着场景拍一张照片)
    • 在html中创建画布canvas
      • 在index.html文件中创建画布标签<canvas>
      • <canvas>标签必须在<script>标签(加载javascript脚本)之前创建
      • <canvas>中使用class属性字段, 可以在javascript中通过canvas的class字段获取(引用)该canvas
    • 在javascript中引用画布canvas,引用对象位置一般放到import导入语句下面,即在开头导入引用
      • document.querySelector(‘<标签名>.<类名>’),该语句是在页面中、页面中的元素中获取东西
    • 创建渲染器
      • WebGLRenderer, 参数是一个包含画布canvas的对象
        • WebGLRenderer({canvas:canvas})
    • 调整渲染器属性
      • size:setSize(size.width, size.height)
    • 开始渲染
      • renderer.render(scene, camera)

script.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import * as THREE from 'three'

//引用画布
const canvas = document.querySelector('canvas.webgl')

//scene
const scene = new THREE.Scene()

//objects
//geometry
const geometry = new THREE.BoxGeometry(1,1,1)
//material
const material = new THREE.MeshBasicMaterial({color:0xff0000})
//mesh
const mesh = new THREE.Mesh(geometry, material)
//add mesh to scene
scene.add(mesh)

//camera
//size
const sizes = {
width: 800,
height: 600
}
const camera = new THREE.PerspectiveCamera(75, sizes.width/sizes.height)
camera.position.z = 3
scene.add(camera)

//renderer
const renderer = new THREE.WebGLRenderer({canvas: canvas})
renderer.setSize(sizes.width, sizes.height)
renderer.render(scene, camera)

index.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>03 - First Three.js Project</title>
</head>
<body>
<canvas class="webgl"></canvas>
<script type="module" src="./script.js"></script>
</body>
</html>

image-20260409220254697

如果不设置物体、相机加入场景中的位置,默认是在场景中心,相机在立方物体内部,相机看不到任何东西。

image-20260409221853776

image-20260409222043235

可以看到立方物体是由三角形拼成的。

如何使用别人分享的项目

image-20260410192017205

这是一个别人共享的项目,没有依赖包node_module目录和package-lock.json,通过在项目目录中(和package.json同级)运行npm install来创建node_module依赖包目录和package-lock.json。

此项目中使用npm run dev后会出现两个URL,同时会自动在浏览器中打开URL。

image-20260410194029112

这是由于vite.config.js配置文件的关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import restart from 'vite-plugin-restart'

export default { //导出一对象
root: 'src/', // Sources files (typically where index.html is)
publicDir: '../static/', // Path from "root" to static assets (files that are served as they are)
server:
{
host: true, // Open to local network and display URL
open: !('SANDBOX_URL' in process.env || 'CODESANDBOX_HOST' in process.env) // Open if it's not a CodeSandbox
},
build:
{
outDir: '../dist', // Output in the dist/ folder
emptyOutDir: true, // Empty the folder first
sourcemap: true // Add sourcemap
},
plugins:
[
restart({ restart: [ '../static/**', ] }) // Restart server on static file change
],
}

static文件夹中用于存放一些资源文件例如图片、音频、视频、纹理、模型、字体等或目录。你只需要在url路径中输入static目录中的文件或目录就可以改变方块材质(不需要输入static目录),例如http://localhost:5173/door.jpg

物体变换

transform4个属性

  • position?: THREE.Vector3(右手系),加粗为正轴

    • x:左

    • y:

    • z:

    • Vector3类方法

      • length():场景中心到点的距离

      • one.position.distanceTo(another.position): 两个指定点的距离

        1
        mesh.position.distanceTo(new THREE.Vector3(0,1,2))
      • normalize():向量长度归一化

      • set(x,y,z): 设置当前坐标位置

  • scale?:THREE.Vector3

    • position
  • rotation或者quaternion

    • rotation?: THREE.Euler
      • yaw偏航:沿y轴旋转
      • pitch俯仰:沿x轴旋转
      • roll翻滚:沿z轴旋转
      • 问题:1、万向锁(中间轴旋转90度),2、90度附近的出现不连续的角度变化。
      • 解决:1、改变旋转轴的旋转顺序
      • mesh.rotation.reorder(‘yxz’) 该语句必须放在旋转坐标轴之前使用才能看到效果,否则显示的依旧是之前的结果,新的旋转次序没有被使用。
    • quaternion
      • 四元数$(x,y,z,w=cos(\frac{\theta}{2}))$随旋转轴和角度更新
    • lookAt(new THREE.Vector3(0,-1,0)):3D物体的lookAt方法可以平移视角

组成一个变换矩阵,注意:变换必须放到渲染部分之前才能看到效果,通常放到创建对象之后,对象加入场景之前

辅助功能

  • THEE.AxesHelpher(size?:number):显示坐标轴, 参数size设置轴的长短
    • 创建完后需要加入场景

高级技术

着色器

其他

便携场景

React Three Fiber