在 WebGL 中使用 Three.js 探索模型和动画

浏览器中的 3D 图形自推出以来一直是一个热门话题。但如果您要使用普通的旧式 WebGL 创建应用程序,则需要很长时间。这就是为什么出现了一些真正有用的库。 Three.js 是其中最受欢迎的之一,在本系列中,我将向您展示如何充分利用它为您的用户创建令人惊叹的 3D 体验。

我希望您在开始阅读本教程之前对 3D 空间有基本的了解,因为我不会解释坐标和向量等主题。


准备工作

像往常一样,我们将从您之前创建的代码开始。下载并解压我提供的资源,您就可以开始了。


第 1 步:关于在 Blender 中导出模型的说明

在我们开始编程部分之前,我将解释一些很多人都遇到问题的问题。当您在 Blender 中创建模型并希望将其导出为 Three.js 格式时,您应该记住以下几点:

  • 首先,删除父子关系。如果您离开,Three.js 导出器将不会导出任何动画(这也适用于骨架修改器)
  • 第二,对顶点进行分组。如果您希望骨骼移动任何顶点,则必须对它们进行分组,并用骨骼的名称来命名该组。
  • 第三,您只能有一个动画。 这听起来可能是一个大问题,但我稍后会解释解决方法。

此外,导出时您必须确保在导出器中选择了这些选项:SkinningBonesSkeletal Animation


第 2 步:导入模型

与 Three.js 中的几乎所有内容一样,导入模型非常简单。有一个特殊的类 THREE.JSONLoader 将为我们做所有事情。当然,它只加载 JSON 模型,但建议使用它们,所以我只会介绍这个加载器(其他加载器的工作方式几乎相同)。我们先初始化它:

var loader = new THREE.JSONLoader;
var animation;

无需参数。我们还需要定义一个动画变量,以便稍后访问它。现在我们可以加载模型了:

loader.load('./model.js', function (geometry, materials) {
	var skinnedMesh = new THREE.SkinnedMesh(geometry, new THREE.MeshFaceMaterial(materials));
	skinnedMesh.position.y = 50;
	skinnedMesh.scale.set(15, 15, 15);
	scene.add(skinnedMesh);
	
	animate(skinnedMesh);
});

load 方法接受两个参数:模型路径和回调函数。加载模型时将调用此函数(因此同时您可以向用户显示加载栏)。将使用两个参数调用回调函数:模型的几何形状及其材料(它们随模型一起导出)。在回调中,我们正在创建网格,但这次是 THREE.SkinnedMesh,它支持动画。

接下来,我们将模型向上移动 50 个单位,将其放在立方体的顶部,将其缩放 15 倍(因为我倾向于在 Blender 中创建小模型)并将其添加到场景中。接下来我们调用 animate 函数来设置并播放动画。


第3步:动画

现在我们设置动画。这是 animate 函数的源代码:

function animate(skinnedMesh) {
	var materials = skinnedMesh.material.materials;

	for (var k in materials) {
		materials[k].skinning = true;
	}

	THREE.AnimationHandler.add(skinnedMesh.geometry.animation);
	animation = new THREE.Animation(skinnedMesh, "ArmatureAction", THREE.AnimationHandler.CATMULLROM);
	animation.play();
}

首先,我们必须在模型的所有材质中启用蒙皮(动画)。接下来,我们必须将模型中的动画添加到 THREE.AnimationHandler 并创建 THREE.Animation 对象。参数按以下顺序排列:要设置动画的网格、模型中的动画名称和插值类型(当您拥有像人体这样的复杂模型,并且希望网格平滑弯曲时很有用)。最后,我们播放动画。

但是如果你现在打开浏览器,你会看到模型没有移动:

在 WebGL 中使用 Three.js 探索模型和动画

要解决此问题,我们必须在 render 函数中添加一行,位于 articleSystem 旋转下方:

if (animation) animation.update(delta);

这将更新动画的时间,因此 THREE.AnimationHandler 知道要渲染哪一帧。现在打开浏览器,您应该看到顶部的立方体向左和向右弯曲:

在 WebGL 中使用 Three.js 探索模型和动画


第 4 步:多个动画

是的,有一种解决方法仅适用于模型中的一个动画序列,但它需要您对其进行编辑。这个想法是将每个动画添加到一个序列中,然后,当该动画结束时,下一个动画开始。接下来,导出模型后,您需要更改动画代码。假设我们有一个从开始到第三秒的站立动画,以及从第三秒到结束的行走动画。然后在我们的 render 函数中,我们必须检查动画是哪一秒,如果到达当前序列的结束时间,则停止它并从头开始播放:

var currentSequence = 'standing';

function (render) {
...
	if (animation) animation.update(delta);
	if (currentSequence == 'standing') {
		if (animation.currentTime > 4) {
			animation.stop();
			animation.play(false, 0); // play the animation not looped, from 0s
		}
	} else if (currentSequence == 'walking') {
		if (animation.currentTime <= 4 || animation.currentTime > 8) {
			animation.stop();
			animation.play(false, 4); // play the animation not looped, from 4s
		}
	}
...
}

您必须记住从正确的时间开始不循环的动画。如果用户的帧速率确实很低,这当然会出现问题,因为增量会更高,并且 animation.currentTime 可能远高于任何特定序列的限制,导致播放下一个序列的某些部分。但只有当增量约为 300-500 毫秒时才会引人注目。

现在要更改 animate 函数来播放行走动画,只需将这些参数添加到 animation.play 函数即可:

animation.play(false, 0);

此外,让我们允许用户使用 a 键在动画之间切换。将此代码添加到文件末尾,就在 render() 调用之前:

document.addEventListener('keyup', function (e) {
	if (e.keyCode == 'A'.charCodeAt(0)) {
		currentSequence = (currentSequence == 'standing' ? 'walking': 'standing');
	}
});

第 5 步:附着到骨骼

这种技术在角色扮演游戏中特别有用,但它也可以应用于其他类型。它涉及将另一个对象附加到动画对象的骨骼上:衣服、武器等。

让我们首先修改 loader.load 回调。在 scene.add(skinnedMesh') 下添加此代码:

item = new THREE.Mesh(new THREE.CubeGeometry(100, 10, 10), new THREE.MeshBasicMaterial({ color: 0xff0000 }));
item.position.x = 50;
pivot = new THREE.Object3D();
pivot.scale.set(0.15, 0.15, 0.15);
pivot.add(item);
pivot.useQuaternion = true;
skinnedMesh.add(pivot);

item 网格模拟您可能想要附加到动画对象的东西。为了使其围绕特定点而不是围绕中心旋转,我们将其添加到 pivot 对象并将其向右移动 50 个单位(宽度的一半)。我们必须将其缩放到 0.15,因为它将被添加到 skinnedMesh,其缩放比例为 15。最后,在将其添加到我们的动画对象之前,我们告诉它使用四元数。

基本上,四元数是一个数字系统,但由于 Three.js 为我们处理了所有事情,如果您不想,则不必深入研究这个主题(但如果您愿意,请查看其维基百科页)。它们用于旋​​转物体,而没有万向节锁定的风险。

现在,在 render 函数中,我们必须更新对象的位置和旋转:

pivot.position = new THREE.Vector3().getPositionFromMatrix(skinnedMesh.bones[2].skinMatrix);
pivot.quaternion.setFromRotationMatrix(skinnedMesh.bones[2].skinMatrix);

让我解释一下这里发生了什么。首先,我们将位置设置为与模型中最后一个骨骼的位置相同。我们使用 skinMatrix 属性来计算它。然后我们使用相同的属性来计算 pivot 旋转的四元数。之后,您可以打开浏览器,您应该看到红色光束附加到我们的模型上:

在 WebGL 中使用 Three.js 探索模型和动画


结论

我希望您从本教程中学到了一些新的有趣的技术。与往常一样,请随意尝试我们创建的应用程序。在本系列的下一个(也是最后一个)教程中,我将向您展示 OpenGL/WebGL 着色器的真正威力。

以上就是在 WebGL 中使用 Three.js 探索模型和动画的详细内容,更多请关注编程之家其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


kindeditor4.x代码高亮功能默认使用的是prettify插件,prettify是Google提供的一款源代码语法高亮着色器,它提供一种简单的形式来着色HTML页面上的程序代码,实现方式如下: 首先在编辑器里面插入javascript代码: 确定后会在编辑器插入这样的代码: <pre
这一篇我将介绍如何让kindeditor4.x整合SyntaxHighlighter代码高亮,因为SyntaxHighlighter的应用非常广泛,所以将kindeditor默认的prettify替换为SyntaxHighlighter代码高亮插件 上一篇“让kindeditor显示高亮代码”中已经
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小
JS怎么获取当前时间戳
JS如何判断对象是否为数组
JS怎么获取图片当前宽高
JS对象如何转为json格式字符串
JS怎么获取图片原始宽高
怎么在click事件中调用多个js函数
js如何往数组中添加新元素
js如何拆分字符串
JS怎么对数组内元素进行求和
JS如何判断屏幕大小
js怎么解析json数据
js如何实时获取浏览器窗口大小
原生JS实现别踩白块小游戏(五)
原生JS实现别踩白块小游戏(一)