Three.js 快速入门教程【五】动画渲染循环

请添加图片描述

系列文章目录

Three.js 快速入门教程【一】开启你的 3D Web 开发之旅
Three.js 快速入门教程【二】透视投影相机
Three.js 快速入门教程【三】渲染器
Three.js 快速入门教程【四】三维坐标系
Three.js 快速入门教程【五】动画渲染循环
Three.js 快速入门教程【六】相机控件 OrbitControls
Three.js 快速入门教程【七】常见几何体类型
Three.js 快速入门教程【八】常见材质类型
Three.js 快速入门教程【九】光源类型



一、前言

      在使用 Three.js 进行 3D 场景开发时,实现流畅的动画效果是至关重要的。而动画渲染循环则是实现动画的核心机制之一,其中 requestAnimationFrame 函数扮演着关键角色。如果你有看过该系列教程之前的文章对动画渲染循环一定不会陌生,经常出现在示例代码里面。本文将详细介绍 Three.js 中的动画渲染循环,并深入讲解 requestAnimationFrame 的工作原理和使用方法。


二、动画渲染循环的概念

动画渲染循环是指在每一帧中更新场景中的对象状态,并将更新后的场景渲染到屏幕上的过程。在 Three.js 中,我们通常使用一个循环来不断地调用渲染函数,以实现动画效果。然而,使用传统的 setInterval 或 setTimeout 来实现动画循环可能会导致性能问题和不流畅的动画效果,因为它们的执行时间间隔可能与屏幕的刷新率不一致。


三、requestAnimationFrame 详解

requestAnimationFrame 是浏览器提供的一个用于优化动画性能的 API。它的主要作用是告诉浏览器在下次重绘之前执行指定的函数,以更新动画。requestAnimationFrame 的优势在于:

1、与屏幕刷新率同步:requestAnimationFrame 的执行频率与屏幕的刷新率保持一致,这样可以确保动画的流畅性。常见的显示器刷新频率有60Hz、75Hz、120Hz、144Hz等

2、节能:当页面处于非活动状态时(例如切换到后台),requestAnimationFrame 会自动暂停,从而节省系统资源。

requestAnimationFrame 的使用方法如下:

function animate() {
    // 更新场景中的对象状态
    mesh.rotation.x += 0.01;
    mesh.rotation.y += 0.01;
    // 渲染场景
    renderer.render(scene, camera);
    // 递归调用 animate 函数,实现动画循环
    requestAnimationFrame(animate);
}

// 启动动画循环
animate();

在上述代码中,我们定义了一个 animate 函数,该函数在每一帧中更新物体的旋转角度,并调用 renderer.render 方法来渲染场景。然后,我们使用 requestAnimationFrame 递归调用 animate 函数,从而实现了一个连续的动画循环。


四、动画渲染循环在开发中应用

1、物体自转

绕Y轴方向自转

function animate() {
    // 更新场景中的对象状态
    mesh.rotation.y += 0.01;
    // 渲染场景
    renderer.render(scene, camera);
    // 递归调用 animate 函数,实现动画循环
    requestAnimationFrame(animate);
}

// 启动动画循环
animate();

请添加图片描述

2、物体绕坐标轴做圆周运动

通过修改物体rotation属性值只能让物体基于自身几何中心点自转,如果想实现物体围绕某个坐标轴旋转效果,就要控制物体位置使其在圆形轨道上做圆周运动。

以绕Y轴做圆周运动为例:

核心代码:

       // 定义圆周运动的参数
      const radius = 20; // 圆周的半径
      let angle = 0; // 初始角度
      const speed = 0.01; // 运动速度

        // 渲染循环
        function animate() {
            requestAnimationFrame(animate);
            // 计算物体在圆周上的位置
            const x = radius * Math.cos(angle);
            const z = radius * Math.sin(angle);
            // 更新物体的位置
            mesh.position.set(x, mesh.position.y, z);
            // 增加角度,让物体继续运动
            angle += speed;
            renderer.render(scene, camera);
        }
        animate();

在 animate 函数中,使用 Math.cos 和 Math.sin 函数根据当前角度计算物体在 XZ 平面上的位置。
通过 mesh.position.set(x, mesh.position.y, z) 更新物体的位置。
每次循环增加 angle 的值,让物体继续沿着圆周运动。

完整代码:

import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

//创建场景
const scene = new THREE.Scene();
scene.background='#000000'
// 创建坐标轴辅助器
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
//创建一个球体
const geometry = new THREE.SphereGeometry(3);
//创建一个基础材质
const material = new THREE.MeshBasicMaterial({ color: "#409EFF" });
//创建一个网格对象
const mesh = new THREE.Mesh(geometry, material);
//设置网格对象位置
mesh.position.set(0, 5, 20);
//添加到场景中
scene.add(mesh);

//创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
//设置相机位置
camera.position.set(0, 20, 50);
//相机默认看向网格对象
camera.lookAt(mesh.position);

//创建渲染器
const renderer = new THREE.WebGLRenderer();
//设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 设置渲染器的像素比为设备的像素比
renderer.setPixelRatio(window.devicePixelRatio);

//将渲染器的 DOM 元素添加body
document.body.appendChild(renderer.domElement);

// 新建一个相机控件
const controls = new OrbitControls(camera, renderer.domElement);
// 启用阻尼(惯性效果)
controls.enableDamping = true;
controls.dampingFactor = 0.05;

// 定义圆周运动的参数
const radius = 20; // 圆周的半径
let angle = 0; // 初始角度
const speed = 0.01; // 运动速度

// 动画循环
function animate() {
  // 计算物体在圆周上的位置
  const x = radius * Math.cos(angle);
  const z = radius * Math.sin(angle);
  // 更新物体的位置
  mesh.position.set(x, mesh.position.y, z);
  // 增加角度,让物体继续运动
  angle += speed;
  // 定时刷新
  requestAnimationFrame(animate);
  // 更新控制器,必须调用以应用阻尼效果
  controls.update();
  //重新渲染
  renderer.render(scene, camera);
}
// 执行动画
animate();

请添加图片描述

3、物体平移

/ 动画循环
function animate() {
//沿x轴正方向移动
  mesh.position.x+=0.1
  // 定时刷新
  requestAnimationFrame(animate);
  //重新渲染
  renderer.render(scene, camera);
}
// 执行动画
animate();

请添加图片描述

4、物体缩放

//缩放比例
let scale = 1;
// 动画循环
function animate() {
  scale = Math.max(0, scale - 0.002);
  //缩放物体
  mesh.scale.set(scale, scale, scale);
  // 定时刷新
  requestAnimationFrame(animate);
  // 更新控制器,必须调用以应用阻尼效果
  controls.update();
  //重新渲染
  renderer.render(scene, camera);
}
// 执行动画
animate();

请添加图片描述


五、总结

       通过本文的介绍,我们了解了 Three.js 中动画渲染循环的基本概念,并深入学习了 requestAnimationFrame 的工作原理和使用方法。使用 requestAnimationFrame 可以帮助我们实现更加流畅和高效的动画效果,是 Three.js 开发中不可或缺的一部分

更多three.js入门知识点请关注该系列教程后续的更新。

对整threeJS体系进行全面剖析。整理出全面的教学大纲,涵盖内容面非常广。此教学版本为threeJS107版本。关于版本不建议大家使用低于90的版本学习。以下是课程目录1-ThreeJS概览(基本图形简介,什么是点线面如何绘制点线面,什么是材质,什么是几何体,什么是相机,什么是渲染器,什么是场景)2-相机和渲染器(详解相机类型,渲染器如何使用,针对不同场景怎么用,怎么调效果,怎么渲染,怎么输出画布,如何解决透明问题等等)3-创建平面几何(常见的几何体如何使用,如何使用简单的几何体绘制出自定义自己想要的几何体,关于几何体的性能剖析,如何解决性能,几何体的渲染原理)4-高级图形算法常见库(求直线的斜率  计算线段与圆的交点 计算线段的长度 判断折线是否在多边形内 等等)5-sprite精灵(怎么让一个图标永远朝向屏幕,精灵的属性,精灵材质原理等,广告提示框必用)6-骨骼游戏动画(什么是模型动画,常见游戏案例,如何让人头进行各种攻击动作)7-3d模型加载(常见模型格式,如何渲染不同格式,不同格式的特点,什么格式性能优越,模型渲染异常,贴图不显示等问题详解)8-高阶动态纹理(你所不知道的纹理用法,我说你不知道,你肯定不知道)9-漫游轨迹以及其动画路径(怎么绘制贝塞尔曲线,如何使用曲线上的路径,跟随路径移动的原理,相机如何运动,物体如何运动)10-着色器(什么是着色器。初识着色器基础,着色器材质怎么用,怎么使用着色器库)11-常见渲染以及透明度问题12-对象拾取以及拖拽(3d世界里面如何拖拽物体,拖拽的原理,mousemove mouseon等的事件效果)13-世界坐标以及组的问题(什么是相对坐标,什么是世界坐标,什么是当前坐标,怎么转化父子坐标系,组的优化,为什么用组,组的优势)14-指定对象旋转中心(什么是物体的几何体中心,如何改变中心,如何绕轴转动)15-层级对象渲染(多个场景一键切换,切换的优势,针对大项目的用法)16-拓展了解系列(不定期不断更新案例,各种酷炫效果bloom,halo等,以及各种3d图表,粒子案例等,不断构建你的3d实践能力)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pixle0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值