游戏开发图形学3D渲染【免费下载链接】openmwOpenMW is an open-source open-world RPG game engine that supports playing Morrowind. Main repo and issue tracker can be found here: https://gitlab.com/OpenMW/openmw/项目地址https://gitcode.com/gh_mirrors/op/openmw点击查看免费下载openmw.animation是 OpenMW 面向本地脚本context local提供的角色动画控制包支持查询与操纵 NPC、玩家的骨骼动画状态。本篇指南以该包的官方 API 文档files/lua_api/openmw/animation.lua为骨架结合其 C 绑定实现apps/openmw/mwlua/animationbindings.cpp讲解全部枚举、函数与参数读完即可编写可运行的动画控制脚本并理解其与引擎动画队列、VFX 系统的交互原理。包定位与使用前提openmw.animation只应被本地脚本local script加载其所有函数以GameObjectactor为第一个参数其中标注 Can only be used on self 的函数只能作用于当前本地脚本所属的对象SelfObject。这与 OpenMW Lua API 的上下文模型一致本地脚本才有资格操纵自己的动画与特效。local anim require(openmw.animation)官方文档同时给出一个重要提示对于playBlended这类方法应优先使用 AnimationController 接口对应interface_animation包来触发相应的处理器handler而不是直接调用本包。直接调用受引擎硬编码的角色控制器约束它可能在任何时刻、出于任何原因修改或取消正在播放的动画因此文档建议自定义动画优先使用playQueued除非确实需要底层混合播放能力。三大枚举PRIORITY、BLEND_MASK 与 BONE_GROUPPRIORITY动画优先级优先级决定同一骨骼上多个动画共存时的裁决次序。数值越大优先级越高各值及其含义常量值说明PRIORITY.Default0默认优先级PRIORITY.WeaponLowerBody1持武器时的下半身动画PRIORITY.SneakIdleLowerBody2潜行待机下半身PRIORITY.SwimIdle3游泳待机PRIORITY.Jump4跳跃PRIORITY.Movement5移动PRIORITY.Hit6受击PRIORITY.Weapon7武器动作PRIORITY.Block8格挡PRIORITY.Knockdown9击倒PRIORITY.Torch10火把PRIORITY.Storm11风暴天气动画PRIORITY.Scripted13脚本动画专用只要有该优先级的动画存在所有非该优先级的动画都会被暂停注意Scripted是 13 而非 12——从源码看MWMechanics::Priority枚举中 12 为Death而Scripted排在最后。Scripted优先级的行为在文档中有明确说明它会让所有低于它的动画暂停是脚本驱动表现如强制演出时的关键手段。BLEND_MASK混合骨骼掩码控制playBlended时动画影响哪些骨骼区域取值可组合位掩码常量值覆盖范围BLEND_MASK.LowerBody1从Bip01 pelvis及以下的全部骨骼BLEND_MASK.Torso2从Bip01 Spine1及以上的全部骨骼不含手臂BLEND_MASK.LeftArm4从Bip01 L Clavicle及向外的手臂骨骼BLEND_MASK.RightArm8从Bip01 R Clavicle及向外的手臂骨骼BLEND_MASK.UpperBody14从Bip01 Spine1及以上包含双臂BLEND_MASK.All15全部骨骼这些掩码值在 animationbindings.cpp 中与MWRender::Animation::BlendMask一一映射且以只读表形式暴露makeStrictReadOnly脚本中不可修改。BONE_GROUP骨骼组枚举用于getActiveGroup查询某骨骼组当前播放的动画常量值覆盖范围BONE_GROUP.LowerBody1Bip01 pelvis及以下BONE_GROUP.Torso2Bip01 Spine1及以上不含手臂BONE_GROUP.LeftArm3Bip01 L Clavicle及向外BONE_GROUP.RightArm4Bip01 R Clavicle及向外注意BONE_GROUP与BLEND_MASK的取值不同前者是 1–4 的顺序编号后者是位掩码二者用途也不同掩码用于指定播放范围骨骼组用于查询活跃动画。查询类函数状态检查与信息获取以下函数只读查询动画状态可作用于任意 actorLObject不要求是 selfhasAnimation(actor)→ boolean检查对象是否拥有动画对象。C 侧实现即world-getAnimation(ptr) ! nullptr见 animationbindings.cpp。getTextKeyTime(actor, key)→ number|nil返回给定文本键text key在动画轨道内的绝对位置若不存在返回nilC 中getTextKeyTime返回负值时转为nullopt。isPlaying(actor, groupName)→ boolean指定动画组是否正在播放。getCurrentTime(actor, groupName)→ number|nil当前播放的绝对时间未播放返回nilC 侧负值映射为nullopt。isLoopingAnimation(actor, groupName)→ boolean判断是否为循环动画由groupName与循环起始/结束键共同决定。getCompletion(actor, groupName)→ number|nil动画完成度0–1组未激活时返回nil。getLoopCount(actor, groupName)→ number|nil剩余循环次数不含当前循环未激活返回nil。getSpeed(actor, groupName)→ number|nil当前播放速度倍率未激活返回nil。C 实现通过getInfo读取注释明确指出getInfo还能返回速度倍率但该值平时不被使用。getActiveGroup(actor, boneGroup)→ string返回指定骨骼组当前活跃的动画组名。传入的boneGroup必须合法0 ≤ 值 BoneGroup::Num_BoneGroups否则抛出Invalid bonegroup运行时错误。hasGroup(actor, groupName)→ booleanactor 的动画对象中是否存在该动画组。hasBone(actor, boneName)→ booleanactor 骨骼中是否存在指定骨骼。C 实现走节点表nodemap而非直接读场景图因此线程安全见 animationbindings.cpp。硬编码循环动画组列表isLoopingAnimation的判断依据之一是硬编码的循环组名单。官方文档列出的组名如下每个均含按武器类型后缀的变体walkforward, walkback, walkleft, walkright, swimwalkforward, swimwalkback, swimwalkleft, swimwalkright, runforward, runback, runleft, runright, swimrunforward, swimrunback, swimrunleft, swimrunright, sneakforward, sneakback, sneakleft, sneakright, turnleft, turnright, swimturnleft, swimturnright, spellturnleft, spellturnright, torch, idle, idle2 ~ idle9, idlesneak, idlestorm, idleswim, jump, inventoryhandtohand, inventoryweapononehand, inventoryweapontwohand, inventoryweapontwowide除上述硬编码名单外动画组中是否存在循环起始/结束键也会影响判定。仅限 self 的操纵函数以下函数在 C 绑定中接受SelfObject即只能用于当前本地脚本对象同时getMutablePtrOrThrow会检查对象RefData的isEnabled()状态禁用状态下的对象会直接抛错见 animationbindings.cppskipAnimationThisFrame(actor)跳过一帧动画等价于 MWScript 的SkipAnim。实现调用mechanics-skipAnimation(ptr)注释说明它只设置一个在更新阶段才消费的标志位因此无需排队。cancel(actor, groupName)取消并从活跃动画列表中移除指定动画组。对应Animation::disable(groupname)。setLoopingEnabled(actor, groupName, enabled)启用/禁用指定动画组的循环默认循环是开启的。setSpeed(actor, groupName, speed)修改播放速度speed1为正常速度。文档特别注明该设置不具粘性只影响当前播放序列结束之前。C 实现为adjustSpeedMult且参数必须是有限浮点数FiniteFloat。clearAnimationQueue(actor, clearScripted)清空当前动画队列中所有动画影响由 MWScript、playQueued和 AI 包播放的动画不影响playBlended播放的动画。参数clearScripted控制是否保留Scripted优先级的动画。addGlow(actor, options)给 actor 附加施法光效spell-casting glow。addVfx/removeVfx/removeAllVfxVFX 特效的添加与移除。队列播放playQueuedplayQueued是 MWScriptLoopGroup的扩展版本以独占方式播放动画直到播放完毕或队列被clearAnimationQueue清空。文档建议用clearAnimationQueue配合startKey选项来模拟LoopGroup的各种播放模式。支持两种调用形式-- 播放死亡动画不等候。等价于 playgroup, death1, 1 anim.clearAnimationQueue(self, false) anim.playQueued(self, death1) -- 指定自定义起始/结束键 anim.clearAnimationQueue(self, false) anim.playQueued(self, spellcast, { startKey self start, stopKey self stop })options表支持以下键默认值取自 C 绑定 animationbindings.cpp键类型默认值说明loopsnumber ≥ 0无限首次播放之后额外循环的次数speednumber ≥ 01播放速度倍率startKeystringstart动画起始文本键stopKeystringstop动画结束文本键forceLoopbooleanfalse即使非循环动画也强制循环C 侧playQueued通过sol::overload支持带/不带 options 两种调用最终都落到mechanics-playAnimationGroupLua(ptr, groupname, numberOfLoops, speed, startKey, stopKey, forceLoop)。未提供loops时使用std::numeric_limitsuint32_t::max()即无限循环。混合播放playBlendedplayBlended直接在底层动画系统播放一个动画组提供骨骼级混合控制选项比playQueued更丰富默认值取自 animationbindings.cpp键类型默认值说明loopsnumber ≥ 00首次播放后额外循环次数priorityPriority或表PRIORITY.Default可传单个优先级作用于所有骨骼组或传{ [BONE_GROUP] Priority }映射表逐组指定blendMask掩码BLEND_MASK.All参与混合的骨骼范围autoDisablebooleantrue播放完毕立即移除动画之后无法再查询其信息speednumber ≥ 01播放速度startKeystringstart起始文本键stopKeystringstop结束文本键startPointnumber 0–10动画起始完成度forceLoopbooleanfalse强制循环优先级参数支持两种形式C 侧getPriorityArgument会先尝试sol::optionalPriority枚举再尝试BoneGroup → Priority映射表表项必须是合法的骨骼组与优先级对且骨骼组越界 0 || Num_BoneGroups会抛错。播放时组名会被转为小写StringUtils::lowerCase并且最终循环标志为forceLoop || animation-isLoopingAnimation(lowerGroup)——即使不传forceLoop硬编码循环组也会照常循环。视觉效果施法光效与 VFXaddGlow施法光效local util require(openmw.util) animation.addGlow(self, { color util.color.rgb(1, 0, 0), duration 1.5 })必需参数coloropenmw.util.Color颜色值duration以秒计的有限时长负值表示永久光效。C 实现通过mLuaManager-addAction将操作延迟到主线程执行addGlowAction最终调用Animation::addSpellCastGlow(color, duration)。addVfx附着式特效addVfx(actor, model, options)在 actor 上播放一个 VFX模型路径通常取自记录如openmw.types.StaticRecord.model或魔法效果记录。也可通过向目标 actor 发送AddVfx事件来触发。options 支持键类型默认值说明loopbooleanfalse为 true 时循环直到被移除boneNamestring特效附着的骨骼名particleTextureOverridestring覆盖粒子贴图vfxIdstring用于removeVfx及去重的 ID默认空串允许重复。建议用与魔法效果 ID 无关的唯一标识避免与引擎交互若设为等于openmw.core.MagicEffectId如core.magic.EFFECT_TYPE.FireDamage引擎会在该魔法效果归零时自动移除特效useAmbientLightbooleantrueMorrowind 中 VFX 默认附带白色环境光false 则不附加autoTransformbooleantrue为 true 时引擎自动计算变换transformopenmw.util.Transform—相对变换autoTransform为 true 时叠加在其上官方文档给出的典型用法从魔法效果记录驱动 VFXlocal mgef core.magic.effects.records[myEffectName] anim.addVfx(self, VFX_Hands, { boneName Bip01 L Hand, particleTextureOverride mgef.particle, loop mgef.continuousVfx, vfxId mgef.id .. _myuniquenamehere, }) -- 之后移除 anim.removeVfx(self, mgef.id .. _myuniquenamehere)向其他 actor 施加特效则通过事件local mgef core.magic.effects.records[myEffectName] target:sendEvent(AddVfx, { model types.Static.record(mgef.hitStatic).model, options { vfxId mgef.id, particleTextureOverride mgef.particle, loop false, transform util.transform.move(100, 0, 0), }, })C 实现animationbindings.cpp会校验transform是否为合法矩阵!transform-valid()时抛错并通过addAction延迟执行Animation::addEffect(model, effectId, loop, boneName, particleTexture, useAmbientLight, autoTransform, transform)。removeVfx与removeAllVfx同理分别映射removeEffect(effectId)与removeEffects()。需要说明的是这些 action 的命名addGlowAction、addVfxAction是绑定内部标签并非脚本可见接口。脚本实践示例一次完整的演出编排综合以上 API一个典型的脚本化过场模式如下local anim require(openmw.animation) local util require(openmw.util) -- 1. 以 Scripted 优先级接管角色让默认动画全部暂停 anim.clearAnimationQueue(self, false) -- 2. 播放队列动画等价于 MWScript 的 playgroup/loopgroup anim.playQueued(self, attack1, { loops 0, speed 1.0 }) -- 3. 查询播放状态 if anim.isPlaying(self, attack1) then local t anim.getCurrentTime(self, attack1) -- 当前绝对时间 local c anim.getCompletion(self, attack1) -- 完成度 0~1 end -- 4. 底层混合动画只影响上半身覆盖在移动动画之上 anim.playBlended(self, cast, { blendMask anim.BLEND_MASK.UpperBody, priority anim.PRIORITY.Scripted, startKey self start, stopKey self stop, }) -- 5. 附加视觉表现 anim.addGlow(self, { color util.color.rgb(1, 1, 0), duration 2.0 }) anim.addVfx(self, VFX_Hands, { boneName Bip01 R Hand, loop false })注意使用顺序队列类函数playQueued、clearAnimationQueue与查询类函数可自由组合而playBlended走的是另一条混合播放通道不进入clearAnimationQueue管辖的队列。由于本地脚本上下文限制上述 self 函数只对当前对象生效对 NPC 施加特效请使用AddVfx事件。与引擎的交互边界从源码实现可以提炼几条关键边界禁用对象不可操作所有需要可变对象的函数都会先校验isEnabled()禁用对象一律抛Cant use a disabled object。无动画对象不可操作对没有动画对象的物体调用相关函数会抛Object has no animationanimationbindings.cpp。特效操作是延迟执行的addGlow、addVfx、removeVfx、removeAllVfx均通过addAction排队到引擎更新阶段执行因此它们不保证立即生效也不应在同一帧内同步查询其结果。只读表保护PRIORITY、BLEND_MASK、BONE_GROUP三个枚举表均通过makeStrictReadOnly/makeReadOnly暴露脚本尝试修改会失败。这些实现细节均有对应的绑定源码可查见 apps/openmw/mwlua/animationbindings.cpp。API 的权威参考即文档注释源文件 files/lua_api/openmw/animation.lua官方文档页面由docs/source/reference/lua-scripting/openmw_animation.rst嵌入生成动画相关的接口AnimationController说明见 docs/source/reference/lua-scripting/interface_animation.rst。赞分享游戏开发图形学3D渲染【免费下载链接】openmwOpenMW is an open-source open-world RPG game engine that supports playing Morrowind. Main repo and issue tracker can be found here: https://gitlab.com/OpenMW/openmw/项目地址https://gitcode.com/gh_mirrors/op/openmw点击查看免费下载相关推荐Lark CLI 云文档 Memo/Brief 体裁契约让飞书文档 Agent 写出可决策、可核验的高层简报Lark CLI 云文档 Memo/Brief 体裁契约让飞书文档 Agent 写出可决策、可核验的高层简报 导读 在企业协同场景中「备忘录 / 简报」是最游戏开发图形学3D渲染OpenMW Lua 脚本 AI 指南Escort 护送 AI 包的参数详解与底层实现OpenMW Lua 脚本 AI 指南Escort 护送 AI 包的参数详解与底层实现 本文围绕 OpenMW 官方 Lua 脚本参考文档 Escort AI游戏开发图形学3D渲染OpenMW GamepadControls Lua 接口详解手柄光标与控制器菜单的脚本化控制OpenMW GamepadControls Lua 接口详解手柄光标与控制器菜单的脚本化控制 OpenMW 通过内置 Lua 脚本向玩家侧脚本暴露了 Gam游戏开发图形学3D渲染上一篇CANN AI Core算子开发指南下一篇零成本开发5款免费代码编辑器完整选型指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考