读过本文章后,你将了解如何在DOM中创建一个可交互式的3D空间。
注:Three.js需要一定的逻辑和数学知识。
1.创建渲染器
首先获取DOM元素,定义一个容器变量。
- const container = document.getElementById(‘container’);
然后,将使用Web GL渲染器显示场景。
- const renderer = new THREE.WebGLRenderer({
- antialias: true
- });
设置渲染器并指定参数 antialias (抗锯齿),默认渲染器不会开启抗锯齿。
接下来设置renderer的大小,renderer.setSize需要2个参数,宽度和高度。
- renderer.setSize(window.innerWidth, window.innerHeight);
现在,我们将渲染器附加到容器变量中的dom元素
- container.appendChild(renderer.domElement);
最后,更改光标的样式为指针
- renderer.domElement.style.cursor = ‘pointer’;
2.创建场景
定义一个场景
- const scene = new THREE.Scene();
设置场景的背景颜色
- scene.background = new THREE.Color(‘#000000’);
为场景定义一个雾类,根据对象的距离使对象看起来更密集。相关雾类的说明请参阅文档 。
- scene.fog = new THREE.Fog(scene.background, 10, 20);
3.创建摄像机
Three.js有不同的相机选项,本文使用的为PerspectiveCamera,因为它的目的是模仿人眼。
- const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, .1, 10000);
PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )
- fov — 摄像机视锥体垂直视野角度
- aspect — 摄像机视锥体长宽比
- near — 摄像机视锥体近端面
- far — 摄像机视锥体远端面
对于摄像机,必须设置其位置。 如果忘记设置相机的位置,相机将看不到任何东西。
- camera.position.set(0, -5, 5);
4.为相机设置场景旋转
需引入OrbitControl.js,OrbitControls允许摄像机绕目标旋转,即控制鼠标旋转场景。
- const controls = new THREE.OrbitControls(camera, renderer.domElement);
- renderer.render(scene, camera);
它需要两个参数:要控制的相机和要运行的dom元素
5.创建一个空间粒子
在此将创建一个函数 Particles,该函数负责将粒子添加到three.js组对象中。
粒子具有6个属性:
- 颜色 Color
- 尺寸 Size
- 数量 pointCount
- 范围水平 rangeV
- 范围垂直 rangeH
- 速度 speed
- const color = this.color = options.color || ‘#000000’;
- const size = this.size = options.size || 0.4;
- const pointCount = this.pointCount = options.pointCount || 40;
- const rangeV = this.rangeV = options.rangeV || 2;
- const rangeH = this.rangeH = options.rangeH || 1;
- const speed = this.speed = this.speedTarget = options.speed || 0.0005;
6.将粒子添加到threejs的组
- THREE.Group.call(this);
使用画布为粒子创建纹理
首先,创建一个画布元素,该元素将保存粒子。
- const canvas = document.createElement(‘canvas’);
然后设置 width 和 height = 128,因为这是three.js图像的标准
- canvas.width = canvas.height = 128;
创建一个ctx变量,该变量等于在canvas变量上返回getContext方法。
在画布上创建原形图案。
- const ctx = canvas.getContext(‘2d’);
- const centerX = canvas.width / 2;
- const centerY = canvas.height / 2;
- const radius = canvas.width / 3;
- ctx.beginPath();
- ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
- ctx.fillStyle = ‘#fff’;
- ctx.fill();
7.转换画布纹理到threejs
THREE.Texture 一个应用在表面或反射或折射的图
- const texture = new THREE.Texture(canvas);
- texture.premultiplyAlpha = true;
- texture.needsUpdate = true;
创建几何体并使用以上纹理
THREE.Geometry
- const pointsGeo = new THREE.Geometry();
创建点材质
- const pointsMat = new THREE.PointsMaterial({
- color,
- size,
- map: texture,
- transparent: true,
- depthWrite: false
- });
创建点的三维向量坐标并将点添加到组
- for (var p = 0; p < pointCount; p++) {
- var point = new THREE.Vector3(
- THREE.Math.randFloatSpread(rangeH),
- THREE.Math.randFloatSpread(rangeV),
- THREE.Math.randFloatSpread(rangeH)
- );
- pointsGeo.vertices.push(point);
- }
- var points = this.points = new THREE.Points(pointsGeo, pointsMat);
- this.add(points);
更多API可查阅文档
8.为粒子函数增加属性
- const container = document.getElementById(‘container’);
更新位置函数
- Particles.prototype.updateConstant = function () {
- let pCount = this.pointCount;
- while (pCount–) {
- const point = this.points.geometry.vertices[pCount];
- if (point.y < –this.rangeV / 2) {
- point.y = this.rangeV / 2;
- }
- point.y -= this.speed;
- }
- this.points.geometry.verticesNeedUpdate = true;
- }
9.使用函数创建粒子云
- const stars = new Particles({
- color: ‘#ffffff’,
- size: 1,
- rangeH: 10,
- rangeV: 10,
- pointCount: 100,
- size: .1,
- speed: .1
- });
- scene.add(stars);
10.为场景增加鼠标监听
为了能够在场景中移动,我们需要控制摄像机的位置。
- const cameraTarget = new THREE.Vector3();
- cameraTarget.copy(camera.position);
创建一个鼠标变量,该变量是一个THREE.vector 2对象,它是一个二维向量。
- const mouse = new THREE.Vector2();
- function mousemove({
- clientX,
- clientY
- }) {
- mouse.x = (clientX / window.innerWidth) * 5 – 1;
- mouse.y = (clientY / window.innerHeight) * 5 – 1;
- cameraTarget.x = -mouse.x * 1;
- cameraTarget.z = 5 + mouse.y * 1;
- }
点击鼠标按键将改变粒子的速度。
- function mousedown(e) {
- stars.speedTarget = 0.5;
- renderer.domElement.style.cursor = ‘none’;
- }
- function mouseup(e) {
- stars.speedTarget = 0.1;
- renderer.domElement.style.cursor = ‘pointer’;
- }
最后将渲染器变量eventListeners中增加回调,以便每次移动鼠标时都会触发该函数。
- renderer.domElement.addEventListener(‘mousemove’, mousemove, false);
- renderer.domElement.addEventListener(‘mousedown’, mousedown, false);
- renderer.domElement.addEventListener(‘mouseup’, mouseup, false);
11.循环绘制动画
requestAnimationFrame函数会告诉浏览器,你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
- function loop() {
- requestAnimationFrame(loop);
- controls.update();
- stars.updateConstant();
- lerp(camera.position, ‘x’, cameraTarget.x);
- lerp(camera.position, ‘z’, cameraTarget.z);
- lerp(stars, ‘speed’, stars.speedTarget);
- renderer.render(scene, camera);
- }
- function lerp(object, prop, destination) {
- if (object && object[prop] !== destination) {
- object[prop] += (destination – object[prop]) * 0.1;
- if (Math.abs(destination – object[prop]) < 0.01) {
- object[prop] = destination;
- }
- }
- }
12.完整示例
本文链接地址: Threejs 创建3D交互空间