Threejs 创建3D交互空间

读过本文章后,你将了解如何在DOM中创建一个可交互式的3D空间。

注:Three.js需要一定的逻辑和数学知识。

 1.创建渲染器

首先获取DOM元素,定义一个容器变量。

  1. const container = document.getElementById(‘container’);

然后,将使用Web GL渲染器显示场景。

  1. const renderer = new THREE.WebGLRenderer({
  2.   antialias: true
  3. });

设置渲染器并指定参数 antialias (抗锯齿),默认渲染器不会开启抗锯齿。
接下来设置renderer的大小,renderer.setSize需要2个参数,宽度和高度。

  1. renderer.setSize(window.innerWidth, window.innerHeight);

现在,我们将渲染器附加到容器变量中的dom元素

  1. container.appendChild(renderer.domElement);

最后,更改光标的样式为指针

  1. renderer.domElement.style.cursor = ‘pointer’;

2.创建场景

定义一个场景

  1. const scene = new THREE.Scene();

设置场景的背景颜色

  1. scene.background = new THREE.Color(‘#000000’);

为场景定义一个雾类,根据对象的距离使对象看起来更密集。相关雾类的说明请参阅文档

  1. scene.fog = new THREE.Fog(scene.background, 10, 20);

3.创建摄像机

Three.js有不同的相机选项,本文使用的为PerspectiveCamera,因为它的目的是模仿人眼。

  1. const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, .1, 10000);

PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )

  1. fov — 摄像机视锥体垂直视野角度
  2. aspect — 摄像机视锥体长宽比
  3. near — 摄像机视锥体近端面
  4. far — 摄像机视锥体远端面

 

对于摄像机,必须设置其位置。 如果忘记设置相机的位置,相机将看不到任何东西。

  1. camera.position.set(0, -5, 5);

4.为相机设置场景旋转

需引入OrbitControl.js,OrbitControls允许摄像机绕目标旋转,即控制鼠标旋转场景。

  1. const controls = new THREE.OrbitControls(camera, renderer.domElement);
  2. renderer.render(scene, camera);

它需要两个参数:要控制的相机和要运行的dom元素

5.创建一个空间粒子

在此将创建一个函数 Particles,该函数负责将粒子添加到three.js组对象中。
粒子具有6个属性:

  1. 颜色 Color
  2. 尺寸 Size
  3. 数量 pointCount
  4. 范围水平 rangeV
  5. 范围垂直 rangeH
  6. 速度 speed
  1. const color = this.color = options.color || ‘#000000’;
  2. const size = this.size = options.size || 0.4;
  3. const pointCount = this.pointCount = options.pointCount || 40;
  4. const rangeV = this.rangeV = options.rangeV || 2;
  5. const rangeH = this.rangeH = options.rangeH || 1;
  6. const speed = this.speed = this.speedTarget = options.speed || 0.0005;

6.将粒子添加到threejs的组

  1. THREE.Group.call(this);

使用画布为粒子创建纹理
首先,创建一个画布元素,该元素将保存粒子。

  1. const canvas = document.createElement(‘canvas’);

然后设置 width 和 height = 128,因为这是three.js图像的标准

  1. canvas.width = canvas.height = 128;

创建一个ctx变量,该变量等于在canvas变量上返回getContext方法。
在画布上创建原形图案。

  1. const ctx = canvas.getContext(‘2d’);
  2. const centerX = canvas.width / 2;
  3. const centerY = canvas.height / 2;
  4. const radius = canvas.width / 3;
  5. ctx.beginPath();
  6. ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  7. ctx.fillStyle = ‘#fff’;
  8. ctx.fill();

7.转换画布纹理到threejs

THREE.Texture 一个应用在表面或反射或折射的图

  1. const texture = new THREE.Texture(canvas);
  2. texture.premultiplyAlpha = true;
  3. texture.needsUpdate = true;

创建几何体并使用以上纹理
THREE.Geometry

  1. const pointsGeo = new THREE.Geometry();

创建点材质

  1. const pointsMat = new THREE.PointsMaterial({
  2.   color,
  3.   size,
  4.   map: texture,
  5.   transparent: true,
  6.   depthWrite: false
  7. });

创建点的三维向量坐标并将点添加到组

  1. for (var p = 0; p < pointCount; p++) {
  2.   var point = new THREE.Vector3(
  3.     THREE.Math.randFloatSpread(rangeH),
  4.     THREE.Math.randFloatSpread(rangeV),
  5.     THREE.Math.randFloatSpread(rangeH)
  6.   );
  7.   pointsGeo.vertices.push(point);
  8. }
  9. var points = this.points = new THREE.Points(pointsGeo, pointsMat);
  10. this.add(points);

更多API可查阅文档

8.为粒子函数增加属性

  1. const container = document.getElementById(‘container’);

更新位置函数

  1. Particles.prototype.updateConstant = function () {
  2.   let pCount = this.pointCount;
  3.   while (pCount–) {
  4.     const point = this.points.geometry.vertices[pCount];
  5.     if (point.y < –this.rangeV / 2) {
  6.       point.y = this.rangeV / 2;
  7.     }
  8.     point.y -= this.speed;
  9.   }
  10.   this.points.geometry.verticesNeedUpdate = true;
  11. }

9.使用函数创建粒子云

  1. const stars = new Particles({
  2.   color: ‘#ffffff’,
  3.   size: 1,
  4.   rangeH: 10,
  5.   rangeV: 10,
  6.   pointCount: 100,
  7.   size: .1,
  8.   speed: .1
  9. });
  10. scene.add(stars);

10.为场景增加鼠标监听

为了能够在场景中移动,我们需要控制摄像机的位置。

  1. const cameraTarget = new THREE.Vector3();
  2. cameraTarget.copy(camera.position);

创建一个鼠标变量,该变量是一个THREE.vector 2对象,它是一个二维向量。

  1. const mouse = new THREE.Vector2();
  2. function mousemove({
  3.   clientX,
  4.   clientY
  5. }) {
  6.   mouse.x = (clientX / window.innerWidth) * 5 – 1;
  7.   mouse.y = (clientY / window.innerHeight) * 5 – 1;
  8.   cameraTarget.x = -mouse.x * 1;
  9.   cameraTarget.z = 5 + mouse.y * 1;
  10. }

点击鼠标按键将改变粒子的速度。

  1. function mousedown(e) {
  2.   stars.speedTarget = 0.5;
  3.   renderer.domElement.style.cursor = ‘none’;
  4. }
  5. function mouseup(e) {
  6.   stars.speedTarget = 0.1;
  7.   renderer.domElement.style.cursor = ‘pointer’;
  8. }

最后将渲染器变量eventListeners中增加回调,以便每次移动鼠标时都会触发该函数。

  1. renderer.domElement.addEventListener(‘mousemove’, mousemove, false);
  2. renderer.domElement.addEventListener(‘mousedown’, mousedown, false);
  3. renderer.domElement.addEventListener(‘mouseup’, mouseup, false);

 11.循环绘制动画

requestAnimationFrame函数会告诉浏览器,你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

  1. function loop() {
  2.   requestAnimationFrame(loop);
  3.   controls.update();
  4.   stars.updateConstant();
  5.   lerp(camera.position, ‘x’, cameraTarget.x);
  6.   lerp(camera.position, ‘z’, cameraTarget.z);
  7.   lerp(stars, ‘speed’, stars.speedTarget);
  8.   renderer.render(scene, camera);
  9. }
  10. function lerp(object, prop, destination) {
  11.   if (object && object[prop] !== destination) {
  12.     object[prop] += (destination – object[prop]) * 0.1;
  13.     if (Math.abs(destination – object[prop]) < 0.01) {
  14.       object[prop] = destination;
  15.     }
  16.   }
  17. }

 12.完整示例

示例下载

本文链接地址: Threejs 创建3D交互空间

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注