Unity动画控制器为何依赖另一个动画控制器:动画状态机Ctrl C拷贝的bug

未解之谜

查看一个动画控制器的依赖,里面竟然有另一个动画控制器。

直接去被依赖项的meta文件拷贝guid,然后去依赖项的YAML里搜索,结果是:

这个guid多次出现在AnimatorStateTransition模块。

看不懂YAML,于是把依赖别人的控制器复制一个,把状态删一个,打印一次依赖。然后删成默认状态机,啥都不依赖了,只依赖那个动画控制器。

然后把控制器的层、参数、状态全删掉,再建一个全新控制器,对比它们的YAML。新建的控制器很干净:

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!91 &9100000
AnimatorController:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: New Animator Controller
  serializedVersion: 5
  m_AnimatorParameters: []
  m_AnimatorLayers: []

被删空的控制器YAML则是:

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1101 &-8043723507950298118
AnimatorStateTransition:
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: 
  m_Conditions:
  - m_ConditionMode: 1
    m_ConditionEvent: running
    m_EventTreshold: 0
  m_DstStateMachine: {fileID: 0}
  m_DstState: {fileID: 5868839050235648224, guid: 06bf078c7d5187148b17f1e7918a9e99,
    type: 2}
  m_Solo: 0
  m_Mute: 0
  m_IsExit: 0
  serializedVersion: 3
  m_TransitionDuration: 0.25
  m_TransitionOffset: 0
  m_ExitTime: 0.9464286
  m_HasExitTime: 0
  m_HasFixedDuration: 1
  m_InterruptionSource: 0
  m_OrderedInterruption: 1
  m_CanTransitionToSelf: 1
--- !u!1101 &-7986762334218738143
AnimatorStateTransition:
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: 
  m_Conditions:
  - m_ConditionMode: 6
    m_ConditionEvent: bodyStatus
    m_EventTreshold: 1
  m_DstStateMachine: {fileID: 0}
  m_DstState: {fileID: -4066937683750499412, guid: 06bf078c7d5187148b17f1e7918a9e99,
    type: 2}
  m_Solo: 0
  m_Mute: 0
  m_IsExit: 0
  serializedVersion: 3
  m_TransitionDuration: 0.25
  m_TransitionOffset: 0
  m_ExitTime: 0.89892185
  m_HasExitTime: 0
  m_HasFixedDuration: 1
  m_InterruptionSource: 0
  m_OrderedInterruption: 1
  m_CanTransitionToSelf: 1
--- !u!1101 &-5474338561685204398
AnimatorStateTransition:
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: 
  m_Conditions:
  - m_ConditionMode: 1
    m_ConditionEvent: Jump
    m_EventTreshold: 0
  m_DstStateMachine: {fileID: 0}
  m_DstState: {fileID: -9165411807507458709, guid: 06bf078c7d5187148b17f1e7918a9e99,
    type: 2}
  m_Solo: 0
  m_Mute: 0
  m_IsExit: 0
  serializedVersion: 3
  m_TransitionDuration: 0.068148136
  m_TransitionOffset: 0
  m_ExitTime: 0.89687735
  m_HasExitTime: 0
  m_HasFixedDuration: 1
  m_InterruptionSource: 0
  m_OrderedInterruption: 1
  m_CanTransitionToSelf: 1
--- !u!1101 &-789983268425872304
AnimatorStateTransition:
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: 
  m_Conditions:
  - m_ConditionMode: 1
    m_ConditionEvent: TakeDrop
    m_EventTreshold: 0
  m_DstStateMachine: {fileID: 0}
  m_DstState: {fileID: 3227172602469648728, guid: 06bf078c7d5187148b17f1e7918a9e99,
    type: 2}
  m_Solo: 0
  m_Mute: 0
  m_IsExit: 0
  serializedVersion: 3
  m_TransitionDuration: 0.25
  m_TransitionOffset: 0
  m_ExitTime: 0.89892185
  m_HasExitTime: 0
  m_HasFixedDuration: 1
  m_InterruptionSource: 0
  m_OrderedInterruption: 1
  m_CanTransitionToSelf: 1
--- !u!1101 &-186031674231208760
AnimatorStateTransition:
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: 
  m_Conditions:
  - m_ConditionMode: 6
    m_ConditionEvent: bodyStatus
    m_EventTreshold: 0
  m_DstStateMachine: {fileID: 0}
  m_DstState: {fileID: -1130861594894586152, guid: 06bf078c7d5187148b17f1e7918a9e99,
    type: 2}
  m_Solo: 0
  m_Mute: 0
  m_IsExit: 0
  serializedVersion: 3
  m_TransitionDuration: 0.25
  m_TransitionOffset: 0
  m_ExitTime: 0.89892185
  m_HasExitTime: 0
  m_HasFixedDuration: 1
  m_InterruptionSource: 0
  m_OrderedInterruption: 1
  m_CanTransitionToSelf: 1
--- !u!91 &9100000
AnimatorController:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: NPC 1
  serializedVersion: 5
  m_AnimatorParameters: []
  m_AnimatorLayers:
  - serializedVersion: 5
    m_Name: Base Layer
    m_StateMachine: {fileID: 50358232126170600}
    m_Mask: {fileID: 0}
    m_Motions: []
    m_Behaviours: []
    m_BlendingMode: 0
    m_SyncedLayerIndex: -1
    m_DefaultWeight: 0
    m_IKPass: 0
    m_SyncedLayerAffectsTiming: 0
    m_Controller: {fileID: 9100000}
--- !u!1107 &50358232126170600
AnimatorStateMachine:
  serializedVersion: 6
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: Base Layer
  m_ChildStates: []
  m_ChildStateMachines: []
  m_AnyStateTransitions: []
  m_EntryTransitions: []
  m_StateMachineTransitions: {}
  m_StateMachineBehaviours: []
  m_AnyStatePosition: {x: 0, y: 30, z: 0}
  m_EntryPosition: {x: 120, y: 120, z: 0}
  m_ExitPosition: {x: 270, y: 50, z: 0}
  m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
  m_DefaultState: {fileID: 0}
--- !u!1101 &1116902853594775685
AnimatorStateTransition:
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: 
  m_Conditions:
  - m_ConditionMode: 3
    m_ConditionEvent: gunStatus
    m_EventTreshold: 0
  m_DstStateMachine: {fileID: 0}
  m_DstState: {fileID: -2272526421185388783, guid: 06bf078c7d5187148b17f1e7918a9e99,
    type: 2}
  m_Solo: 0
  m_Mute: 0
  m_IsExit: 0
  serializedVersion: 3
  m_TransitionDuration: 0.25
  m_TransitionOffset: 0
  m_ExitTime: 0.90909094
  m_HasExitTime: 0
  m_HasFixedDuration: 1
  m_InterruptionSource: 0
  m_OrderedInterruption: 1
  m_CanTransitionToSelf: 1

多了很多AnimatorStateTransition:模块。

我能想到的解释就是这个控制器的一些状态和转换当初是从被依赖的直接复制出来的,在序列化文件里它就是直接复制了这部分文本,但是这样无效,所以保存时序列化另外创建了转换对象,这部分文本也没有删。

这里m_ObjectHideFlags意思应该是这个对象已失效,隐藏,但是不删除。

我看了被依赖控制器YAML的一个转换对象,m_DstState字段根本没有guid,所以可能是拷贝状态时转换对象进了新控制器,添加了对原来目标状态的引用。

AnimatorStateTransition:
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: 
  m_Conditions:
  - m_ConditionMode: 6
    m_ConditionEvent: bodyStatus
    m_EventTreshold: 2
  m_DstStateMachine: {fileID: 0}
  m_DstState: {fileID: -5291231011926439337}
  m_Solo: 0
  m_Mute: 0
  m_IsExit: 0
  serializedVersion: 3
  m_TransitionDuration: 0.25
  m_TransitionOffset: 0
  m_ExitTime: 0.9493243
  m_HasExitTime: 0
  m_HasFixedDuration: 1
  m_InterruptionSource: 0
  m_OrderedInterruption: 1
  m_CanTransitionToSelf: 1
--- !u!114 &-9205196945450993477

继续实验:拷贝状态转换

然后我从一个状态机C拷了一个转换,到新建的状态机,什么也没拷上,然后打印一下新状态机的依赖,已经依赖上状态机C了。

如果徒手修改YAML文件

我删除了AnimatorStateTransition:k开头的一段,编辑器直接解析失败,状态机界面打不开,文件直接废掉。

继续实验:拷贝状态

又新建动画控制器,从控制器M拷贝状态过去,成功粘贴。打印依赖,依赖了状态机M。

被粘贴的控制器的YAML是这样的,控制器M的guid是05a5eccf713b1304b872c5c0c2e3ab0a,出现在AnimatorStateTransition模块,而不是AnimatorState模块。

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1101 &-9221984846367630791
AnimatorStateTransition:
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: 
  m_Conditions:
  - m_ConditionMode: 2
    m_ConditionEvent: dead
    m_EventTreshold: 0
  m_DstStateMachine: {fileID: 0}
  m_DstState: {fileID: -3094905352768277915, guid: 05a5eccf713b1304b872c5c0c2e3ab0a,
    type: 2}
  m_Solo: 0
  m_Mute: 0
  m_IsExit: 0
  serializedVersion: 3
  m_TransitionDuration: 0.25
  m_TransitionOffset: 0
  m_ExitTime: 0.92788464
  m_HasExitTime: 0
  m_HasFixedDuration: 1
  m_InterruptionSource: 0
  m_OrderedInterruption: 1
  m_CanTransitionToSelf: 1
--- !u!1107 &-3121839260780123505
AnimatorStateMachine:
  serializedVersion: 6
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: Base Layer
  m_ChildStates:
  - serializedVersion: 1
    m_State: {fileID: 798723549730859907}
    m_Position: {x: 320, y: 30, z: 0}
  m_ChildStateMachines: []
  m_AnyStateTransitions: []
  m_EntryTransitions: []
  m_StateMachineTransitions: {}
  m_StateMachineBehaviours: []
  m_AnyStatePosition: {x: 50, y: 20, z: 0}
  m_EntryPosition: {x: 50, y: 120, z: 0}
  m_ExitPosition: {x: 800, y: 120, z: 0}
  m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
  m_DefaultState: {fileID: 798723549730859907}
--- !u!91 &9100000
AnimatorController:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: "\u54C8\u54C8\u54C8"
  serializedVersion: 5
  m_AnimatorParameters: []
  m_AnimatorLayers:
  - serializedVersion: 5
    m_Name: Base Layer
    m_StateMachine: {fileID: -3121839260780123505}
    m_Mask: {fileID: 0}
    m_Motions: []
    m_Behaviours: []
    m_BlendingMode: 0
    m_SyncedLayerIndex: -1
    m_DefaultWeight: 0
    m_IKPass: 0
    m_SyncedLayerAffectsTiming: 0
    m_Controller: {fileID: 9100000}
--- !u!1102 &798723549730859907
AnimatorState:
  serializedVersion: 6
  m_ObjectHideFlags: 1
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: Dead
  m_Speed: 2
  m_CycleOffset: 0
  m_Transitions: []
  m_StateMachineBehaviours: []
  m_Position: {x: 50, y: 50, z: 0}
  m_IKOnFeet: 0
  m_WriteDefaultValues: 0
  m_Mirror: 0
  m_SpeedParameterActive: 0
  m_MirrorParameterActive: 0
  m_CycleOffsetParameterActive: 0
  m_TimeParameterActive: 0
  m_Motion: {fileID: 7400000, guid: 78833b2045374d9489cc36e6fa0e9bed, type: 2}
  m_Tag: 
  m_SpeedParameter: 
  m_MirrorParameter: 
  m_CycleOffsetParameter: 
  m_TimeParameter: 

如何拷贝状态机

右键有一个

粘贴后不会依赖源控制器,源控制器的guid也不会出现在YAML。

结论&教训

不要从已有的状态机框选Ctrl C拷贝状态和转换,否则目标控制器会引用源控制器。分AB包会出问题。

在状态机界面右键点拷贝。

Broken text PPtr in file(Assets/Art/Animators/XXX.controller). Local file identifier (-2698132134870541907) doesn't exist!

现在推测这个错误也是框选拷贝状态机导致的,在YAML里被添加了对动画文件的引用,但是这些模块停止随编辑器更新。

更多实验

我又框选Ctrl C几次,也不是一定会隐性依赖。一切以选择依赖结果为准,看见有2个控制器,说明已经被污染了。一旦污染这个控制器也就完蛋了,不管怎么删都无法去除依赖了,手动删YAML又会导致编辑器解析错误。

没有隐性依赖其他控制器,但是隐性依赖很多动画剪辑

还遇到了这个情况,依赖的动画剪辑明显多于实际用到的。

【下垂控制与虚拟同步机】下垂控制与虚拟同步机两种并网型(grid-forming)控制策略的性能研究(Simulink仿真实现)内容概要:本文围绕下垂控制与虚拟同步机(VSG)两种并网型(grid-forming)控制策略,通过Simulink仿真平台对其性能进行了系统性对比研究。重点分析了二者在电网频率调节、电压支撑、动态响应特性、抗扰能力及并网稳定性等方面的差异与优劣,旨在为不同应用场景下的逆变器控制策略选型提供理论依据和技术支撑。研究涵盖了控制原理建模、仿真系统搭建、典型工况测试(如负载突变、电网波动)以及性能指标评估,充分展示了两种技术在现代电力电子并网系统中的应用潜力与局限性。; 适合人群:具备电力电子、自动控制或新能源并网相关基础知识的研究生、科研人员及从事新能源系统仿真的工程技术人员。; 使用场景及目标:①掌握下垂控制与虚拟同步机的核心控制原理及实现方法;②理解两类grid-forming控制策略在动态响应、频率电压支撑方面的性能差异;③为微电网、构网型逆变器等系统的控制方案设计与仿真验证提供参考。; 阅读建议:读者应结合Simulink仿真模型进行实践操作,重点关注控制器参数设计对系统性能的影响,并可通过修改工况条件进一步探究两种策略在复杂电网环境下的适应性。
内容概要:本文提出了一种考虑N-1安全准则的分布鲁棒机会约束低碳经济调度模型,旨在应对电力系统中由可再生能源出力不确定性带来的调度风险。该模型深度融合分布鲁棒优化与机会约束规划方法,在确保系统在单一元件故障(N-1)条件下仍能安全稳定运行的前提下,实现经济性与低碳化双重目标的协同优化。通过Matlab编程实现,结合先进优化算法高效求解复杂调度问题,有效平衡了系统经济性、环保性与安全可靠性之间的矛盾,并提供了完整的代码复现资源,便于科研验证与工程应用。; 适合人群:具备一定电力系统分析基础和Matlab编程能力,从事电力系统优化调度、低碳运行、不确定性建模、鲁棒优化与机会约束等领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于复现和验证顶级EI期刊中关于低碳经济调度的前沿研究成果;②为高比例可再生能源接入的电力系统提供兼具安全性与经济性的调度决策支持;③深入学习和掌握分布鲁棒优化、机会约束建模、N-1安全约束处理及其在电力系统中的集成应用方法; 阅读建议:读者应结合所提供的Matlab代码进行实践操作,重点剖析N-1故障集的构建逻辑、分布鲁棒对不确定性的建模方式、机会约束的转化技巧以及低碳目标与经济调度的耦合机制,建议配合YALMIP等优化建模工具进行调试、结果分析与模型扩展研究。
为什么这份资料值得你下载? 你是不是也卡在过这些地方:摄像头插上去只出花屏、DCMI 收不到数据、DMA 一跑就溢出、逻辑分析仪抓出来的波形看不懂不知道哪根线错了?并口 CMOS 摄像头(OV2640 / OV5640)是嵌入式视觉的标配,但网上教程大多只给一段「能跑就行的代码」,从 SCCB 寄存器到 DCMI 时序、从帧缓存到调波形,没有一个讲透的。这份工程把整条链路一次性讲明白。 你能直接拿到什么 - 可直接研读的 HAL 驱动源码(STM32 风格,全中文注释):SCCB 总线读写(硬件 I2C + 软件模拟双保险)、OV2640 与 OV5640 两套寄存器配置与初始化、DCMI + DMA 抓帧、多缓冲帧缓存环形队列。 - 一份能救命的波形调试笔记:把「无像素时钟 / HSYNC 极性反 / VSYNC 不翻转 / 数据错位 / JPEG 帧头缺失 / DMA 溢出」六大故障,整理成「现象、波形、排查、判定」对照表,配 ASCII 时序图。纯靠猜会浪费一周,对着表十分钟定位。 - 单文件离线教程:HTML 阅读器自带目录、代码复制、章节折叠、搜索、避坑框,断网也能看;有 Markdown 源。 核心 1. 一次讲清两款主流传感器:OV2640(入门 JPEG/RGB565)与 OV5640(500 万像素、含 PLL 配置),共用 SCCB 层,各自寄存器表分开实现。 2. 不只给代码,更给「为什么」:每个配置背后的时序与寄存器含义都解释,改分辨率、改输出格式不再靠蒙。 3. 把最隐蔽的硬件坑前置:DCMI 同步信号极性、DMA 双缓冲、场消隐窗口,这些文档里不写、出事才发现的细节,全在笔记里。 适合谁 嵌入式工程师、在校学生、创客,以及做机器视觉小车、智能门锁、工业检测、AI 相机原型的开发者
内容概要:本文围绕概率最小均方自适应滤波器(LMS)在信号处理中的应用展开,重点介绍了其在噪声消除、系统辨识等场景下的Matlab实现方法。文章系统阐述了自适应滤波的基本原理,涵盖滤波器结构设计、权重迭代更新机制及收敛性分析,并通过具体的Matlab代码实例演示了模型的构建、调试与性能评估过程。同时,结合轴承故障诊断、负荷预测等实际工程问题,深入探讨了该算法在多学科交叉领域的应用潜力与有效性,展现了其在复杂信号环境下的强大适应能力。; 适合人群:具备一定信号处理理论基础和Matlab编程能力的高校研究生、科研人员及工程技术人员,尤其适用于自动化、电气工程、通信工程、机械故障诊断等领域从事信号分析与系统建模的相关从业者。; 使用场景及目标:①掌握概率LMS自适应滤波器的核心算法原理与Matlab实现流程;②应用于实际工程项目中如信号去噪、系统辨识、故障特征提取等任务;③为后续研究VMD、CNN-BiLSTM等先进模型提供信号预处理基础和技术支撑; 阅读建议:此资源以Matlab代码实践为核心,建议读者在学习过程中结合文中提供的完整代码进行仿真实验与参数调优,深入理解算法的动态行为与性能边界,同时可参考文末网盘资料拓展学习相关技术内容,全面提升科研与工程应用能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值