最近学习Three.js,此贴供学习记录之用。
学习视频:Three.js教程。讲解很详细,也有配套的笔记,但不包含前端基础知识的讲解,如果是纯小白的朋友,可以找这位up之前的教程学习一下。
附:此贴记录时间在前期工作(包括环境配置、软件和插件下载等)都准备好之后,在macOS系统,使用VScode编写。
三维场景显示在我们的屏幕中总共分三步:
在写.js文件之前
- 使用importmaps配置路径
关于importmaps具体的讲解请看这里
<!-- importmap导入映射 -->
<script type="importmap">
{
"imports": {
"three": "./three.js/build/three.module.js"
}
}
</script>
⚠️注:若不使用importmap配置,而是在.js文件中直接引入,在使用其他控件时可能会遇到浏览器控制台报错"TypeError: Module name, ‘three’ does not resolve to a valid URL.
",博主尚未想明白是什么原因🥲。
- .html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js入门①</title>
</head>
<body>
<div id="webgl" style="margin: 100px; background-color: blueviolet;"></div>
<!-- importmap导入映射 -->
<script type="importmap">
{
"imports": {
"three": "./three.js/build/three.module.js"
}
}
</script>
<!-- 引入.js文件 -->
<script src="./0503_1.js" type="module"></script>
</body>
</html>
一、创建一个三维场景
- 引入js
// 引入three.js
import * as THREE from 'three';
- 创建一个三维场景
// 创建一个三维场景
const scene = new THREE.Scene();
- 加入辅助观察坐标系
// 添加辅助观察坐标系
const axesHelper = new THREE.axesHelper(100); // x,y,z,长度均为100,也可以写成(100, 100, 100)
// 将坐标系加入场景
scene.add(axesHelper);
三维场景中的物体
- 创建物体(形状)
// 添加物体 几何体,长方体,定义长宽高
const geometry = new THREE.BoxGeometry(50, 50, 50);
- 创建材质对象(外观)
这里将材质设置为半透明以便更好观察辅助坐标系
// 创建材质对象
const material = new THREE.MeshBasicMaterial({
color: 0xff0000, // 颜色
transparent: true, // 设置透明
opacity: 0.5 // 透明度
});
- 创建网格模型(实体)
// 创建网格模型 参数:形状,材质
const mesh = new THREE.Mesh(geometry, material);
- 设置物体位置
// 设置模型在三维空间位置
mesh.position.set(0, 0, 0);
- 添加物体到场景中
// 添加物体
scene.add(mesh);
二、加入摄影机
- 设置在屏幕中显示的尺寸,即画布尺寸
// 设置画布尺寸
const width = 800;
const height = 500;
- 创建相机对象并设置参数
透视投影摄像机参数:
fov: 视场角度 模拟观察范围,在此范围内的物体予以显示
aspect: 视锥水平和竖直方向长度比 常与画布大小相同
near: 视锥近截面距相机距离
far: 视锥远截面距相机距离
// 创建相机对象 设置参数
const camera = new THREE.PerspectiveCamera(30, width/height, 0.1, 3000);
- 设置相机的位置
// 相机位置设置
camera.position.set(200, 200, 200);
- 设置观察目标
// 设置观察目标
camera.lookAt(0, 0, 0); // 观察原点
camera.lookAt(mesh.position); // 观察物体mesh位置
三、对场景进行渲染
- 创建WebGL渲染器对象
// 创建WebGL渲染器对象
const renderer = new THREE.WebGLRenderer();
- 设置Canvas画布
// 设置画布
renderer.setSize(width, height);
- 渲染器执行渲染方法
// 执行渲染方法 对哪个场景使用哪个相机进行拍照
renderer.render(scene, camera);
- 将元素插入
// 插入body
document.body.appendChild(renderer.domElement);
// 插入指定位置
document.getElementById("webgl").appendChild(renderer.domElement); // renderer.domElement为一个HTML元素
完整.js文件
// 引入three.js
import * as THREE from 'three';
// 创建一个三维场景
const scene = new THREE.Scene();
// 添加辅助观察坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
// 添加物体 几何体,长方体,定义长宽高
const geometry = new THREE.BoxGeometry(50, 50, 50);
// 创建材质对象
const material = new THREE.MeshBasicMaterial({
color:0xff0000,
transparent: true, // 设置透明
opacity: 0.5 // 透明度
});
// 创建网格模型 给出物体及材质
const mesh = new THREE.Mesh(geometry, material);
// 设置模型在三维空间中的位置
mesh.position.set(0, 10, 0);
// 将物体添加到场景中
scene.add(mesh);
// 控制台打印
console.log("mesh", mesh);
// 设置画布尺寸(单位:px)
const width = 800;
const height = 500;
// 创建相机对象 设置相机参数
/*
fov: 视场角度 模拟观察范围,物体需在视场范围内才可显示
aspect: 视锥水平和竖直方向长度比 通常与画布大小相同
near: 视锥近裁截面对相机距离
far: 视锥远裁截面对相机距离
*/
const camera = new THREE.PerspectiveCamera(30, width/height, 0.1, 3000);
// 设置相机位置
camera.position.set(200, 200, 200);
// 相机观察目标
camera.lookAt(mesh.position); // 指向某个物体 网格模型mesh
// 创建WebGL渲染器对象
const renderer = new THREE.WebGLRenderer();
// 设置Canvas画布尺寸
renderer.setSize(width, height);
// 渲染器执行渲染方法 使用哪个相机对哪个场景进行拍照
renderer.render(scene, camera);
// 获得渲染方法.render()生成的Canvas画布
// 将Canvas画布插入特定元素位置
document.getElementById("webgl").appendChild(renderer.domElement); // renderer.domElement为一个HTML元素
- 效果(辣眼睛配色hhhhhh)
画布Canvas的全屏显示
画布也是一种html元素,故three.js渲染输出的Canvas画布的布局方法与普通web前端相同。
const width = window.innerWidth; //窗口文档显示区的宽度作为画布宽度
const height = window.innerHeight; //窗口文档显示区的高度作为画布高度
- 此时Canvas的显示:
可以看到上图的Canvas左侧和上侧均有白边,若要实现完全的全屏显示,还需要修改一下body元素的css设置。
<style>
body{
overflow: hidden;
margin: 0;
}
</style>
- 修改后:
Canvas画布宽高度动态变化
Canvas画布宽高度动态变化,需要更新相机和渲染的参数,才能正常渲染。
// onresize 事件会在窗口被调整大小时发生
window.onresize = function () {
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 全屏情况下:设置观察范围长宽比aspect为窗口宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix();
};