发布于 2026-01-06 2 阅读
0

理解并运用 Three.js 和 Angular 创建 3D 动画

理解并运用 Three.js 和 Angular 创建 3D 动画

嘿,大家好吗?

今天我将讲解 Three.js 以及如何将其与 Angular 结合使用!之后,我们将使用 Three.js 创建一个简单的 3D 动画!

那么,让我们开始吧!首先,我们来看看 Three.js 是什么!

🎯 Three.js 简介:

Three.js 是一个非常棒的 JavaScript 库,它能让你的网站功能强大、美观,实现各种令人惊叹的效果!Three.js 支持处理 3D 几何体、物体、灯光、纹理以及其他一些很酷的功能!Three.js 包含三个重要组件:场景、摄像机和渲染器!

看看这些例子,让你的思绪自由驰骋,畅想你能创造出的无数可能性!

现在,让我们开始工作吧👩🏽‍🎨 🧑🏽‍🎨!


安装依赖项:

👇🏻 Install on the project
npm install three
Enter fullscreen mode Exit fullscreen mode
👇🏻 Install on the project
npm i @types/three
Enter fullscreen mode Exit fullscreen mode

生成并导入 Canvas Box 组件:

让我们创建 canvas 组件,所以Angular CLI我们将使用以下代码创建组件:

👇🏻 Create the canvas component
ng g c components/canvas-box
Enter fullscreen mode Exit fullscreen mode

并将其导入我们的app.module.ts

...
import { CanvasBoxComponent } from './components/canvas-box/canvas-box.component';

@NgModule({
  imports: [
    BrowserModule
  ],
  declarations: [
    AppComponent, 
    CanvasBoxComponent
  ]
})
...
Enter fullscreen mode Exit fullscreen mode

理解和运用画布盒结构:

首先,canvas-box.component.html我们需要创建 canvas 的 html 结构,并为 canvas 添加一个 id,结构如下所示:

<canvas id="canvas-box"></canvas>
Enter fullscreen mode Exit fullscreen mode

现在,让我们用 three.js 来创造奇迹,canvas-box.component.ts创建一个createThreeJsBox()方法,添加ngOnInit()生命周期钩子并导入 Three.js:

...
import * as THREE from 'three';

export class CanvasBoxComponent implements OnInit {
 ngOnInit(): void {
  this.createThreeJsBox();
 }

 createThreeJsBox(): void {
 }
}
...
Enter fullscreen mode Exit fullscreen mode

我们需要获取 canvas 元素的 html 代码,所以让我们创建一个常量并获取该元素:

...
export class CanvasBoxComponent implements OnInit {
 ...
 createThreeJsBox(): void {
    const canvas = document.getElementById('canvas-box');
 }
}
...
Enter fullscreen mode Exit fullscreen mode

⚠️ 重要提示

document.getElementById不建议在 Angular 中使用,因为我们有 SSR!我使用它只是因为在我看来它是最简单、最常用的方法!如果你一定要用,我建议你验证一下是否是 SSR 端,如果是,就退出函数!这里有一个可以安装的包,你可以用它来做这个验证:ngx-verify-is-server-side


接下来,我们将创建场景、材质以及两种类型的灯光,并将它们放置在场景中!首先,让我们创建一些常量,代码如下所示:

...
export class CanvasBoxComponent implements OnInit {
 ...
 createThreeJsBox(): void {
    const canvas = document.getElementById('canvas-box');

    const scene = new THREE.Scene();

    const material = new THREE.MeshToonMaterial();

    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    scene.add(ambientLight);

    const pointLight = new THREE.PointLight(0xffffff, 0.5);
    pointLight.position.x = 2;
    pointLight.position.y = 2;
    pointLight.position.z = 2;
    scene.add(pointLight);
 }
}
Enter fullscreen mode Exit fullscreen mode

👨🏽‍🏫👩🏽‍🏫 理解代码:

const scene = new THREE.Scene()
Enter fullscreen mode Exit fullscreen mode

在这里我们声明THREE.Scene(),场景对我们来说是必要且重要的,因为有了它,我们才能展示动画!场景就像我们的“动画场景”,我们创作的一切都需要添加到场景中!

const material = new THREE.MeshToonMaterial()
Enter fullscreen mode Exit fullscreen mode

我们声明了材质画布,它material就像我们 3D 元素的 CSS 一样!Three.js 包含几种类型的组件,请点击此处查看。

const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
Enter fullscreen mode Exit fullscreen mode

我们在场景中声明一个THREE.AmbientLight环境光,设置环境光的颜色和强度,并将环境光添加到场景中。

const pointLight = new THREE.PointLight(0xffffff, 0.5);
pointLight.position.x = 2;
pointLight.position.y = 2;
pointLight.position.z = 2;
scene.add(pointLight);
Enter fullscreen mode Exit fullscreen mode

我们创建一个新的THREE.PointLight,声明颜色和强度,改变位置pointLight并将其添加到我们的scene


现在让我们创建 3D 几何体并将其添加到场景中,我们创建一个立方体和一个圆环体,代码如下:

...
export class CanvasBoxComponent implements OnInit {
 ...
 createThreeJsBox(): void {

   /*The our code is here, I removed it because of the total lines*/
   ...

   const box = new THREE.Mesh(
      new THREE.BoxGeometry(1.5, 1.5, 1.5), 
      material
   );

   const torus = new THREE.Mesh(
      new THREE.TorusGeometry(5, 1.5, 16, 100),
      material
   );

   scene.add(torus, box);
 }
}
Enter fullscreen mode Exit fullscreen mode

👨🏽‍🏫👩🏽‍🏫 理解代码:

我们通过声明每个几何体的属性来创建两个 3D 几何体,为几何体添加材质(“css”),然后将几何体添加到场景中。


接下来,我们将声明屏幕尺寸,创建摄像机和渲染器!代码如下:

...
export class CanvasBoxComponent implements OnInit {
 ...
 createThreeJsBox(): void {

   /*The our code is here, I removed it because of the total lines*/
   ...

   const canvasSizes = {
    width: window.innerWidth,
    height: window.innerHeight,
   };

   const camera = new THREE.PerspectiveCamera(
    75,
    canvasSizes.width / canvasSizes.height,
    0.001,
    1000
   );
   camera.position.z = 30;
   scene.add(camera);

   if (!canvas) {
    return;
   }

   const renderer = new THREE.WebGLRenderer({
    canvas: canvas,
   });
   renderer.setClearColor(0xe232222, 1);
   renderer.setSize(canvasSizes.width, canvasSizes.height);
 }
}
Enter fullscreen mode Exit fullscreen mode

👨🏽‍🏫👩🏽‍🏫 理解代码:

const canvasSizes = {
  width: window.innerWidth,
  height: window.innerHeight,
};
Enter fullscreen mode Exit fullscreen mode

创建一个基于窗口width及其属性的对象。height

const camera = new THREE.PerspectiveCamera(
  75,
  canvasSizes.width / canvasSizes.height,
  0.001,
  1000
);
camera.position.z = 30;
scene.add(camera);
Enter fullscreen mode Exit fullscreen mode

我们创建相机,相机模拟人眼所见的景象。它是渲染 3D 场景最常用的投影模式,并声明了相关THREE.PerspectiveCamera属性,例如 de fov: 75aspect: canvasSizes.width / canvasSizes.heightnear: 0.001far: 1000之后,我们修改camera.position.z并将相机添加到场景中。


我们需要让场景具有响应性,因此我们需要canvasSizes在窗口大小调整事件中更新对象,让我们开始吧!

...
export class CanvasBoxComponent implements OnInit {
 ...
 createThreeJsBox(): void {

   /*The our code is here, I removed it because of the total lines*/
   ...

  window.addEventListener('resize', () => {
    canvasSizes.width = window.innerWidth;
    canvasSizes.height = window.innerHeight;

    camera.aspect = canvasSizes.width / canvasSizes.height;
    camera.updateProjectionMatrix();

    renderer.setSize(canvasSizes.width, canvasSizes.height);
    renderer.render(scene, camera);
  });
 }
}
Enter fullscreen mode Exit fullscreen mode

👨🏽‍🏫👩🏽‍🏫 理解代码:

我们添加了调整大小监听器,并更新了一些重要属性,canvasSizes包括属性camera.aspect、、camera.updateProjectionMatrix()renderer属性。之后,我们渲染了更新后的scenecamera


现在让我们为 3D 几何体添加动画,让场景更炫酷!我们将使用THREE.Clock()`, getElapsedTime()` 更新X, Y, Z几何体的 `de` 属性,更新 `de` renderer,并在下一帧再次调用动画requestAnimationFrame,代码如下:

...
export class CanvasBoxComponent implements OnInit {
 ...
 createThreeJsBox(): void {

   /*The our code is here, I removed it because of the total lines*/
   ...

  const clock = new THREE.Clock();

  const animateGeometry = () => {
    const elapsedTime = clock.getElapsedTime();

    // Update animation objects
    box.rotation.x = elapsedTime;
    box.rotation.y = elapsedTime;
    box.rotation.z = elapsedTime;

    torus.rotation.x = -elapsedTime;
    torus.rotation.y = -elapsedTime;
    torus.rotation.z = -elapsedTime;

    // Render
    renderer.render(scene, camera);

    // Call animateGeometry again on the next frame
    window.requestAnimationFrame(animateGeometry);
  };

  animateGeometry();
 }
}
Enter fullscreen mode Exit fullscreen mode

👨🏽‍🏫👩🏽‍🏫 理解代码:

const clock = new THREE.Clock();
Enter fullscreen mode Exit fullscreen mode

创建一个名为 `std::const` 的常量THREE.Clock(),用于跟踪时间。

const elapsedTime = clock.getElapsedTime();
Enter fullscreen mode Exit fullscreen mode

我们声明一个新的常量来获取自时钟开始以来经过的秒数,并设置动画的“速度”来控制动画效果。

box.rotation.x = elapsedTime;
box.rotation.y = elapsedTime;
box.rotation.z = elapsedTime;

torus.rotation.x = -elapsedTime;
torus.rotation.y = -elapsedTime;
torus.rotation.z = -elapsedTime;
Enter fullscreen mode Exit fullscreen mode

在这里,我们通过改变几何体的X, Y, Z位置来制作动画。

renderer.render(scene, camera);
Enter fullscreen mode Exit fullscreen mode

场景渲染完毕,摄像机已更新。

window.requestAnimationFrame(animateGeometry);
Enter fullscreen mode Exit fullscreen mode

我们宣布我们animateGeometryrequestAnimationFrame参与动画制作。

animateGeometry();
Enter fullscreen mode Exit fullscreen mode

只是调用一下我们的函数而已 :D


太棒了!我们有了更酷炫的 Three.js 实现,之后我们就能创造出超棒的几何组合了!😁😁🚀🚀💥 🔥

现在我们对 Three.js 及其结构有了基本的了解!

Three.js 非常棒,我们可以用它做无数的事情,让我们的网站变得强大。

这里我们可以看到我们的案例研究的实际示例🤘🏻:

就这些啦,希望你们喜欢!如果有任何问题、建议或其他话题,请留言!

回头见✌🏼

文章来源:https://dev.to/renancferro/understanding-and-implementing-thirdjs-with-angular-and-creating-a-3d-animation-3eea