Appearance
❤three.js
搭建+vue3
1、简介
地址:
threejs官网
JS
https://threejs.org/
three.js中文官网
JS
https://www.webgl3d.cn/
github各个版本:
JS
// 官方英文网地址
https://github.com/mrdoob/three.js/tags
//中文网地址
http://www.webgl3d.cn/pages/aac9ab/
github地址:
threejs官方文件包
JS
// threejs官方文件包地址
https://github.com/mrdoob/three.js/releases
//threejs官方文件包所有版本
https://github.com/mrdoob/three.js/releases
// Threejs中文网(电子书课件)
http://www.webgl3d.cn
// Threejs官网中文文档链接
https://threejs.org/docs/index.html#manual/zh/
概念
three.js是JavaScript编写的WebGL第三方库。提供了非常多的3D显示功能
什么是threejs,很简单,你将它理解成three + js就可以了。three表示3D的意思,js表示javascript的意思。那么合起来,three.js就是使用javascript来写3D程序的意思。Javascript是运行在网页端的脚本语言,那么毫无疑问Three.js也是运行在浏览器上的
three.js其实是依靠与Canvas画布的3D绘图功能,threejs渲染的三维效果图就是呈现在Canvas画布上面。
功能
Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象。你可以在它的主页上看到许多精彩的演示。
three.js所包含的知识和技巧
目录简介
Build目录:主要的两个文件three.min.js,three.js。
Docs目录:这里是three.js的帮助文档,里面是各个函数的api,可惜并没有详细的解释。试图用这些文档来学会three.js是不可能的。
Editor目录:一个类似3D-max的简单编辑程序,它能创建一些三维物体。
Examples目录:一些例子demo,可惜没有文档介绍。对图像学理解不深入的同学,学习成本非常高。
Src目录:源代码目录,里面是所有源代码。
Test目录:一些测试代码,基本没用
2、安装使用
three.js 安装
js
在vue3之中安装使用
yarn add three --save
npm的方式
npm install --save three
vite npm install --save-dev vite
(这里我采用的yarn安装,全面拥抱yarn,确实比那个npm好用,哈哈 ^_^)
CDN
js
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
<script type="importmap">{ "imports": { "three": "https://unpkg.com/three@<version>/build/three.module.js", "three/addons/": "https://unpkg.com/three@<version>/examples/jsm/" } }
</script>
3、实现一个简单的3D球体
接下来我们创建一个简单的3D球体,并添加到场景中。
先看看我们最后实现的效果
代码如下:
构建我们的结构
js
<template>
<div ref="container"></div>
</template>
(1)引入我们需要的元素并且创建变量来进行存储three之中的场景,相机,渲染器以及球体这个对象
- 使用
script setup
语法进行组件的设置。 - 引入了 Vue 3 的
onMounted
和ref
方法,以及 Three.js 库中的THREE
对象。 - 创建了一些变量来存储 Three.js 中的场景、相机、渲染器和球体对象。
(2)引入我们生命周期钩子函数并且写一个事件监听
onMounted
钩子:组件挂载到 DOM 后立即执行用于设置 Three.js 场景、相机和渲染器,这个时候同时我们开始动画循环。animate
函数:球体转动的每一帧过程之中更新球体的旋转角度,使用渲染器将场景渲染到页面上。onWindowResize
函数:窗口大小调整时更新相机的长宽比例和渲染器的大小,让内容适应新的窗口大小。
(3)总结
上面整个过程就是我们创建一个 Vue 3 组件,渲染一个带有旋转效果的 3D 球体,实现了基本的 3D 绘制和动画。
接下来看一下我们的代码然后不断理解其中带给我们的概念。
js
<script setup>
import { onMounted, ref } from 'vue';
import * as THREE from 'three';
// 创建对 DOM 元素的引用
const container = ref(null);
let scene, camera, renderer, sphere;
onMounted(() => {
// 创建场景
scene = new THREE.Scene();
// 创建相机
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// 创建渲染器
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
container.value.appendChild(renderer.domElement);
// 创建一个球体
const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true });
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
// 动画循环
function animate() {
requestAnimationFrame(animate);
// 旋转球体
sphere.rotation.x += 0.01;
sphere.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
// 处理窗口大小调整
window.addEventListener('resize', onWindowResize);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
});
</script>
4、具体概念和参数的理解
先来看看我们通过参数调整的图形效果
4-0、canvas画布
这里我们直接跳过这个画布概念,做前端的应该都知道
接下来我们学习一些three之中的概念,这些概念能够帮助我们更好的理解three
4-1、三维场景Scene
理解three的理念。首先要理解我们的第一个概念--场景
在three之中,场景可以说是所有部分的起始,就类似我们构建一个虚拟世界,首先得有一个场景,故事才开始娓娓道来一样
three之中场景好比容器,将对象、模型、粒子、灯光等放入指定场景之中
js
const scene = new THREE.Scene()
完整代码我们打印输出看看这个场景究竟是什么
js
<script src="./three.js"></script>
<script>
//随便输入一个API,测试下是否已经正常引入three.js
console.log(THREE.Scene);
</script>
JS
class Scene extends Object3D {
constructor() {
super(); // 调用父类的构造函数
this.isScene = true; // 标识是否为场景对象
this.type = 'Scene'; // 类型标识
this.background = null; // 背景(默认为 null)
this.environment = null; // 环境(默认为 null)
this.fog = null; // 雾效(默认为 null)
this.overrideMaterial = null; // 覆盖材质(默认为 null)
this.autoUpdate = true; // 是否自动更新(默认为 true)
}
// 设置背景方法
setBackground(background) {
this.background = background;
}
// 设置环境方法
setEnvironment(environment) {
this.environment = environment;
}
// 设置雾效方法
setFog(fog) {
this.fog = fog;
}
// 设置覆盖材质方法
setOverrideMaterial(material) {
this.overrideMaterial = material;
}
// 设置自动更新
setAutoUpdate(autoUpdate) {
this.autoUpdate = autoUpdate;
}
// 更新方法,通常在每帧渲染时调用
update() {
if (this.autoUpdate) {
// 在此处加入你需要每帧更新的内容
console.log("Scene is updating...");
}
}
}
这里我们可以看出,其实就是简单得一个类得函数,其中包含了我们需要的各种东西
那么场景如何确定你在页面上得位置呢,这个时候就需要用到threejs得三维坐标系
threejs三维坐标系
哲理threejs里面定位使用的是三维直角坐标系(其实就是我们初高中三位坐标里面得---三维笛卡尔坐标系
)去定位。
还记得初高中老师教的我们拿手指头去衡量吗?就跟下图之中所示的差不多
对象
创造了场景,这个时候我们就可以想着往里面加点什么了,加的这个对象就是threejs之中的对象的概念,可以是自己创造的几何体,也可以是我们的网络模型
几何体
这里我们虽然创建了几何体,但是就跟画画一样,你画的东西,现在是无色的啊
所以其实我们整个过程其实是:
创建一个几何体(Geometry)和材质(Material),并将它们组合成一个网格对象(Mesh)
也就是类似下面这段代码
js
//1. 长方体形状
const geometry = new THREE.BoxGeometry(100, 100, 100);
//2. 长方体材质
const material = new THREE.MeshBasicMaterial({
color: 0x0000ff,
});
//3. 长方体网格模型Mesh
const mesh = new THREE.Mesh(geometry, material);
//4. 长方体添加到虚拟场景中
scene.add(mesh);
这里我们需要注意的就是这个颜色值应该是一个十六进制格式的
js
十六进制颜色代码中,金色的标准表示是 `#FFD700`,所以我们这里使用的就是
const material = new THREE.MeshBasicMaterial({ color: 0xFFD700 });
4-2 相机Camera
想把我们之前创建的三维场景Scene
渲染到web网页上,还需要定义一个虚拟相机Camera
。
怎么理解这个相机呢,你可以想象成你需要对上面的那个几何体拍个照片给别人,否则别人也看不到啊。
透视投影相机PerspectiveCamera
如何实例化一个透视投影相机呢
js
// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera();
//这里我们使用一下
// 创建相机
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
4-3 WebGL渲染器WebGLRenderer
有了场景,也有了几何体,手上也有了相机,那这个时候,总要有个人用相机吧,渲染器WebGLRenderer
就是做这个用处的
创建
js
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer({
canvas:canvas//渲染结果输出画布:canvas
});
渲染
js
renderer.render(scene, camera); //执行渲染操作
渲染器Canvas画布属性.domElement
这里我们是进行了渲染,那如何进行相关的canvas样式的更改呢?
.domElement
本质上就是一个HTML元素:Canvas画布
那这里我们如何插入呢,这里我们插入页面之中试试(其实就是插入你之前拍下的照片)
js
document.body.appendChild(renderer.domElement);
4-4 动画渲染循环
threejs可以借助HTML5的API请求动画帧window.requestAnimationFrame
实现动画渲染
看看官方给我们的介绍,这一看,可不就是直接调用的请求动画帧被
js
// requestAnimationFrame实现周期性循环执行
function render() {
requestAnimationFrame(render);//请求再次执行函数render
}
render();
概念我们都学完了,那接下来就拿个html写个旋转的不管啥先瞅瞅呗
看,是不是跟我们开头的几乎一模一样,所以知道了基础的一些概念,自己写一个球体已经很简单了。
js
.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- <canvas style="background: black;" width="800" height="800"></canvas> -->
<script src="./three.js"></script>
<script>
// 创建场景 Scene
const scene = new THREE.Scene();
console.log(THREE.Scene); //随便输入一个API,测试下是否已经正常引入three.js
// 创建透视相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// 创建 WebGL 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// canvas.appendChild(renderer.domElement);
const geometry = new THREE.SphereGeometry(1, 32, 32); // 创建一个几何体
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 , wireframe: true}); // 创建一个基本材质并设置颜色
const cube = new THREE.Mesh(geometry, material);// 将几何体和材质组合成一个网格对象
scene.add(cube);// 将立方体添加到场景中
// 创建动画循环
function animate() {
requestAnimationFrame(animate);
// 使立方体旋转
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 渲染场景和相机
renderer.render(scene, camera);
}
// 开始动画循环
animate();
</script>
</body>
</html>
4-5 vue3之中使用(ref方式)
在普通的html页面之中我们使用没问题,那么接下来我们就该挪进去vue3组件之中了,那这个时候我们又改如何使用呢?
vue3组件之中还是一样,只不过vue3需要通过ref标记获取HTML元素方式
下面就是我们的元素
js
<script setup>
import { ref } from 'vue'
const webgl = ref(null);
</script>
<template>
<div ref="webgl">
</div>
</template>
<script setup>
import { ref } from 'vue'
import { onMounted } from 'vue'
import * as THREE from 'three';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(30,width/height,1,3000);
// WebGL渲染器
const renderer = new THREE.WebGLRenderer();
...
// 原来canvas直接插入body代码删除
// document.body.appendChild(renderer.domElement);
export default renderer;
const webgl = ref(null);
onMounted(() => {
//webgl.value:表示ref值为webgl的div元素
webgl.value.appendChild(renderer.domElement);
});
</script>
后面可以抽离出我们经常用多的部分
import renderer from './twin.js';//获取到threejswebgl的渲染器对象
看看我们的效果,调整一下颜色
js
renderer.setClearColor(0xFFFFFF); // 设置背景颜色为金色
直接使用我们的渲染器给渲染个呗,ok
5、进阶
普通的一个我们实现了,那么接下来我们给他加一些花里胡哨的操作
从右侧加个光模拟一下大爆炸的感觉
js
// 设置场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建一个简单的立方体以观察光照效果
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 ,antialias: true});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 添加地面
const planeGeometry = new THREE.PlaneGeometry(200, 200);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x808080, side: THREE.DoubleSide });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = Math.PI / 2; // 使平面水平放置
plane.position.y = -1; // 调整平面位置
scene.add(plane);
// 创建一个球体作为光源的表示
const sphereGeometry = new THREE.SphereGeometry(1, 10, 10);// 创建一个几何体
const sphereMaterial = new THREE.MeshBasicMaterial({ color: 0xFFD700 , wireframe: true}); // 创建一个基本材质并设置颜色
const lightSphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // 将几何体和材质组合成一个网格对象
scene.add(lightSphere);
// 添加点光源
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
scene.add(pointLight);
// 将光源和球体移动到初始位置(右上角)
lightSphere.position.set(2, 2, 2);
pointLight.position.copy(lightSphere.position);
camera.position.z = 5;
// 动画函数
function animate() {
requestAnimationFrame(animate);
// 光源向下移动
lightSphere.position.y -= 0.01;
pointLight.position.copy(lightSphere.position);
renderer.render(scene, camera);
}
animate();
只有细细体会,自己才能感觉到,3D的世界!