上文中已经介绍了Three.js相关的信息和项目的初始化配置,接下来将讲述关于Three.js的一些基础项的配置及实现。
目录
1.轨道控制查看器(OrbitControls)
2.设置物体移动
3.设置物体缩放与旋转
3.1 物体缩放
3.2 物体旋转
4.物体运动动画处理
4.1 应用requestAnimationFrame正确处理动画运动
4.2 通过Clock跟踪时间处理动画
4.3 Gsap动画库实现动画控制
5.根据尺寸实现自适应画面
6.使用js接口实现画布全屏和退出全屏
7.使用dat.gui实现用户界面控制
Orbit controls(轨道控制器)可以使得相机围绕目标进行轨道运动。
创建场景及物体初始化配置:
// 1、创建场景
const scene = new THREE.Scene();
// 2、创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
// 设置相机位置
camera.position.set(0, 0, 10);
scene.add(camera);
// 添加物体
// 创建几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
// 根据几何体和材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
// 将几何体添加到场景中
scene.add(cube);
// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// console.log(renderer);
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement);
在js文件中导入OrbitControls
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
创建轨道控制器
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
添加坐标轴辅助器
// 添加坐标轴辅助器(红:x;绿:y;蓝:z)
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
渲染函数:
//渲染函数
function render() {
renderer.render(scene, camera);
// //请求动画帧, 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render);
}
render();
实现效果:
实现原理:通过设置物体cube的位置x/y/z的值的变换,请求帧动画,在渲染下一帧的时候设置新的x,y,z坐标值实现物体的移动。
实现如下,设置每渲染一帧对cube的x坐标值进行递增,从而实现物体的移动。
function render() {
cube.position.x += 0.01;//每画一帧加0.01
if (cube.position.x > 5) {
cube.position.x = 0;
}
renderer.render(scene, camera);
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render);
}
render();
Three中,对于物体的缩放,可通过.scale : Vector3实现物体的局部缩放。默认值是Vector3( 1, 1, 1 )。例如:cube.scale.set(x, y, z)或cube.scale.x;cube.scale.y;cube.scale.z;进行设置。
cube.scale.set(3, 2, 1);
物体旋转实现通过.rotation : Euler 实现
物体的局部旋转,以弧度来表示。(请参阅Euler angles-欧拉角)
欧拉角描述一个旋转变换,通过指定轴顺序和其各个轴向上的指定旋转角度来旋转一个物体。
对 Euler 实例进行遍历将按相应的顺序生成它的分量 (x, y, z, order)。
Euler( x : Float, y : Float, z : Float, order : String )
x - (optional) 用弧度表示x轴旋转量。 默认值是 0。
y - (optional) 用弧度表示y轴旋转量。 默认值是 0。
z - (optional) 用弧度表示z轴旋转量。 默认值是 0。
order - (optional) 表示旋转顺序的字符串,默认为'XYZ'(必须是大写)。
order值应用于旋转顺序。默认值为 'XYZ',这意味着对象将首先是 绕X轴旋转,然后是Y轴,最后是Z轴。其他可能性包括: 'YZX', 'ZXY', 'XZY', 'YXZ'和'ZYX'。这些必须是大写字母。
Three.js 使用intrinsic Tait-Bryan angles(Yaw、Pitch、Roll)。 这意味着旋转是在本地坐标系下进行的。也就是说,对于“XYZ”顺序,首先是围绕local-X轴旋转(与world- x轴相同), 然后是local-Y(现在可能与world y轴不同),然后是local-Z(可能与world z轴不同)。
示例代码:
cube.rotation.set(Math.PI / 4, 0, 0, "XZY");
实现效果:
在实现物体的动态移动时,由于计算机的内存或资源等占用,会导致帧动画渲染的时间会出现波动,为了提供更好的视觉感受和交互体验,下面介绍三种对于运动动画处理的方式。
该方式通过速度、时间与路程之间的关系,对动画帧进行处理,从而实现平滑的运动效果。
function render(time) {
// console.log(time);
let t = (time / 1000) % 5;//(time/1000ms)求得当前时间,%5设置求余实现反复
cube.position.x = t * 1;//s=t*v
renderer.render(scene, camera);
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render);
}
render();
Clock
该对象用于跟踪时间。如果performance.now可用,则 Clock 对象通过该方法实现,否则回落到使用略欠精准的Date.now来实现。
通过Three提供的Clock接口,获取自时钟启动后的秒数,并利用s=v*t实现对物体运动距离的设置,从而实现物体移动的平滑动画。
// 设置时钟
const clock = new THREE.Clock();
function render() {
// 获取时钟运行的总时长
let time = clock.getElapsedTime();
console.log("时钟运行总时长:", time);
// let deltaTime = clock.getDelta();
// console.log("两次获取时间的间隔时间:", deltaTime);
let t = time % 5;
cube.position.x = t * 1;
renderer.render(scene, camera);
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render);
}
render();
GSAP 是一个强大的 JavaScript 工具集,可将开发人员变成动画超级英雄。构建适用于所有主流浏览器的高性能动画。动画 CSS、SVG、画布、React、Vue、WebGL、颜色、字符串、运动路径、通用对象...... JavaScript 可以触摸的任何东西!GSAP 的ScrollTrigger插件让您可以用最少的代码创建令人瞠目结舌的滚动动画。在解决超过 1100 万个站点的实际问题时,没有其他文库能够提供如此先进的测序、可靠性和严格控制。GSAP 可以解决无数的浏览器不一致问题;你的动画只是工作。GSAP 的核心是一个高速属性操纵器,随着时间的推移以极高的准确性更新值。GitHub - greensock/GSAP: GreenSock's GSAP JavaScript animation library (including Draggable).GreenSock's GSAP JavaScript animation library (including Draggable). - GitHub - greensock/GSAP: GreenSock's GSAP JavaScript animation library (including Draggable).https://github.com/greensock/GSAP1.安装gsap库
npm install gsap
2. 导入动画库
// 导入动画库
import gsap from "gsap";
3. 设置动画
要创建动画,gsap.to()需要两件事:
".myClass"
.opacity:0.5
、rotation:45
等)以及其他可选的特殊属性,如duration
和onComplete
。例如,要在 1 秒内 将 id 为“logo”的元素移动到x
100 的位置(与 相同):transform: translateX(100px)
gsap.to("#logo", {duration: 1, x: 100});
注意:请记住,GSAP 不仅适用于 DOM 元素,因此您甚至可以为原始对象的自定义属性设置动画,如下所示:
var obj = {prop: 10};
gsap.to(obj, {
duration: 1,
prop: 200,
//onUpdate fires each time the tween updates; we'll explain callbacks later.
onUpdate: function() {
console.log(obj.prop); //logs the value on each update.
}
});
因此,在Three中,对于物体移动动画也可以使用gsap库进行实现,例如实现双击屏幕开始或暂停动画事件:
// 设置动画
// 物体移动
var animate1 = gsap.to(cube.position, {
x: 5,
duration: 5,
ease: "power1.inOut",
// 设置重复的次数,无限次循环-1
repeat: -1,
// 往返运动
yoyo: true,
// delay,延迟2秒运动
delay: 2,
onComplete: () => {
console.log("动画完成");
},
onStart: () => {
console.log("动画开始");
},
});
// 物体旋转动画
gsap.to(cube.rotation, { x: 2 * Math.PI, duration: 5, ease: "power1.inOut" });
window.addEventListener("dblclick", () => {
// console.log(animate1);
if (animate1.isActive()) {
// 暂停
animate1.pause();
} else {
// 恢复
animate1.resume();
}
});
实现效果:
通过监听画面尺寸的变化,改变相机和渲染器的尺寸,实现自适应画面:
// 监听画面变化,更新渲染画面
window.addEventListener("resize", () => {
// console.log("画面变化了");
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix();
// 更新渲染器
renderer.setSize(window.innerWidth, window.innerHeight);
// 设置渲染器的像素比
renderer.setPixelRatio(window.devicePixelRatio);
});
function render() {
controls.update();
renderer.render(scene, camera);
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render);
}
render();
通过监听屏幕双击事件,对渲染器进行全屏展示和退出全屏:
//设置双击进入/退出全屏
window.addEventListener("dblclick", () => {
const fullScreenElement = document.fullscreenElement;
if (!fullScreenElement) {
// 双击控制屏幕进入全屏,退出全屏
// 让画布对象全屏
renderer.domElement.requestFullscreen();
} else {
// 退出全屏,使用document对象
document.exitFullscreen();
}
});
在Three项目开发时,由于许多参数和功能需要可视化的进行调节或使用,因此可以使用图形界面控制其内容。dat.gui是一个轻量型的JavaScript库,他能提供便捷的方式,让你去修改或者操作js中的变量和函数。
1.安装
yarn add dat.gui
or
npm install dat.gui
2.导入
import * as dat from 'dat.gui';
3.使用
const gui = new dat.GUI({}) //创建GUI实例
// 创建实例的时候 new dat.GUI(params)
Param | Type | Default | Description |
---|---|---|---|
[params] | Object |
||
[params.name] | String |
此 GUI 的名称。 | |
[params.load] | Object |
表示此 GUI 的已保存状态的 JSON 对象。 | |
[params.parent] | dat.gui.GUI |
我嵌套的 GUI。 | |
[params.autoPlace] | Boolean |
true |
|
[params.hideable] | Boolean |
true |
如果为 true,则通过h按键显示/隐藏 GUI。 |
[params.closed] | Boolean |
false |
如果为真,则开始关闭 |
[params.closeOnTop] | Boolean |
false |
如果为真,关闭/打开按钮显示在 GUI 顶部 |
4.案例:
设置交互控件,实现对物体的材质颜色、移动距离、是否显示、线框样式及动画开关的控制。
//设置dat.gui
const gui = new dat.GUI();
gui
.add(cube.position, "x")
.min(0)
.max(5)
.step(0.01)
.name("移动x轴")
.onChange((value) => {
console.log("值被修改:", value);
})
.onFinishChange((value) => {
console.log("完全停下来:", value);
});
// 修改物体的颜色
const params = {
color: "#ffff00",
fn: () => {
// 让立方体运动起来
gsap.to(cube.position, { x: 5, duration: 2, yoyo: true, repeat: -1 });
},
};
gui.addColor(params, "color").onChange((value) => {
console.log("值被修改:", value);
cube.material.color.set(value);
});
// 设置选项框
gui.add(cube, "visible").name("是否显示");
var folder = gui.addFolder("设置立方体");
folder.add(cube.material, "wireframe");
// 设置按钮点击触发某个事件
folder.add(params, "fn").name("立方体运动");
实现效果: