【3D游戏基础】蒙皮骨骼动画与骨架
创始人
2024-05-02 05:22:44

效果

目标!画出蒙皮动画的骨架。
e9a6eceb1b848d67ed52b272a25518db.gif

视频

https://www.bilibili.com/video/BV1pM411m7Yw

PPT

https://zfxdvouj61.feishu.cn/file/boxcnwgESO6zdQetO7oNhKboNsd
以下为PPT文字稿,建议还是看视频

讲讲自己对蒙皮骨骼动画的理解,并在 Cocos Creator 3.6 中绘制出骨架~希望对大家有帮助~

917774a7dd4dc5621689d9c7c931f3b4.png

这是我们今天实现效果,在 Cocos Creator 中把骨架画出来,图中绿色的线就是绘制的骨架

e56cb73a7b2a86eea0bf849fdd0dceda.gif

在开始之前,我们介绍一下如何导入模型?长按3d资源拖入到资源管理器中.

3239e265fd9e9402f295dfbde7292a8b.png

让我们看看gltf资源包括什么(介绍最下方),mesh 网格,texture 贴图,material 材质,animation 动画 ,skeleton 骨架数据。根节点有个动画组件,cips是动画列表,default clip 是默认动画, play on load 是加载后自动播放。Sockets 是挂点系统。启用 useBakedAnimation 时会使用预烘焙骨骼动画系统(所有动画数据都会按照指定帧率提前预采样、烘焙到全局复用的骨骼动画贴图合集上),禁用 useBakedAnimation 后会使用实时计算骨骼动画系统(动画数据会输出到场景的骨骼节点树中)。

ca707008c5cd549a36973264d8b29e0b.png

mesh 就是网格,由三角形拼成的网格,可以看到这个网格有7325个顶点,和11186个三角形,minpos 就是包围盒最小值, maxpos 就是包围盒最大的值

5842f5d70503c8439e3d15405e3e3fdb.png

关于网格,这张图会看的清楚一点,由多个三角形构成。

6b0c57e8196eaadc7431f6e4a2b951dc.jpeg

材质就像是给刚才的网格穿上的衣服,贴图就像是衣服上好看的图案

284f11be6199e72ae57dd1544e99f154.png

可以在这个模型上看到贴图的部件,是通过纹理映射的方式显示这张图片。例如手套映射到贴图的右下角。

c134807ed053c57cbe6e381861689b75.png

还有一种常见的贴图叫法线贴图,简单来说这张贴图可以让模型更有凹凸感

b6a97462dfc8d34638893ee763579cfe.jpeg

骨架,就像是人体的骨骼一样。蒙皮,蒙的就是网格相对于骨架的位置

e5e97fbdbae56e3472480041d8fd8dd4.jpeg

事实上,在实现中并没有骨架,并不是一条一条的线,而是一个一个的点。叫做关节或者说骨骼点。蒙皮就是根据根据这个点,计算网格点的位置。

39ab4f246fe7a15a064281ad876cf365.jpeg

选中场景中的3d模型,点击动画编辑器,进入动画编辑模式。可以预览动画效果。

7180682665d56bdc694fa4aa74614510.png

点击播放按钮就可以播放了。可以看到右上角的属性面板并没有变化,那么这个动画是移动的是什么呢?

879ef2c77d288227ce1bc6925c64967f.gif

前面几个点的 postion rotation 并没有发生变化

0bafefe5144d13b6db1055eb77c48b4d.gif

可以看到后面几个点位移旋转发生了变化,这些点就是骨骼(关节)。蒙皮动画的本质是改变骨骼的节点信息,网格再根据骨骼点实时计算网格的形状。

fe8ff0417190695e2d4322a42633ff71.gif

材质,网格,骨架是由蒙皮网格渲染器(skinmeshrenderer) 组织在一起。

d73a57ac7ddc82a2944e4dada8c0e6f2.png

总结一下,一个3d资源拖入到场景中的结构是怎么样的。根节点有一个骨骼动画组件。他的儿子中包含了骨骼蒙皮渲染组件(将材质,网格,骨骼组织在一起)。还有种儿子是骨骼(关节),蒙皮动画实际上是对这些骨骼点进去移动旋转,然后网格再根据这个点的信息,再计算网格的形状(蒙皮)。

6b7e9e3db019a68c00c7a6fb4a7c5ab3.png

了解了上面的知识,我们现在开始实战吧。我们的目标是画出这个骨骼!

1e2b37159690a9552fef36a23ceea602.gif

我们该如何绘制骨架呢?只要在这些骨骼点和其父节点画一条线就行了。

4131ad1a5520e4169719b7a171bc35ee.gif

我们要画的是这些骨骼,这些骨骼的数据应该在哪里获取呢?是的,就在骨架数据中获取,骨架数据就是在蒙皮网格渲染器中。

7c4823de585afd63ab43de3f94043576.png

model 就是对应这初始节点。先拿到蒙皮网格渲染器的组件,找到骨架数据,再找到骨骼点,并做上标记。最后再递归按深度优先的顺序把所有骨骼点保存起来。这个bones就是所有的关节点了。

e5251098297954ac53753701cc7b7269.png

那么我们应该用什么组件画骨架呢?这里用了 Cocos Creator 的线段组件。对有爸爸的骨骼们创建线段组件。把每个骨骼和他爸爸的世界坐标告诉线段组件,就能画出骨架了。

4b7d2c3b3bf92d53e0187141d7abc445.png

还需要注意的是,要想把这东西画到最前!需做到 透 深 优!透是指透明渲染队列。在 Cocos Creator 默认的前向渲染管线中,是先渲染不透明队列再渲染透明队列。选择透明队列就可以再更后的阶段绘制。深 指的是 深度读写都关闭,深度写是影响之后东西的绘画,深度读是只被之前绘画的深度影响,当然我们都不想影响就都关了。优 是只 优先级,要在最后画!

82a858227f9b8fcb51d8ef04461ccca0.png

最后,介绍一下这个脚本怎么使用。将这个脚本拖入到场景中,再挂上场景中的3D模型就可以了。

3728f7cf6f77c73cf9194ffeff8339e5.png

小结~ 1.动画驱动骨骼 2.骨骼决定网格 3.画最前,透深优

b7683129c281f48730a950efeb269f3d.png

代码

import { _decorator, Component, Node, SkinnedMeshRenderer, Line, SkeletalAnimation, Color, gfx, GradientRange, log } from 'cc';
const { ccclass, property } = _decorator;@ccclass('SkeletonHelper')
export class SkeletonHelper extends Component {@property(Node)model: Node = null!private bones: Node[] = []private lines: Line[] = []start() {log('欢迎关注微信公众号【白玉无冰】 https://mp.weixin.qq.com/s/-I6I6nG2Hnk6d1zqR-Gu2g')const skeletalAnimation = this.model.getComponent(SkeletalAnimation)skeletalAnimation.useBakedAnimation = false; // maybe todoconst skinMeshRds = this.model.getComponentsInChildren(SkinnedMeshRenderer)skinMeshRds.forEach(element => {const skinningRoot = element.skinningRootelement.skeleton.joints.forEach((v) => {const node = skinningRoot.getChildByPath(v)node['isBone'] = true;})});const bones = this.getBoneList(this.model);this.bones = bones;for (let i = 0; i < bones.length; i++) {const bone = bones[i];if (bone.parent && bone.parent['isBone']) {const line = this.addComponent(Line);const state = { priority: 255, depthStencilState: new gfx.DepthStencilState(false, false) }// @ts-ignoreline._materialInstance.overridePipelineStates(state)line.worldSpace = true;line.width.constant = 0.01;line.color.mode = GradientRange.Mode.TwoColors //there are some bugs in cocos creator // engine\cocos\particle\models\line-model.ts   // engine\cocos\particle\animator\gradient.tsline.color.colorMin = Color.BLUEline.color.colorMax = Color.GREENline.positions = [bone.worldPosition, bone.parent.worldPosition] as never[]this.lines.push(line)}}}showSkeleton(show: boolean) {this.lines.forEach(l => l.enabled = show)}private getBoneList(object: Node) {const boneList: Node[] = [];if (object['isBone']) {boneList.push(object);}for (let i = 0; i < object.children.length; i++) {boneList.push.apply(boneList, this.getBoneList(object.children[i]));}return boneList;}lateUpdate(deltaTime: number) {let lineIndex = 0;for (let i = 0; i < this.bones.length; i++) {const bone = this.bones[i];if (bone.parent && bone.parent['isBone']) {const line = this.lines[lineIndex++];line.positions = [bone.worldPosition, bone.parent.worldPosition] as never[]}}}
}

视频

2fd730477563a8c40cfc047c064b0d8c.jpeg

“点赞“ ”在看” 鼓励一下392048b3bf09888566afd6c2f328e199.png

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...