From 9480c6474ab8b58bd277bba0d5404dbeb8add5f0 Mon Sep 17 00:00:00 2001 From: luzhuang <364439895@qq.com> Date: Mon, 19 Feb 2024 11:27:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A8=E7=94=BB=E6=96=87=E6=A1=A3=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20(#955)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: animator doc --- docs/animation-animator.zh-CN.md | 75 ++++---- docs/animation-animatorController.zh-CN.md | 201 +++++++++++++++++++++ docs/animation-clip-for-artist.zh-CN.md | 2 +- docs/animation-clip.zh-CN.md | 141 ++++++++------- docs/animation-overview.zh-CN.md | 42 +++++ docs/animation-sprite-sheet.zh-CN.md | 28 ++- docs/animation-state-machine.md | 166 ----------------- docs/animation-system.zh-CN.md | 37 ++-- docs/core-component.zh-CN.md | 12 +- docs/core-entity.zh-CN.md | 13 +- docs/interface-intro.zh-CN.md | 2 + 11 files changed, 409 insertions(+), 310 deletions(-) create mode 100644 docs/animation-animatorController.zh-CN.md create mode 100644 docs/animation-overview.zh-CN.md delete mode 100644 docs/animation-state-machine.md diff --git a/docs/animation-animator.zh-CN.md b/docs/animation-animator.zh-CN.md index 67311572a..f7988991a 100644 --- a/docs/animation-animator.zh-CN.md +++ b/docs/animation-animator.zh-CN.md @@ -5,7 +5,7 @@ type: 动画 label: Animation --- -动画控制组件([Animator](${api}core/Animator))可以通过状态机组织动画片段([AnimationClip](${api}core/AnimationClip))实现更加灵活丰富的动画效果。 +动画控制组件([Animator](${api}core/Animator))的作用是读取[动画控制器](${docs}animation-animatorController)([AnimatorController](${api}core/AnimatorController))的数据,并播放其内容。 ### 参数说明 @@ -15,53 +15,44 @@ label: Animation ## 编辑器使用 -通过 `AnimatorController` 编辑器,用户可以很方便的添加过渡和混合等动画效果。 +1. 当我们把模型拖入到场景中,模型以初始姿态展示出来,但是并不会播放任何动画,我们需要在模型实体上添加动画控制组件([Animator](${api}core/Animator)) -1. 将带动画的模型上传到编辑器上,编辑器会自动加载其上的动画片段到资源面板中 +![2](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*kuSLTaxomrUAAAAAAAAAAAAADsJ_AQ/original) -![4](https://gw.alipayobjects.com/zos/OasisHub/2ee85519-4f48-4e65-8dcc-b6afe9d1f7d9/4.jpg) +2. 动画控制组件([Animator](${api}core/Animator))需要绑定一个 [动画控制器](${docs}animation-animatorController) 资产,我们创建并绑定 -2. 当我们把模型拖入到场景中,模型以初始姿态展示出来,但是并不会播放任何动画,我们需要在模型实体上添加 Animator 组件,来控制动画的播放 +![3](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*irT7SZvw4N8AAAAAAAAAAAAADsJ_AQ/original) - ![image-20210902230821166](https://gw.alipayobjects.com/zos/OasisHub/405ebaa7-8c03-4fd0-816e-cbcb39562b68/1667457441830-207e0940-4a82-4bc2-8d9c-d12d44c3eb31.png) +![4](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*VtX3RJR8kdMAAAAAAAAAAAAADsJ_AQ/original) -3. Animator 组件需要引入一个 AnimatorController 资产,我们创建并引入 +3. 至此你在导出的项目中就可以通过 `animator.play` 播放[动画控制器](${docs}animation-animatorController)中的动画了。 -![image](https://gw.alipayobjects.com/zos/OasisHub/35f5788a-7544-4231-b11e-373fcce31267/1667457702054-45c9d61a-1e9b-49b5-a719-36724471aaa2.png) - -![image](https://gw.alipayobjects.com/zos/OasisHub/68de5813-be5f-4669-91bc-d8d3f4077c5a/1667457755170-565aaa77-ec4b-462a-9a38-dc7ad66e9c19.png) - -4. 刚创建的 AnimatorController 中没有任何数据,我们需要对他进行编辑, 双击资产, 并为它添加一个 AnimatorState - -![3](https://gw.alipayobjects.com/zos/OasisHub/4f4139aa-eaaf-4b9d-b077-1570e783843d/3.jpg) - -5. 点击 AnimatorState 为它绑定一个 AnimationClip - -![image](https://gw.alipayobjects.com/zos/OasisHub/8e29b9fa-eeed-4e5c-84c1-ea68f9732a92/1667457999371-e0ed9c57-d44c-4f2a-abda-12eba6e3a934.png) - -6. 至此你在导出的项目中就可以通过 `animator.play("New State")` 播放 `running` 动画了。如果你没有为实体添加 Animator 组件的话 Galacean Engine 会为你默认创建一个并且 AnimatorController 中默认添加了模型的所有动画,拿上图的模型举例,你只需要直接调用 `animator.play("running")` 就可以了。以上内容是可以帮助你更清晰的了解 Animator 的运行机制,当然除此以外你可以通过 AnimatorController 的编辑器实现更多的功能。 +如果你没有为实体添加 动画控制组件([Animator](${api}core/Animator))的话 Galacean Engine 会为你默认创建一个并且 [动画控制器](${docs}animation-animatorController) 中默认添加了模型的所有动画片段,当然除此以外你可以通过 [动画控制器](${docs}animation-animatorController) 实现更多的功能。 ## 脚本使用 +> 在使用脚本之前,最好阅读[动画系统构成](${docs}animation-system)文档,以帮助你更好的了解动画系统的运行逻辑 + ### 播放动画 -在加载GLTF模型后引擎会自动为模型添加一个Animator组件,并将模型中的动画片段加入其中。可以直接在模型的根实体上获取Animator组件,并播放指定动画。 +在加载 GLTF 模型后引擎会自动为模型添加一个 Animator 组件,并将模型中的动画片段加入其中。可以直接在模型的根实体上获取 Animator 组件,并播放指定动画。 ```typescript engine.resourceManager - .load("https://gw.alipayobjects.com/os/bmw-prod/5e3c1e4e-496e-45f8-8e05-f89f2bd5e4a4.glb") + .load( + "https://gw.alipayobjects.com/os/bmw-prod/5e3c1e4e-496e-45f8-8e05-f89f2bd5e4a4.glb" + ) .then((asset) => { const { defaultSceneRoot } = asset; rootEntity.addChild(defaultSceneRoot); const animator = defaultSceneRoot.getComponent(Animator); animator.play("run"); -}); + }); ``` #### 控制播放速度 -你可以通过 [speed](${api}core/Animator#speed)  属性来控制动画的播放速度。 `speed` 默认值为 `1.0` ,值越大播放的越快,越小播放的越慢。当值为负数时,进行倒播。 - +你可以通过 [speed](${api}core/Animator#speed)  属性来控制动画的播放速度。 `speed`  默认值为 `1.0` ,值越大播放的越快,越小播放的越慢。当值为负数时,进行倒播。 ```typescript animator.speed = 2.0; @@ -78,10 +69,10 @@ animator.enabled = false; animator.enabled = true; ``` -如果你只想针对某一个动画状态进行暂停,可以通过将它的速度设置为0来实现。 +如果你只想针对某一个动画状态进行暂停,可以通过将它的速度设置为 0 来实现。 ```typescript -const state = animator.findAnimatorState('xxx'); +const state = animator.findAnimatorState("xxx"); state.speed = 0; ``` @@ -89,7 +80,7 @@ state.speed = 0; -你可以使用 [play](${api}core/Animator#play) 方法来播放指定的AnimatorState。参数为AnimatorState的`name`,其他参数说明详见[API文档](${api}core/Animator#play)。 +你可以使用 [play](${api}core/Animator#play)  方法来播放指定的 AnimatorState。参数为 AnimatorState 的`name`,其他参数说明详见[API 文档](${api}core/Animator#play)。 ```typescript animator.play("run"); @@ -103,26 +94,26 @@ const normalizedTimeOffset = 0.5; // 归一化的时间 animator.play("run", layerIndex, normalizedTimeOffset); ``` -### 动画数据 - -#### 设置动画数据 - -你可以通过 [animatorController](${api}core/Animator#animatorController)  属性来设置动画控制器的动画数据,加载完成的GLTF模型会自动添加一个默认的AnimatorController。 +### 获取当前在播放的动画状态 +你可以使用 [getCurrentAnimatorState](${api}core/Animator#getCurrentAnimatorState)  方法来获取当前正在播放的 AnimatorState。参数为动画状态所在层的序号`layerIndex`, 详见[API 文档](${api}core/Animator#getCurrentAnimatorState)。获取之后可以设置动画状态的属性,比如将默认的循环播放改为一次。 ```typescript -animator.animatorController = new AnimatorController(); +const currentState = animator.getCurrentAnimatorState(0); +// 播放一次 +currentState.wrapMode = WrapMode.Once; +// 循环播放 +currentState.wrapMode = WrapMode.Loop; ``` -#### 复用动画数据 - -有的时候模型的动画数据存储在其他模型中,可以用如下的方式引入使用: - - +### 获取动画状态 -除此以外还有一种方式,Animator的 [AnimatorController](${api}core/AnimatorController) 就是一个数据存储的类,它不会包含运行时的数据,基于这种设计只要绑定Animator组件的模型的**骨骼节点的层级结构和命名相同**,我们就可以对动画数据进行复用。 +你可以使用 [findAnimatorState](${api}core/Animator#findAnimatorState)  方法来获取指定名称的 AnimatorState。详见[API 文档](${api}core/Animator#getCurrentAnimatorState)。获取之后可以设置动画状态的属性,比如将默认的循环播放改为一次。 ```typescript -const animator = model1.getComponent(Animator); -animator.animatorController = model2.getComponent(Animator).animatorController; +const state = animator.findAnimatorState("xxx"); +// 播放一次 +state.wrapMode = WrapMode.Once; +// 循环播放 +state.wrapMode = WrapMode.Loop; ``` diff --git a/docs/animation-animatorController.zh-CN.md b/docs/animation-animatorController.zh-CN.md new file mode 100644 index 000000000..ac864e06d --- /dev/null +++ b/docs/animation-animatorController.zh-CN.md @@ -0,0 +1,201 @@ +--- +order: 3 +title: 动画控制器 +type: 动画 +label: Animation +--- + +动画控制器([AnimatorController](${api}core/AnimatorController))用于组织[动画片段](${docs}animation-clip)([AnimationClip](${api}core/AnimationClip))实现更加灵活丰富的动画效果。 + +## 编辑器使用 + +### 基础使用 + +通过动画控制器的编辑器,用户可以在其中组织[动画片段](${docs}animation-clip)的播放逻辑 + +1. 准备好动画片段([制作动画片段](${docs}animation-clip-)) + +![1](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*Qc8sQ6iJd8IAAAAAAAAAAAAADsJ_AQ/original) + +2. 要组织播放这些动画片段我们需要创建一个动画控制器([AnimatorController](${api}core/AnimatorController))资产 + +![3](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*irT7SZvw4N8AAAAAAAAAAAAADsJ_AQ/original) + +3. 刚创建的动画控制器中没有任何数据,我们需要对他进行编辑,双击资产, 并为它添加一个 AnimatorState + +![5](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*BcYXSI6OTyoAAAAAAAAAAAAADsJ_AQ/original) + +4. 点击 AnimatorState 为它绑定一个动画片段 + +![6](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*KwFzRZCmbxoAAAAAAAAAAAAADsJ_AQ/original) + +5. 在[动画控制组件](${docs}animation-animator)上绑定该动画控制器([AnimatorController](${api}core/AnimatorController))资产 + +![4](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*VtX3RJR8kdMAAAAAAAAAAAAADsJ_AQ/original) + +6. 至此你在导出的项目中就可以通过 `animator.play("New State")` 播放 `run` 动画了 + +你还可以通过动画控制器的编辑器实现更多的功能: + +### 默认播放 + +将 AnimatorState 连接到`entry`上你导出的项目运行时就会自动播放其上的动画,而不需再调用 `animator.play`。同时你也会看到编辑器的模型也开始播放动画了。 +![2](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*t2JlQ7PGqikAAAAAAAAAAAAADsJ_AQ/original) + +### 动画过渡 + +将两个想要过渡的 `AnimatorState` 连接即可实现动画过渡的效果, 点击两个动画间的连线,可以修改动画过渡的参数调整效果 + +![animationcrossfade](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*7_OFQqABtc0AAAAAAAAAAAAADsJ_AQ/original) + +#### 参数说明 + +| 属性 | 功能说明 | +| :------- | :----------------------------------------------------------------- | +| duration | 过渡时长,时间为相对目标状态的归一化时间, 默认值为 1.0 | +| offset | 目标状态向前的偏移时间,时间为相对目标状态的归一化时间, 默认值为 0 | +| exitTime | 起始状态过渡开始时间,时间为相对起始状态的归一化时间, 默认值为 0.3 | + +### 动画叠加 + +Galacean 引擎支持多层的动画叠加。动画叠加是通过 `AnimatorControllerLayer` 间的混合达到的效果。第一层是基础动画层,修改它的权重及混合模式将不会生效。 + +双击 `AnimatorController` 资源文件编辑动画,添加 Layer,将混合的动作也连接`entry` + +![animationadditive](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*vF7fS6mRnmYAAAAAAAAAAAAADsJ_AQ/original) + +有的时候你想要得到一个固定的姿势,需要裁减设计师给到的动画切片,可以修改 `AnimatorState` 的`StartTime` 及 `EndTime`,点击 `AnimatorState` 即可对其进行编辑: + +![1](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*JNFGTboEM5QAAAAAAAAAAAAADsJ_AQ/original) + +| 属性 | 功能说明 | +| :------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Name | 修改 `AnimatorState` 的名字,名字在所在的层要是**唯一**的。 | +| AnimationClip | 用于绑定 `AnimationClip` 资产,`AnimationClip` 存储了模型的动画数据。 | +| WrapMode | `AnimatorState` 是循环播放还是播放一次,默认为 `Once` 即播放一次。 | +| Speed | `AnimatorState` 的播放速度,默认值为 1.0 ,值越大动画速度越快 | +| StartTime | `AnimatorState` 从 `AnimationClip` 的哪个时间开始播放,时间为相对 `AnimationClip` 时长的归一化时间。默认值为 0 ,即从头开始播放。 例如:值为 1.0 ,则是 `AnimationClip` 的最后一帧状态。 | +| EndTime | `AnimatorState` 播放到 `AnimationClip` 的哪个时间结束播放,时间为相对 `AnimationClip` 时长的归一化时间。默认值为 1.0 ,即播放到最后。 | + +你也可以通过修改 `Layer` 的 `Weight` 参数来调整 `Layer` 在混合中的权重,通过修改 `Blending` 来修改混合模式。 + +![animationadditive2](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*_3aNSKP44FgAAAAAAAAAAAAADsJ_AQ/original) + +| 属性 | 功能说明 | +| :------- | :--------------------------------------------------------------------------------- | +| Name | 该层的名字。 | +| Weight | 该层的混合权重,默认值为 1.0 。 | +| Blending | 该层的混合模式,`Additive` 为叠加模式, `Override` 为覆盖模式,默认值为 `Override` | + +## 脚本使用 + +> 在使用脚本之前,最好阅读[动画系统构成](${docs}animation-system)文档,以帮助你更好的了解动画系统的运行逻辑 + +### 默认播放 + +你可以通过设置 AnimatorStateMachine 的[defaultState](${api}core/AnimatorStateMachine#defaultState) 来设置所在层的默认播放动画,这样当 Animator `enabled=true` 时你不需要调用 `play` 方法即可默认播放。 + +```typescript +const layers = animator.animatorController.layers; +layers[0].stateMachine.defaultState = animator.findAnimatorState("walk"); +layers[1].stateMachine.defaultState = animator.findAnimatorState("sad_pose"); +layers[1].blendingMode = AnimatorLayerBlendingMode.Additive; +``` + +### 动画过渡 + +你可以通过为 `AnimatorState` 添加 `AnimatorTransition` 实现动画状态间的过渡。 + +```typescript +const walkThenRunState = animatorStateMachine.addState("walkThenRun"); +walkThenRunState.clip = walkClip; +const runState = animatorStateMachine.addState("run"); +runState.clip = runClip; +const transition = new AnimatorStateTransition(); +transition.duration = 1; +transition.offset = 0; +transition.exitTime = 0.5; +transition.destinationState = runState; +walkThenRunState.addTransition(transition); +animator.play("walkThenRun"); +``` + +通过这样的方式你之后每次在该动画状态机所在的层播放 `walkThenRun` 动画时都会在 `walk` 动画播放一半时开始过渡到 `run` 动画。 + +### 动画叠加 + +将想要叠加的动画状态添加到其他层并将它的混合模式设置为 `AnimatorLayerBlendingMode.Additive` 即可实现动画叠加效果, + + + +### 动画数据 + +#### 设置动画数据 + +你可以通过 [animatorController](${api}core/Animator#animatorController)  属性来设置动画控制器的动画数据,加载完成的 GLTF 模型会自动添加一个默认的 AnimatorController。 + +```typescript +animator.animatorController = new AnimatorController(); +``` + +#### 复用动画数据 + +有的时候模型的动画数据存储在其他模型中,可以用如下的方式引入使用: + + + +除此以外还有一种方式,Animator 的 [AnimatorController](${api}core/AnimatorController) 就是一个数据存储的类,它不会包含运行时的数据,基于这种设计只要绑定 Animator 组件的模型的**骨骼节点的层级结构和命名相同**,我们就可以对动画数据进行复用。 + +```typescript +const animator = model1.getComponent(Animator); +animator.animatorController = model2.getComponent(Animator).animatorController; +``` + +### 状态机脚本 + + + +状态机脚本为用户提供了动画状态的生命周期钩子函数来编写自己的游戏逻辑代码。用户可以通过继承 [StateMachineScript](${api}core/StateMachineScript) 类来使用状态机脚本。 + +状态机脚本提供了三个动画状态周期: + +- `onStateEnter`:动画状态开始播放时回调。 +- `onStateUpdate`:动画状态更新时回调。 +- `onStateExit`:动画状态结束时回调。 + +```typescript +class theScript extends StateMachineScript { + // onStateEnter is called when a transition starts and the state machine starts to evaluate this state + onStateEnter(animator: Animator, stateInfo: any, layerIndex: number) { + console.log("onStateEnter", animator, stateInfo, layerIndex); + } + + // onStateUpdate is called on each Update frame between onStateEnter and onStateExit callbacks + onStateUpdate(animator: Animator, stateInfo: any, layerIndex: number) { + console.log("onStateUpdate", animator, stateInfo, layerIndex); + } + + // onStateExit is called when a transition ends and the state machine finishes evaluating this state + onStateExit(animator: Animator, stateInfo: any, layerIndex: number) { + console.log("onStateExit", animator, stateInfo, layerIndex); + } +} + +animatorState.addStateMachineScript(theScript); +``` + +如果你的脚本不用复用的话你也可以这么写: + +```typescript +state.addStateMachineScript( + class extends StateMachineScript { + onStateEnter( + animator: Animator, + animatorState: AnimatorState, + layerIndex: number + ): void { + console.log("onStateEnter: ", animatorState); + } + } +); +``` diff --git a/docs/animation-clip-for-artist.zh-CN.md b/docs/animation-clip-for-artist.zh-CN.md index 29150c0ed..05f293bb4 100644 --- a/docs/animation-clip-for-artist.zh-CN.md +++ b/docs/animation-clip-for-artist.zh-CN.md @@ -1,5 +1,5 @@ --- -order: 4 +order: 6 title: 美术动画切片 type: 动画 label: Animation diff --git a/docs/animation-clip.zh-CN.md b/docs/animation-clip.zh-CN.md index 6a26eda14..d274dcc48 100644 --- a/docs/animation-clip.zh-CN.md +++ b/docs/animation-clip.zh-CN.md @@ -5,75 +5,88 @@ type: 动画 label: Animation --- -设计师输出的带动画的模型中的每个动作在我们的编辑器中会被解析成一个个的**动画片段**资产,我们也可以通过动画片段编辑器创作额外的动画。 +**动画片段**是 Galacean 动画系统的核心元素之一,Galacean 支持导入外部设计软件设计的模型动画,设计师输出的带动画的模型中的每个动画在 Galacean 中会被解析成一个个的**动画片段**资产,我们也可以通过动画片段编辑器创作额外的动画。 + +有两种常用的方式得到动画片段 + +1. 导入用第三方工具(例如 Autodesk® 3ds Max®, Autodesk® Maya®, Blender)创建的带动画的模型,详见[美术制作动画片段](${docs}animation-clip-for-artist) + +![1](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*Qc8sQ6iJd8IAAAAAAAAAAAAADsJ_AQ/original) + +2. 在 Galacean 中创建动画片段(下文会介绍编辑器和脚本这两种创建方式) + +## 动画面板介绍 + 动画片段编辑器目前支持除物理相关组件的所有可插值属性的编辑,如果你需要编辑其他属性,要在实体上添加对应的组件。 +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*NzstQooi6vMAAAAAAAAAAAAADsJ_AQ/original) + +> 注:Galacean 动画编辑器默认以 60FPS 为基准,上图所示时间`0:30`为 30 帧处, 若时间轴刻度为`1:30`则为 90 帧处 + ## 基础操作 ### Transform 组件示例 1. 在资产面板中 右键/点击+ 创建 `动画片段` 资产 -![1](https://gw.alipayobjects.com/zos/OasisHub/52c428f1-6b5f-4486-93f9-f27ef468a9be/image-20230116150410999.png) +![1](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*Bs6UQ6Vwz1UAAAAAAAAAAAAADsJ_AQ/original) 2. 双击 `动画片段` 资产,并选择一个实体作为 `动画片段` 的编辑对象 -![image-20230116150755284](https://gw.alipayobjects.com/zos/OasisHub/016a62dc-991f-4c67-9d00-0c3b09f438dc/image-20230116150755284.png) -![image-20230116151013992](https://gw.alipayobjects.com/zos/OasisHub/31d2f185-fb98-42c5-af98-46c0fe6a4feb/image-20230116151013992.png) +![image-20230116150755284](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*lpghT5f2f8YAAAAAAAAAAAAADsJ_AQ/original) +![image-20230116151013992](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*puAUR61-qVQAAAAAAAAAAAAADsJ_AQ/original) 3. 添加要做动画的属性(这里我添加了两个) -![image-20230116151140988](https://gw.alipayobjects.com/zos/OasisHub/443943a5-a586-42ae-badd-5117a33a0628/image-20230116151140988.png) -![image-20230116151307372](https://gw.alipayobjects.com/zos/OasisHub/59154743-fd64-4905-85c7-35cb315b625d/image-20230116151307372.png) -![image-20230116151429682](https://gw.alipayobjects.com/zos/OasisHub/6fee9c22-6e7e-4ab0-9457-d4f374f6c33e/image-20230116151429682.png) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*0jmGQa_9oS0AAAAAAAAAAAAADsJ_AQ/original) +![image-20230116151429682](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*3oiwSrG8kQEAAAAAAAAAAAAADsJ_AQ/original) 4. 给属性添加关键帧 -![image-20230116151707943](https://gw.alipayobjects.com/zos/OasisHub/908d4ddb-ad3f-45e1-9164-4a55b520f205/image-20230116151707943.png) - +![image-20230116151707943](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*xZUrRqNu9yIAAAAAAAAAAAAADsJ_AQ/original) 当我们点击添加关键帧按钮时,关键帧会存入当前指定属性的值,所以当我们什么都未改变时,关键帧存入的是此刻这个实体的 `position` 值。我们希望他 60 帧后移动到 (3, 0, 0)的位置,所以先将这个正方体通过属性面板修改到(3, 0, 0) 再添加关键帧 - -![clip](https://gw.alipayobjects.com/zos/OasisHub/3379fb37-f3ed-44d7-8116-48667a2982ff/clip.gif) - +![clip](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*tXYFT42fUQ4AAAAAAAAAAAAADsJ_AQ/original) 同理我们也为 `rotation` 属性添加关键帧 +![clip2](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*LlLlQIeEfZEAAAAAAAAAAAAADsJ_AQ/original) +可以看到当属性的值改变时,`动画片段编辑器` 会自动为你添加关键帧,可以让你更方便快速的编辑。 -![clip2](https://gw.alipayobjects.com/zos/OasisHub/f0a0a28d-561e-4efb-b461-f0ae5f92efb9/clip2.gif) +##### 录制模式 -可以看到当属性的值改变时,`动画片段编辑器` 会自动为你添加关键帧,可以让你更方便快速的编辑。 +我们提供了录制模式以方便开发者快速的添加关键帧。在添加属性之后开启录制模式,当对应的属性修改时就会自动添加关键帧 +![record](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*a_vgR76aB7cAAAAAAAAAAAAADsJ_AQ/original) 5. 预览 `动画片段` 你可以直接移动时间线(可以拖动时间线,点击空白位置,在当前帧输入框中修改数值),来观察它在指定时刻的表现,比如我将时间轴移动到 30 帧 - -![timeline](https://gw.alipayobjects.com/zos/OasisHub/d736229d-beeb-4657-be4b-85825c3de939/timeline.gif) - +![timeline](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*-T6tT6OO_b4AAAAAAAAAAAAADsJ_AQ/original) 也可以直接播放 `动画片段` - -![timeline2](https://gw.alipayobjects.com/zos/OasisHub/138f524e-27f1-4db4-a7a4-90664a516e5f/timeline2.gif) - +![timeline2](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*RNRxS5GHSlEAAAAAAAAAAAAADsJ_AQ/original) 编辑好的 `动画片段`资产可以应用于任一实体,切换实体即可预览其效果 - -![timeline3](https://gw.alipayobjects.com/zos/OasisHub/766a8566-c6ec-430a-b703-3895f85e7d94/timeline3.gif) +![timeline3](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*wVnySZCp9P0AAAAAAAAAAAAADsJ_AQ/original) 6. 应用 `动画片段` -上一步只是让我们可以预览 `动画片段`的效果,真正要在项目中使用还是要使用 `动画`组件,绑定 `动画控制器` 资产,详见[动画编辑](${docs}animation-animator)。这里我们为正方体添加 `动画` 组件,可以看到创建的 `动画片段` 已经通过 `动画组件` 作用到正方体上了。 - -![animator](https://gw.alipayobjects.com/zos/OasisHub/a87bf618-93e9-4130-8f80-fd0a7ba24fa6/animator.gif) +上一步只是让我们可以预览 `动画片段` 的效果,真正要在项目中使用还是要使用[动画控制组件](${docs}animation-animator),绑定 [动画控制器](${docs}animation-animatorController) 资产,详见[动画编辑](${docs}animation-animator)。这里我们为正方体添加[动画控制组件](${docs}animation-animator),可以看到创建的 `动画片段` 已经通过[动画控制组件](${docs}animation-animator)作用到正方体上了。 +![animator](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*Zn95TpfDbMkAAAAAAAAAAAAADsJ_AQ/original) ### 文字组件示例 -文字字号动画 +#### 文字字号动画 -![image-20230116170015405](https://gw.alipayobjects.com/zos/OasisHub/10dfd915-f68d-4982-825f-ad191f58e22a/image-20230116170015405.png) +首先要有一个具有 TextRender 组件的实体 +![image-20230116170015405](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*S_9XSovxcEUAAAAAAAAAAAAADsJ_AQ/original) 此时我们再添加属性时可以看到,可添加关键帧的属性增加了 `TextRenderer` 组件相关的可插值的属性 -![image-20230116170144892](https://gw.alipayobjects.com/zos/OasisHub/1061be4b-5d88-4ae8-af0f-3856affcc51a/image-20230116170144892.png) +![textAnim](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*97OvS6MBBywAAAAAAAAAAAAADsJ_AQ/original) 我们添加 fontSize,并按照上文的方式添加关键帧 -![image-20230116170144892](https://gw.alipayobjects.com/zos/OasisHub/d53ed8f7-3126-4001-a26b-8e037fe2b6d5/animatorText.gif) +![textAnim2](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*j2xFQ43GtrMAAAAAAAAAAAAADsJ_AQ/original) + +### 帧动画示例 + +除了数值类型,Galacean 还支持引用类型的动画曲线,可以阅读[帧动画](${docs}animation-sprite-sheet)来了解,如何制作帧动画。 ## 更多操作 @@ -83,82 +96,87 @@ label: Animation 选中关键帧并拖动即可 -![animatorText2](https://gw.alipayobjects.com/zos/OasisHub/5fd37304-5b24-4219-b45a-7e29174484e3/animatorText2.gif) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*pvoKQYg5XJgAAAAAAAAAAAAADsJ_AQ/original) #### 修改关键帧的值 -把时间线移动到指定关键帧上,然后重新输入值即可 +开启录制模式,把时间线移动到指定关键帧上,然后重新输入值即可 -![animatorText3](https://gw.alipayobjects.com/zos/OasisHub/d2fc1577-9765-44a1-99e0-88173f65c8c1/animatorText3.gif) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*TWuARqwaMtUAAAAAAAAAAAAADsJ_AQ/original) #### 删除关键帧 -选中关键帧并按退格键即可 +选中关键帧右键选择删除 -![animatorText4](https://gw.alipayobjects.com/zos/OasisHub/0e0abc32-beba-460f-9e25-286698816341/animatorText4.gif) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*pIT1T7EgEg8AAAAAAAAAAAAADsJ_AQ/original) ### 编辑子实体 `动画片段` 不仅可以作用于添加`Animator`组件的实体上,还可以作用于它的子实体上。 -1. 我们为刚才的文字添加一个子实体 +1. 我们为刚才的立方体添加一个子实体 -![image-20230116173105694](https://gw.alipayobjects.com/zos/OasisHub/a59d5687-5f74-4fab-a457-42e3d07b38da/image-20230116173105694.png) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*cRQ6RqDjJiQAAAAAAAAAAAAADsJ_AQ/original) 2. 我们再点击添加属性就可以看到子实体的属性可以添加了 -![image-20230116180314221](https://gw.alipayobjects.com/zos/OasisHub/bd59b6df-a0f8-48d3-bd5d-23eeccba4816/image-20230116180314221.png) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*F9pdRItUmK4AAAAAAAAAAAAADsJ_AQ/original) 3. 选择子实体之后,添加关键帧即可 -![child](https://gw.alipayobjects.com/zos/OasisHub/3e03fc0a-a346-4897-8607-3a36ccb11e22/child.gif) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*Hb3wRI4_cocAAAAAAAAAAAAADsJ_AQ/original) ### 编辑动画曲线 -`动画片段编辑器` 支持动画曲线编辑,点击右下角的 `Curves` 即可切换 +`动画片段编辑器` 支持动画曲线编辑,点击右上角的 `Curves` 即可切换 -![image-20230116183809640](https://gw.alipayobjects.com/zos/OasisHub/529e7716-d5c6-4857-9a81-966e0f371b6b/image-20230116183809640.png) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*Nb1OQLNOk1YAAAAAAAAAAAAADsJ_AQ/original) -属性对应曲线的颜色与按钮的颜色相同 +曲线模式的纵轴为属性的数值 +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*2nJNSKjivogAAAAAAAAAAAAADsJ_AQ/original) -![image-20230116183933986](https://gw.alipayobjects.com/zos/OasisHub/1c96f6a9-d72c-4b1a-b1db-92e2ebf59ab0/image-20230116183933986.png) +你可以按 `shift+滚轮` 调整纵轴的比例 +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*e--qQ644ENsAAAAAAAAAAAAADsJ_AQ/original) -选择关键帧会出现两个控制点,调整控制点即可调整曲线 - -![curve](https://gw.alipayobjects.com/zos/OasisHub/f439881a-39a4-463d-a7fc-1551f88bcd7c/curve.gif) +属性对应曲线的颜色与按钮的颜色相同 -### 调整采样率 +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*EAJXSq_-I7QAAAAAAAAAAAAADsJ_AQ/original) -刚才的曲线调整预览看起来可能并不明显,我们可以通过调低采样率的方式减慢动画速度 +选择关键帧会出现两个控制点,调整控制点即可调整曲线 -![image-20230116185226034](https://gw.alipayobjects.com/zos/OasisHub/c1526af2-337a-4abf-bfde-4c66b6114002/image-20230116185226034.png) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*2XYOTaW6F2sAAAAAAAAAAAAADsJ_AQ/original) -![curve2](https://gw.alipayobjects.com/zos/OasisHub/2ff245ef-2f7f-4e53-a5aa-e06ead091abf/curve2.gif) +也可以通过右键关键帧直接设置内置的预设值 +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*ytdIQpv9eEkAAAAAAAAAAAAADsJ_AQ/original) ## 脚本使用 -你可以自己创建一个 [AnimationClip](${api}core/AnimationClip) 并通过 [addCurveBinding](${api}core/AnimationClip#addCurveBinding) 为它绑定 [AnimationCurve](${api}core/AnimationCurve)。 +> 在使用脚本之前,最好阅读[动画系统构成](${docs}animation-system)文档,以帮助你更好的了解动画系统的运行逻辑 + +你可以自己创建一个 [AnimationClip](${api}core/AnimationClip)  并通过 [addCurveBinding](${api}core/AnimationClip#addCurveBinding) 为它绑定 [AnimationCurve](${api}core/AnimationCurve)。 ```typescript //custom rotate clip -const rotateClip = new AnimationClip('rotate'); -const rotateState = animator.animatorController.layers[0].stateMachine.addState('rotate'); +const rotateClip = new AnimationClip("rotate"); +const rotateState = + animator.animatorController.layers[0].stateMachine.addState("rotate"); rotateState.clip = rotateClip; const rotateCurve = new AnimationVector3Curve(); const key1 = new Keyframe(); key1.time = 0; -key1.value = new Vector3(0,0,0); +key1.value = new Vector3(0, 0, 0); const key2 = new Keyframe(); key2.time = 10; -key2.value = new Vector3(0,360,0); +key2.value = new Vector3(0, 360, 0); rotateCurve.addKey(key1); rotateCurve.addKey(key2); -rotateClip.addCurveBinding('', Transform, "rotation", rotateCurve); +rotateClip.addCurveBinding("", Transform, "rotation", rotateCurve); //custom color clip -const colorClip = new AnimationClip('color'); -const colorState = animator.animatorController.layers[0].stateMachine.addState('color'); +const colorClip = new AnimationClip("color"); +const colorState = + animator.animatorController.layers[0].stateMachine.addState("color"); colorState.clip = colorClip; const colorCurve = new AnimationFloatCurve(); @@ -170,18 +188,16 @@ key2.time = 10; key2.value = 1; colorCurve.addKey(key1); colorCurve.addKey(key2); -colorClip.addCurveBinding('/light', DirectLight, "color.r", colorCurve); +colorClip.addCurveBinding("/light", DirectLight, "color.r", colorCurve); ``` -就像上面的第二个例子,你同样可以为你的子实体 `/light` 绑定 AnimationCurve,同时 `addCurveBinding` 的第三个参数并不局限于组件的属性,它是一个能索引到值的路径。 +你同样可以为你的子实体 `/light` 绑定 AnimationCurve,就像上面的代码示例,同时 `addCurveBinding` 的第三个参数并不局限于组件的属性,它是一个能索引到值的路径。 ### 动画事件 - - -你可以使用 [AnimationEvent](${api}core/AnimationEvent) 来为AnimationClip添加事件,动画事件将在指定时间调用你在同一实体上绑定组件的指定回调函数。 +你可以使用 [AnimationEvent](${api}core/AnimationEvent)  来为 AnimationClip 添加事件,动画事件将在指定时间调用你在同一实体上绑定组件的指定回调函数。 ```typescript const event = new AnimationEvent(); @@ -190,3 +206,4 @@ event.time = 0.5; clip.addEvent(event); ``` + diff --git a/docs/animation-overview.zh-CN.md b/docs/animation-overview.zh-CN.md new file mode 100644 index 000000000..7668d2054 --- /dev/null +++ b/docs/animation-overview.zh-CN.md @@ -0,0 +1,42 @@ +--- +order: 0 +title: 动画系统概述 +type: 动画 +label: Animation +--- + +## 概览 + +Galacean 的动画系统具有以下功能: + +- 解析 GLTF/FBX 模型中的动画并转为 Galacean 中的 AnimationClip 对象 +- 为 Galacean 的所有组件及其属性添加动画 +- 设置动画的开始/结束时间以裁剪动画 +- 设置动画间的过渡,将多个动画叠加 +- 将一个模型的动画应用到另一个模型上 +- 添加动画事件及动画生命周期的脚本 + +## 动画工作流程 + +使用编辑器创建互动项目的整体流程: + +```mermaid +flowchart LR + 添加动画片段 --> 创建动画控制器并导入动画片段 --> 添加动画控制组件播放动画 +``` + +### 1. 添加动画片段 + +Galacean 的动画系统基于动画片段的概念,动画片段包含某些对象应如何随时间改变其位置、旋转或其他属性的相关信息。每个动画片段可视为单个线性录制。 + +你可以在编辑器中创建动画片段,详见[制作动画片段](${docs}animation-clip),也可以导入用第三方工具(例如 Autodesk® 3ds Max®, Autodesk® Maya®, Blender)创建的带动画的模型,详见[美术制作动画片段](${docs}animation-clip-for-artist),或者来自动作捕捉工作室或其他来源。 + +### 2. 创建动画控制器并导入动画片段 + +动画控制器是一个类似于流程图的结构化系统,它在动画系统中充当状态机,负责跟踪当前应该播放哪个片段以及动画应该何时改变或混合在一起。 + +你可以在这篇[动画控制器](${docs}animation-animatorController)中了解如何使用。 + +### 3. 添加动画控制组件 + +编辑好动画控制器后,我们需要在实体上添加[动画控制组件](${docs}animation-animator)并绑定动画控制器资产来播放动画。 diff --git a/docs/animation-sprite-sheet.zh-CN.md b/docs/animation-sprite-sheet.zh-CN.md index 3f57e997e..eb8e7f719 100644 --- a/docs/animation-sprite-sheet.zh-CN.md +++ b/docs/animation-sprite-sheet.zh-CN.md @@ -1,36 +1,30 @@ --- -order: 5 +order: 4 title: 帧动画 type: 动画 label: Animation --- -编辑器支持引用类型的动画曲线,你可以添加类型为资产的关键帧比如(精灵)下图为制作精灵动画的流程: +Galacean 支持引用类型的动画曲线,你可以添加类型为资产的关键帧比如(精灵)下图为制作精灵动画的流程: 1. 给节点添加 `SpriteRenderer` 组件 -image-1 - +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*PxdFQKal1JEAAAAAAAAAAAAADsJ_AQ/original) 2. 在资产面板中创建 `AnimationClip` -image-2 - -3. 在 `AnimationClip` 编辑器中添加 `sprite` 曲线 - -image-3 - -4. 编辑器中点到对应的帧数,在 `SpriteRenderer` 中添加 `Sprite` (sprite 上传相关详见[精灵](${docs}graphics-sprite))即可自动添加关键帧 +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*t1KMQb0s8V8AAAAAAAAAAAAADsJ_AQ/original) -image-4 +3. 在 `AnimationClip` 编辑器中添加 `sprite` 属性 +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*yFnYT5-NDFEAAAAAAAAAAAAADsJ_AQ/original) -完整流程如下: +4. 开启录制模式,编辑器中点到对应的帧数,在 `SpriteRenderer` 中添加 `Sprite` (sprite 上传相关详见[精灵](${docs}graphics-sprite))即可自动添加关键帧 -![spriteAnimation](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*Yo2CQLHR1OkAAAAAAAAAAAAADsJ_AQ/original) +![Alt text](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*wN9sSYfs2eAAAAAAAAAAAAAADsJ_AQ/original) -### 脚本实现 +### 脚本实现 -引擎在1.1版本支持引用类型的动画曲线([AnimationRefCurve](${api}core/AnimationRefCurve)),关键帧的值可以是资产如(精灵,材质),你可以通过创建引用类型的动画曲线实现比如帧动画的能力: +引擎在 1.1 版本支持引用类型的动画曲线([AnimationRefCurve](${api}core/AnimationRefCurve)),关键帧的值可以是资产如(精灵,材质),你可以通过创建引用类型的动画曲线实现比如帧动画的能力: - \ No newline at end of file + diff --git a/docs/animation-state-machine.md b/docs/animation-state-machine.md deleted file mode 100644 index 87a994ed5..000000000 --- a/docs/animation-state-machine.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -order: 4 -title: 动画状态机 -type: 动画 -label: Animation ---- - -### 动画过渡 - -将两个想要过渡的 `AnimatorState` 连接即可实现动画过渡的效果, 点击两个动画间的连线,可以修改动画过渡的参数调整效果 - -![animationcrossfade](https://gw.alipayobjects.com/zos/OasisHub/cd8fa035-0c1c-493e-a0c7-54d301f96156/1667458692286-29d9f543-9b98-4911-8fa7-ac38b61b1668.gif) - -#### 参数说明 - -| 属性 | 功能说明 | -| :------- | :---------------------------------------------------------| -| duration | 过渡时长,时间为相对目标状态的归一化时间, 默认值为 1.0 | -| offset | 目标状态向前的偏移时间,时间为相对目标状态的归一化时间, 默认值为 0 | -| exitTime | 起始状态过渡开始时间,时间为相对起始状态的归一化时间, 默认值为 0.3 | - -#### 脚本使用 - -你可以通过为 `AnimatorState` 添加 `AnimatorTransition` 实现动画状态间的过渡。 - -```typescript -const walkState = animatorStateMachine.addState('walk'); -walkState.clip = walkClip; -const runState = animatorStateMachine.addState('run'); -runState.clip = runClip; -const transition = new AnimatorStateTransition(); -transition.duration = 1; -transition.offset = 0; -transition.exitTime = 0.5; -transition.destinationState = runState; -walkState.addTransition(transition); -animator.play("walk"); -``` -通过这样的方式你之后每次在该动画状态机所在的层播放 `walk` 动画时都会在播放一半时开始过渡到 `run` 动画。 - -### 动画叠加 - -Galacean引擎支持多层的动画叠加。动画叠加是通过 `AnimatorControllerLayer` 间的混合达到的效果。第一层是基础动画层,修改它的权重及混合模式将不会生效。 - -双击 `AnimatorController` 资源文件编辑动画,添加 Layer,将混合的动作也连接`entry` - -![animationadditive](https://gw.alipayobjects.com/zos/OasisHub/7548a66b-a72f-4cad-9b27-c9f1a2824aff/1667459461151-4568a32a-07db-427b-922e-3bc6f844097b.gif) - -有的时候你想要得到一个固定的姿势,需要裁减设计师给到的动画切片,可以向上图一样修改 `AnimatorState` 的`StartTime` 及 `EndTime`,点击 `AnimatorState` 即可对其进行编辑: - -![1](https://gw.alipayobjects.com/zos/OasisHub/cc0db4c9-95f9-48d7-a3ac-48d69e94a31d/1.jpg) - -| 属性 | 功能说明 | -| :------- | :------------------------------------------------------------------- | -| Name | 修改 `AnimatorState` 的名字,名字在所在的层要是**唯一**的。 | -| AnimationClip | 用于绑定 `AnimationClip` 资产,`AnimationClip` 存储了模型的动画数据。 | -| WrapMode | `AnimatorState` 是循环播放还是播放一次,默认为 `Once` 即播放一次。 | -| Speed | `AnimatorState` 的播放速度,默认值为 1.0 ,值越大动画速度越快 | -| StartTime | `AnimatorState` 从 `AnimationClip` 的哪个时间开始播放,时间为相对 `AnimationClip` 时长的归一化时间。默认值为 0 ,即从头开始播放。 例如:值为 1.0 ,则是 `AnimationClip` 的最后一帧状态。 | -| EndTime | `AnimatorState` 播放到 `AnimationClip` 的哪个时间结束播放,时间为相对 `AnimationClip` 时长的归一化时间。默认值为 1.0 ,即播放到最后。 | - -你也可以通过修改 `Layer` 的 `Weight` 参数来调整 `Layer` 在混合中的权重,通过修改 `Blending` 来修改混合模式。 - -![animationadditive2](https://gw.alipayobjects.com/zos/OasisHub/acd80bdf-7c8d-41ac-8a2f-fe75cc6d2da4/1667459778293-be31b02b-7f6c-4c27-becc-2c0c8e80b538.gif) - -| 属性 | 功能说明 | -| :------- | :------------------------------------------------------------------------- | -| Name | 该层的名字。 | -| Weight | 该层的混合权重,默认值为 1.0 。 | -| Blending | 该层的混合模式,`Additive` 为叠加模式, `Override` 为覆盖模式,默认值为 `Override` | - - -#### 脚本使用 - -将想要叠加的动画状态添加到其他层并将它的混合模式设置为 `AnimatorLayerBlendingMode.Additive` 即可实现动画叠加效果, - - - -### 默认播放 - -将 AnimatorState 连接到`entry`上你导出的项目运行时就会自动播放其上的动画,而不需再调用 `animator.play`。同时你也会看到编辑器的模型也开始播放动画了。 -![2](https://gw.alipayobjects.com/zos/OasisHub/de60a906-0d3c-4578-8d50-aa2ce050e560/2.jpg) - -#### 脚本使用 - -你可以通过设置AnimatorStateMachine的[defaultState](${api}core/AnimatorStateMachine#defaultState) 来设置所在层的默认播放动画,这样当Animator `enabled=true` 时你不需要调用 `play` 方法即可默认播放。 - -```typescript -const layers = animator.animatorController.layers; -layers[0].stateMachine.defaultState = animator.findAnimatorState('walk'); -layers[1].stateMachine.defaultState = animator.findAnimatorState('sad_pose'); -layers[1].blendingMode = AnimatorLayerBlendingMode.Additive; -``` - -### 获取当前在播放的动画状态 - -你可以使用 [getCurrentAnimatorState](${api}core/Animator#getCurrentAnimatorState) 方法来获取当前正在播放的AnimatorState。参数为动画状态所在层的序号`layerIndex`, 详见[API文档](${api}core/Animator#getCurrentAnimatorState)。获取之后可以设置动画状态的属性,比如将默认的循环播放改为一次。 - -```typescript -const currentState = animator.getCurrentAnimatorState(0); -// 播放一次 -currentState.wrapMode = WrapMode.Once; -// 循环播放 -currentState.wrapMode = WrapMode.Loop; -``` - -### 获取动画状态 - -你可以使用 [findAnimatorState](${api}core/Animator#findAnimatorState) 方法来获取指定名称的AnimatorState。详见[API文档](${api}core/Animator#getCurrentAnimatorState)。获取之后可以设置动画状态的属性,比如将默认的循环播放改为一次。 - -```typescript -const state = animator.findAnimatorState('xxx'); -// 播放一次 -state.wrapMode = WrapMode.Once; -// 循环播放 -state.wrapMode = WrapMode.Loop; -``` - -### 状态机脚本 - - - -状态机脚本为用户提供了动画状态的生命周期钩子函数来编写自己的游戏逻辑代码。用户可以通过继承 [StateMachineScript](${api}core/StateMachineScript) 类来使用状态机脚本。 - -状态机脚本提供了三个动画状态周期: - -- `onStateEnter`:动画状态开始播放时回调。 -- `onStateUpdate`:动画状态更新时回调。 -- `onStateExit`:动画状态结束时回调。 - -```typescript -class theScript extends StateMachineScript { - // onStateEnter is called when a transition starts and the state machine starts to evaluate this state - onStateEnter(animator: Animator, stateInfo: any, layerIndex: number) { - console.log('onStateEnter', animator, stateInfo, layerIndex); - } - - // onStateUpdate is called on each Update frame between onStateEnter and onStateExit callbacks - onStateUpdate(animator: Animator, stateInfo: any, layerIndex: number) { - console.log('onStateUpdate', animator, stateInfo, layerIndex); - } - - // onStateExit is called when a transition ends and the state machine finishes evaluating this state - onStateExit(animator: Animator, stateInfo: any, layerIndex: number) { - console.log('onStateExit', animator, stateInfo, layerIndex); - } -} - -animatorState.addStateMachineScript(theScript) -``` - -如果你的脚本不用复用的话你也可以这么写: - -```typescript -state.addStateMachineScript( - class extends StateMachineScript { - onStateEnter( - animator: Animator, - animatorState: AnimatorState, - layerIndex: number - ): void { - console.log("onStateEnter: ", animatorState); - } - } -); -``` \ No newline at end of file diff --git a/docs/animation-system.zh-CN.md b/docs/animation-system.zh-CN.md index 0492361ea..f8ab0af66 100644 --- a/docs/animation-system.zh-CN.md +++ b/docs/animation-system.zh-CN.md @@ -1,6 +1,6 @@ --- -order: 0 -title: 动画总览 +order: 5 +title: 动画系统构成 type: 动画 label: Animation --- @@ -27,21 +27,20 @@ flowchart TD AnimationClip --> AnimationEvent:::white AnimationCurve --> Keyframe AnimationCurve --> Interpolation:::white - ``` - +``` -| 概念 | 解释 | -| ------------------------------------------------------------ | ------------------------------------------------------------ | -| [Animator](${api}core/Animator) | 动画控制器组件,用于控制动画的播放。Animator 组件读取 AnimatorController 作为动画数据。通过 AnimatorControllerParameter 设置该 Animator 中的变量。 | -| [AnimatorController](${api}core/AnimatorController) | 用于存储 Animator 组件的动画数据。一个 AnimatorController 包含多个 AnimatorControllerLayer,用于分层播放或动画叠加。 | -| AnimatorControllerParameter(开发中) | 动画控制器中使用的变量,使用户可以通过在脚本中改变变量以控制动画状态的切换。 | -| [AnimatorControllerLayer](${api}core/AnimatorControllerLayer) | 存储该层的动画状态机数据,混合模式以及混合的权重。多个 AnimatorControllerLayer 同时播放时可以通过设置 `blendingMode = AnimatorLayerBlendingMode.Additive` 实现动画叠加的效果。 | -| [AnimatorStateMachine](${api}core/AnimatorStateMachine) | 每个 AnimatorControllerLayer 中有一个 AnimatorStateMachine,用于控制动画状态的播放及状态间的切换及过渡。 | -| [BlendingMode](${api}core/AnimatorControllerLayer#blendingMode) | 动画层的混合模式,默认为 `AnimatorLayerBlendingMode.Override` 既覆盖模式,可以通过将下面的层设置为 `AnimatorLayerBlendingMode.Additive` 实现动画叠加的效果。 | -| [AnimatorState](${api}core/AnimatorState) | AnimatorState 是 AnimatorStateMachine 的基本构成。可以控制 AnimationClip 的速度,是否循环,开始结束时间。每个 AnimatorState 需绑定一个 AnimationClip,当处于该状态时,则会播放该AnimationClip。 | -| [AnimatorTransition](${api}core/AnimatorTransition) | AnimatorTransition定义了状态机何时以及如何从一个状态过渡到另一个状态。通过它可以设置两个动画状态的过渡开始时间 `exitTime`,目标状态的开始时间 `offset` 及过渡时长 `duration`。 | -| [AnimationClip](${api}core/AnimationClip) | 动画片段,存储设计师制作的基于关键帧的动画数据。一个 AnimationClip 一般对应一个模型的特定动作,每个 AnimationClip 包含多个 AnimationCurve。 | -| [AnimationCurve](${api}core/AnimationCurve) | 一个模型拥有多个骨骼,模型动画中每个骨骼实体的指定属性的动画关键帧数据存储于 AnimationCurve 中。一个 AnimationCurve 中包含多个 Keyframe 既关键帧数据。 | -| [AnimationEvent](${api}core/AnimationEvent) | AnimationEvent 可以让你在指定时间调用其同一实体绑定的脚本的回调函数. | -| [Keyframe](${api}core/KeyFrame) | 存储动画关键帧数据,既指定时间实体的属性的值应是多少。 | -| [Interpolation](${api}core/AnimationCurve#interpolation) | 动画曲线中关键帧的插值方式。既当时间在两个关键帧间时,属性的值该如何计算。 | +| 概念 | 解释 | +| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [Animator](${api}core/Animator) | 动画控制器组件,用于控制动画的播放。Animator 组件读取 AnimatorController 作为动画数据。通过 AnimatorControllerParameter 设置该 Animator 中的变量。 | +| [AnimatorController](${api}core/AnimatorController) | 用于存储 Animator 组件的动画数据。一个 AnimatorController 包含多个 AnimatorControllerLayer,用于分层播放或动画叠加。 | +| AnimatorControllerParameter(开发中) | 动画控制器中使用的变量,使用户可以通过在脚本中改变变量以控制动画状态的切换。 | +| [AnimatorControllerLayer](${api}core/AnimatorControllerLayer) | 存储该层的动画状态机数据,混合模式以及混合的权重。多个 AnimatorControllerLayer 同时播放时可以通过设置 `blendingMode = AnimatorLayerBlendingMode.Additive` 实现动画叠加的效果。 | +| [AnimatorStateMachine](${api}core/AnimatorStateMachine) | 每个 AnimatorControllerLayer 中有一个 AnimatorStateMachine,用于控制动画状态的播放及状态间的切换及过渡。 | +| [BlendingMode](${api}core/AnimatorControllerLayer#blendingMode) | 动画层的混合模式,默认为 `AnimatorLayerBlendingMode.Override` 既覆盖模式,可以通过将下面的层设置为 `AnimatorLayerBlendingMode.Additive` 实现动画叠加的效果。 | +| [AnimatorState](${api}core/AnimatorState) | AnimatorState 是 AnimatorStateMachine 的基本构成。可以控制 AnimationClip 的速度,是否循环,开始结束时间。每个 AnimatorState 需绑定一个 AnimationClip,当处于该状态时,则会播放该 AnimationClip。 | +| [AnimatorTransition](${api}core/AnimatorTransition) | AnimatorTransition 定义了状态机何时以及如何从一个状态过渡到另一个状态。通过它可以设置两个动画状态的过渡开始时间 `exitTime`,目标状态的开始时间 `offset` 及过渡时长 `duration`。 | +| [AnimationClip](${api}core/AnimationClip) | 动画片段,存储设计师制作的基于关键帧的动画数据。一个 AnimationClip 一般对应一个模型的特定动作,每个 AnimationClip 包含多个 AnimationCurve。 | +| [AnimationCurve](${api}core/AnimationCurve) | 一个模型拥有多个骨骼,模型动画中每个骨骼实体的指定属性的动画关键帧数据存储于 AnimationCurve 中。一个 AnimationCurve 中包含多个 Keyframe 既关键帧数据。 | +| [AnimationEvent](${api}core/AnimationEvent) | AnimationEvent 可以让你在指定时间调用其同一实体绑定的脚本的回调函数. | +| [Keyframe](${api}core/KeyFrame) | 存储动画关键帧数据,既指定时间实体的属性的值应是多少。 | +| [Interpolation](${api}core/AnimationCurve#interpolation) | 动画曲线中关键帧的插值方式。既当时间在两个关键帧间时,属性的值该如何计算。 | diff --git a/docs/core-component.zh-CN.md b/docs/core-component.zh-CN.md index febf61256..1a997e2ef 100644 --- a/docs/core-component.zh-CN.md +++ b/docs/core-component.zh-CN.md @@ -26,7 +26,15 @@ label: Core ## 编辑器使用 -从层级面板或场景中选择一个实体后,检查器将显示出当前选中节点所可以调整的属性。在此情况下,你可以点击 `Add Component` 按钮来为当前实体添加新的组件。 +从层级面板或场景中选择一个实体后,检查器将显示出当前选中节点挂载的所有组件,组件名显示在左上角 +![Name](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*tZcpRrrYQcMAAAAAAAAAAAAADsJ_AQ/original) +你可以在检查器中控制它是否 enabled +![Enable](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*QRG8TZ1IorQAAAAAAAAAAAAADsJ_AQ/original) +如果不需要它也可以将它删除 +![Delete](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*uqFGQIHyLAwAAAAAAAAAAAAADsJ_AQ/original) +或者编辑它的各种属性 +![Edit](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*IFnGRYHdi7gAAAAAAAAAAAAADsJ_AQ/original) +如果是个空节点,你可以点击 `Add Component` 按钮来为当前实体添加新的组件。 image-20230926112713126 @@ -79,4 +87,4 @@ const entity = directLight.entity; ```typescript directLight.enabled = false; -``` \ No newline at end of file +``` diff --git a/docs/core-entity.zh-CN.md b/docs/core-entity.zh-CN.md index 37f36c2bb..c25c6694e 100644 --- a/docs/core-entity.zh-CN.md +++ b/docs/core-entity.zh-CN.md @@ -15,6 +15,17 @@ label: Core 要新增节点,你可以点击节点面板上的添加按钮,或右键某个节点后选择添加子节点。添加完成后,你可以在检查器面板中对新节点的属性进行编辑。如果使用新增节点按钮, 你还可以快速创建立方体/球体等基本模型 +### 编辑节点 + +点击节点,你就可以对它进行编辑,在右侧的检查器面板中你可以编辑它的名字 +![Name](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*qBiVT6YtvkQAAAAAAAAAAAAADsJ_AQ/original) +是否激活 +![IsActive](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*1l5_QqTgZYUAAAAAAAAAAAAADsJ_AQ/original) +Transform +![Transform](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*3JO6S7BdgMsAAAAAAAAAAAAADsJ_AQ/original) +以及为它增删组件 +![AddComponent](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*iZKVRrznLOAAAAAAAAAAAAAADsJ_AQ/original) + ### 删除节点 选中一个节点后,可以点击节点面板上的删除按钮或通过右键菜单中的删除选项来删除节点。删除节点会删除节点及其所有的子节点。所以在删除节点时,你需要注意所删除的节点是否会影响场景中其他节点。 @@ -101,4 +112,4 @@ newEntity.findByPath("parent/child/grandson"); ```typescript newEntity.isActive = false; -``` \ No newline at end of file +``` diff --git a/docs/interface-intro.zh-CN.md b/docs/interface-intro.zh-CN.md index 57a650936..54e5026fb 100644 --- a/docs/interface-intro.zh-CN.md +++ b/docs/interface-intro.zh-CN.md @@ -29,6 +29,8 @@ label: Basics/Interface | 5 | [主编辑区](${docs}interface-viewport) | 位于编辑器中间,是编辑器的主要操作区域,可以通过鼠标和键盘来编辑场景 | | 6 | 工具栏 | 位于编辑器顶部,这里提供了一些快速的操作如切换 Gizmo 的模式、切换场景视角,相机配置等 | | 7 | 相机预览区 | 位于主编辑区域的左下角,在这里可以以当前选中的相机为视角来预览场景 | +| 8 | s| 双击AnimationClip资产或在面板区添加 ![AnimationClip](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*SIr_Rp4n8X4AAAAAAAAAAAAADsJ_AQ/original)在这里你可以对指定的AnimationClip资产进行编辑,详见[动画片段编辑](${docs}animation-clip) +| 9 | [动画控制器编辑器](${docs}animation-animator) | 双击AnimatorController资产或在面板区添加![AnimatorController](https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*M-qVRII7SZUAAAAAAAAAAAAADsJ_AQ/original)在这里你可以对指定的AnimationClip资产进行编辑,详见[动画控制器编辑](${docs}animation-animator) 对于各个面板详细的介绍可以点击上方链接查看。