Three.js简介概述
three.js是世界上最流行的用于在Web上显示3D内容的JavaScript框架。
Three.js概述
Three.js 是基于 WebGL 技术,用于浏览器中开发 3D 交互场景的 JS 引擎。
默认 WebGL 只支持简单的 点、线、三角,Three.js 就是在此 WebGL 基础之上,封装出强大且使用起来简单的 JS 3D 类库。 目前主流现代浏览器都已支持 WebGL,也意味着支持 Three.js。
Three.js优缺点
🟢 优点
- 基于WebGL技术:Three.js建立在WebGL之上,利用了浏览器的硬件加速能力,能够高效地进行3D渲染,实现流畅的交互体验。
- 易用性:相比直接使用原始的WebGL,Three.js提供了更高级的抽象和封装,使得开发者能够更轻松地创建复杂的3D场景,降低了学习和使用的门槛。
- 跨平台性:Three.js基于Web技术,能够在主流现代浏览器上运行,包括桌面端和移动端,实现了跨平台的兼容性。
🔴 缺点
- 不擅长物理碰撞:虽然Three.js能够实现复杂的3D场景渲染,但其并不擅长处理物理碰撞,这使得它在开发3D游戏等需要物理交互的应用时显得力不从心。
- 学习曲线:尽管相比原始的WebGL,Three.js提供了更高级的抽象和封装,但仍然需要一定的学习成本,特别是对于新手来说,需要掌握一定的3D图形学知识和API使用方法。
- 性能依赖于硬件:由于Three.js是基于WebGL技术的,其性能受限于用户设备的硬件性能,较低配置的设备可能无法实现流畅的渲染效果。
- 不适合大规模应用:虽然Three.js能够满足一般的3D场景需求,但在需要处理大规模数据或者复杂计算的情况下,可能会遇到性能瓶颈。
官网示例
Three.js应用场景
🔍 3D 可视化:Three.js 可以用于创建各种 3D 可视化应用,如数据可视化、科学可视化、工程可视化等。用户可以通过浏览器在线查看和操作 3D 模型,而无需安装任何插件或额外的软件。
🔍 虚拟现实和增强现实:Three.js 可以用于创建虚拟现实(VR)和增强现实(AR)应用,如游戏、教育、培训、设计等。用户可以通过 VR 设备和 AR 设备在 3D 空间中浏览和操作 3D 模型,获得更加沉浸式的体验。
🔍 动画和特效:Three.js 可以用于创建各种 3D 动画和特效,如电影、电视、游戏、广告等。用户可以通过浏览器在线观看和互动 3D 动画和特效,而无需安装任何插件或额外的软件。
🔍 游戏开发:Three.js 可以用于创建各种 3D 游戏,如角色扮演游戏、射击游戏、策略游戏等。用户可以通过浏览器在线玩 3D 游戏,而无需安装任何插件或额外的软件。
🔍 产品展示和演示:Three.js 可以用于创建各种 3D 产品展示和演示,如家具、汽车、电子产品等。用户可以通过浏览器在线查看和操作 3D 模型,了解产品的外观、性能和功能,提高购买决策的准确性。
🔍 建筑和城市规划:Three.js 可以用于创建各种 3D 建筑和城市规划应用,如房地产开发、城市规划、景观设计等。用户可以通过浏览器在线查看和操作 3D 模型,了解项目的设计理念和实施效果,提高决策的准确性。
Three.js技术名词
3大核心关键模块
🐔 场景(Scene):
场景是 Three.js 中的一个核心概念,它是所有 3D 对象的容器。场景可以包含几何体、光源、相机等,它们共同构成了一个完整的 3D 世界。在 Three.js 中,场景是通过 THREE.Scene
类来表示的。
🐔 相机(Camera):
相机是 Three.js 中的另一个核心概念,它负责捕捉 3D 世界中的对象,并将它们渲染到屏幕上。Three.js 提供了多种相机类型,如正交相机(THREE.OrthographicCamera
)和透视相机(THREE.PerspectiveCamera
),以满足不同的渲染需求。
🐔 渲染器(Renderer):
渲染器是 Three.js 中的另一个核心概念,它负责将 3D 世界中的对象渲染到屏幕上。Three.js 提供了多种渲染器类型,如 WebGL 渲染器(THREE.WebGLRenderer
)和 Canvas 渲染器(THREE.CanvasRenderer
),以满足不同的渲染需求。
以下是一个简单的 Three.js 示例,展示了如何创建一个场景、相机和渲染器:
// 创建场景
var scene = new THREE.Scene();
// 创建相机
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 创建渲染器
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 渲染场景
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
在这个示例中,我们创建了一个场景、一个透视相机和一个 WebGL 渲染器。然后,我们将渲染器的 DOM 元素添加到页面中,并使用 requestAnimationFrame 函数来实现动画效果。
其他技术关键词
💯 几何体(Geometry):
几何体是 Three.js 中的一个核心概念,它表示 3D 世界中的物体的形状。Three.js 提供了多种几何体类型,如立方体(THREE.BoxGeometry
)、球体(THREE.SphereGeometry
)、圆锥体(THREE.ConeGeometry
)等。
💯 材质(Material):
材质是 Three.js 中的一个核心概念,它表示 3D 世界中的物体的表面特性,如颜色、纹理、光照等。Three.js 提供了多种材质类型,如基本材质(THREE.MeshBasicMaterial
)、兰伯特材质(THREE.MeshLambertMaterial
)、冯氏材质(THREE.MeshPhongMaterial
)等。
💯 光源(Light):
光源是 Three.js 中的一个核心概念,它表示 3D 世界中的光源,可以对物体的表面产生影响。Three.js 提供了多种光源类型,如平行光(THREE.DirectionalLight
)、点光源(THREE.PointLight
)、聚光灯(THREE.SpotLight
)等。
💯 网格(Mesh):
网格是 Three.js 中的一个核心概念,它表示 3D 世界中的物体,由几何体和材质组成。Three.js 提供了 THREE.Mesh
类来表示网格。
💯 纹理(Texture):
纹理是 Three.js 中的一个核心概念,它表示 3D 世界中的物体的表面贴图。Three.js 提供了多种纹理类型,如图片纹理(THREE.Texture
)、立方体纹理(THREE.CubeTexture
)、视频纹理(THREE.VideoTexture
)等。
💯 动画(Animation):
动画是 Three.js 中的一个核心概念,它表示 3D 世界中的物体的运动和变化。Three.js 提供了多种动画类型,如骨骼动画(THREE.Skeleton
)、变换动画(THREE.TransformControls
)等。
💯 碰撞检测(Collision Detection):
碰撞检测是 Three.js 中的一个核心概念,它表示 3D 世界中的物体之间的碰撞和接触。Three.js 提供了多种碰撞检测算法,如轴对齐边界框(AABB)、球面边界框(Sphere)等。
以下是一个简单的 Three.js 示例,展示了如何创建一个几何体、材质和网格,并将其添加到场景中:
// 创建几何体
var geometry = new THREE.BoxGeometry(1, 1, 1);
// 创建材质
var material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
// 创建网格
var mesh = new THREE.Mesh(geometry, material);
// 将网格添加到场景中
scene.add(mesh);
在这个示例中,我们创建了一个立方体几何体、一个基本材质和一个网格,并将其添加到场景中。然后,我们使用 requestAnimationFrame
函数来实现动画效果。
以上提到的所有关键词和概念,在后续学习过程中,逐个细致学习掌握。加油!!!
表演个小示例
👽 创建 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<!-- 引入初始化样式 -->
<link rel="stylesheet" href="./reset.css" />
</head>
<body>
<!-- 使用模块化方式引入入口文件 -->
<script src="./goboy.js" type="module"></script>
<div id="stage"></div>
<canvas id="text" width="700" height="200"></canvas>
<input id="input" type="text" value="GoBoy IS ME"/>
</body>
</html>
👽 创建 goboy.js
// 导入 THREE 库
import * as THREE from 'three';
// 定义变量
var height,
width,
container,
scene,
camera,
renderer,
particles = [],
mouseVector = new THREE.Vector3(0, 0, 0),
mousePos = new THREE.Vector3(0, 0, 0),
cameraLookAt = new THREE.Vector3(0, 0, 0),
cameraTarget = new THREE.Vector3(0, 0, 800), // 摄像机的目标位置
textCanvas,
textCtx,
textPixels = [],
input;
// 粒子的颜色数组
var colors = ['#F7A541', '#F45D4C', '#FA2E59', '#4783c3', '#9c6cb7'];
// 初始化舞台,设置宽度和高度,并添加事件监听器
function initStage() {
width = window.innerWidth;
height = window.innerHeight;
container = document.getElementById('stage');
window.addEventListener('resize', resize); // 监听窗口大小变化事件
container.addEventListener('mousemove', mousemove); // 监听鼠标移动事件
}
// 初始化场景
function initScene() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({
alpha: true, // 设置透明度
antialias: true // 开启抗锯齿
});
renderer.setPixelRatio(window.devicePixelRatio); // 设置像素比
renderer.setSize(width, height); // 设置渲染器大小
container.appendChild(renderer.domElement); // 将渲染器添加到 DOM 中
}
// 随机生成粒子的初始位置
function randomPos(vector) {
var radius = width * 3;
var centerX = 0;
var centerY = 0;
var r = width + radius * Math.random();
var angle = Math.random() * Math.PI * 2;
vector.x = centerX + r * Math.cos(angle);
vector.y = centerY + r * Math.sin(angle);
}
// 初始化摄像机
function initCamera() {
var fieldOfView = 75;
var aspectRatio = width / height;
var nearPlane = 1;
var farPlane = 3000;
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane
);
camera.position.z = 800; // 设置摄像机位置
}
// 创建光源
function createLights() {
// 创建方向光源
var shadowLight = new THREE.DirectionalLight(0xffffff, 2);
shadowLight.position.set(20, 0, 10);
shadowLight.castShadow = true; // 投射阴影
shadowLight.shadowDarkness = 0.01; // 阴影深度
scene.add(shadowLight);
// 创建方向光源
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.set(-20, 0, 20);
scene.add(light);
// 创建方向光源
var backLight = new THREE.DirectionalLight(0xffffff, 0.8);
backLight.position.set(0, 0, -20);
scene.add(backLight);
}
// 定义粒子构造函数
function Particle() {
this.vx = Math.random() * 0.05; // x 方向速度
this.vy = Math.random() * 0.05; // y 方向速度
}
// 粒子的初始化方法
Particle.prototype.init = function(i) {
var particle = new THREE.Object3D();
var geometryCore = new THREE.BoxGeometry(20, 20, 20); // 创建几何体
var materialCore = new THREE.MeshLambertMaterial({
color: colors[i % colors.length], // 随机选择颜色
shading: THREE.FlatShading // 设置着色方式
});
var box = new THREE.Mesh(geometryCore, materialCore);
box.geometry.__dirtyVertices = true;
box.geometry.dynamic = true;
particle.targetPosition = new THREE.Vector3(
(textPixels[i].x - width / 2) * 4,
textPixels[i].y * 5,
-10 * Math.random() + 20
);
particle.position.set(width * 0.5, height * 0.5, -10 * Math.random() + 20);
randomPos(particle.position);
// 修改顶点的位置
var positionAttribute = box.geometry.attributes.position;
if (positionAttribute) {
var positions = positionAttribute.array;
for (var i = 0; i < positions.length; i += 3) {
positions[i] += -10 + Math.random() * 20;
positions[i + 1] += -10 + Math.random() * 20;
positions[i + 2] += -10 + Math.random() * 20;
}
positionAttribute.needsUpdate = true;
} else {
console.error("Geometry does not have position attribute.");
}
particle.add(box);
this.particle = particle;
};
// 更新粒子的旋转角度
Particle.prototype.updateRotation = function() {
this.particle.rotation.x += this.vx;
this.particle.rotation.y += this.vy;
};
// 更新粒子的位置
Particle.prototype.updatePosition = function() {
this.particle.position.lerp(this.particle.targetPosition, 0.02);
};
// 渲染场景
function render() {
renderer.render(scene, camera);
}
// 更新粒子状态
function updateParticles() {
for (var i = 0, l = particles.length; i < l; i++) {
particles[i].updateRotation();
particles[i].updatePosition();
}
}
// 设置粒子的位置
function setParticles() {
for (var i = 0; i < textPixels.length; i++) {
if (particles[i]) {
particles[i].particle.targetPosition.x =
(textPixels[i].x - width / 2) * 4;
particles[i].particle.targetPosition.y = textPixels[i].y * 5;
particles[i].particle.targetPosition.z = -10 * Math.random() + 20;
} else {
var p = new Particle();
p.init(i);
scene.add(p.particle);
particles[i] = p;
}
}
for (var i = textPixels.length; i < particles.length; i++) {
randomPos(particles[i].particle.targetPosition);
}
}
// 初始化画布
function initCanvas() {
textCanvas = document.getElementById('text');
textCanvas.style.width = width + 'px';
textCanvas.style.height = 200 + 'px';
textCanvas.width = width;
textCanvas.height = 200;
textCtx = textCanvas.getContext('2d');
textCtx.font = '700 100px Arial';
textCtx.fillStyle = '#555';
}
// 初始化输入框
function initInput() {
input = document.getElementById('input');
input.addEventListener('keyup', updateText);
input.value = 'GoBoy IS ME';
}
// 更新文本内容
function updateText() {
var fontSize = width / (input.value.length * 1.3);
if (fontSize > 120) fontSize = 120;
textCtx.font = '700 ' + fontSize + 'px Arial';
textCtx.clearRect(0, 0, width, 200);
textCtx.textAlign = 'center';
textCtx.textBaseline = 'middle';
textCtx.fillText(input.value.toUpperCase(), width / 2, 50);
var pix = textCtx.getImageData(0, 0, width, 200).data;
textPixels = [];
for (var i = pix.length; i >= 0; i -= 4) {
if (pix[i] != 0) {
var x = (i / 4) % width;
var y = Math.floor(Math.floor(i / width) / 4);
if (x && x % 6 == 0 && y && y % 6 == 0)
textPixels.push({
x: x,
y: 200 - y + -120
});
}
}
setParticles();
}
// 动画循环
function animate() {
requestAnimationFrame(animate);
updateParticles();
camera.position.lerp(cameraTarget, 0.2);
camera.lookAt(cameraLookAt);
render();
}
// 窗口大小变化时的响应函数
function resize() {
width = window.innerWidth;
height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
textCanvas.style.width = width + 'px';
textCanvas.style.height = 200 + 'px';
textCanvas.width = width;
textCanvas.height = 200;
updateText();
}
// 鼠标移动时的响应函数
function mousemove(e) {
var x = e.pageX - width / 2;
var y = e.pageY - height / 2;
cameraTarget.x = x * -1;
cameraTarget.y = y;
}
// 初始化舞台
initStage();
// 初始化场景
initScene();
// 初始化画布
initCanvas();
// 初始化摄像机
initCamera();
// 创建光源
createLights();
// 初始化输入框
initInput();
// 开始动画
animate();
// 稍微延迟更新文本内容,以确保初始状态正确显示
setTimeout(function() {
updateText();
}, 40);
👽 创建 goboy.css
body {
overflow: hidden;
background: #A1DBB2;
}
div, canvas {
position: absolute;
}
#text {
z-index: 200;
display: none;
}
input {
z-index: 400;
position: absolute;
text-transform: uppercase;
width: 90%;
bottom: 20px;
background: none;
outline: none;
border: none;
font-size: 30px;
color: #222;
font-weight: bold;
text-align: center;
border-bottom: 1px solid #333;
left: 5%;
}
👽 展示效果
Three.js相关资料官网
- Three.js官网:https://threejs.org/
- threejs.org 中文文档:https://threejs.org/docs/index.html#manual/zh/introduction/Creating-a-scene
- threejs.org 官方教程:https://threejs.org/manual/
- Three.js Github:https://github.com/mrdoob/three.js
- webgl3d.cn Three.js教程:http://www.webgl3d.cn/