尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

TiXL 时间线 Dope Sheet 深度指南:关键帧在播放时间中的绘制、拖动与跨剪辑捕捉

TiXL 时间线 Dope Sheet 深度指南:关键帧在播放时间中的绘制、拖动与跨剪辑捕捉 TiXL 时间线 Dope Sheet 深度指南关键帧在播放时间中的绘制、拖动与跨剪辑捕捉【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3本指南以 TiXL实时动态图形创作软件时间线中Dope Sheet关键帧表的播放时间playback time坐标体系为核心完整复现从「创建拉伸的[VideoClip]并制作双键淡出」到「跨不同时间映射行的关键帧捕捉」的整套验证流程。读完你将掌握关键帧如何在拉伸/滑动slip剪辑中按实际生效位置绘制如何让拖拽 1:1 跟随鼠标如何让围栏选择、条带点选、选区范围指示器与屏幕上看到的位置严格一致以及该机制对应的底层源码实现TimeClip仿射时间映射与ParamTimeMapping坐标换算。一、为什么关键帧必须绘制在“播放时间”1.1 剪辑会改变参数的时间坐标TiXL 中[TimeClip]、[VideoClip]这类算子的输出带有时间剪辑time clip语义。一个剪辑由两个时间段共同定义见 Core/Animation/TimeClip.csTimeRangeStart / End剪辑放置在时间线上的区间单位恒为小节barsSourceRangeStart / End剪辑内容自身的源时间区间可以是 bars 或秒ClipTimeUnits枚举见同一文件第 14–18 行。二者共同决定了一条仿射affine时间映射。当SourceRange与TimeRange长度不同剪辑即被拉伸stretch或压缩当二者长度相同但起点不同则发生滑动slip。源码中成对提供正反两个方向的换算MapTimelineToSource(double timelineBars)把时间线位置映射进剪辑的源时间即“播放到时间线第 X 小节时内容内部读到哪一帧”MapSourceToTimeline(double sourceBars)反向把源时间映射回时间线位置“这条源时间上的关键帧实际作用于哪个播放位置”。关键帧的曲线数据Curve始终保存在算子的**本地时间local time**里——对剪辑内的参数而言本地时间就是SourceRange所代表的源时间。因此同一枚关键帧在源时间中的U值与它在时间线标尺上的屏幕 X 位置是两个不同的数前者是数据后者必须经由映射换算。1.2 ParamTimeMapping一次换算两枚数字负责这条换算的是时间线画布中定义的ParamTimeMapping结构体见 Editor/Gui/Windows/TimeLine/TimeLineCanvas.cspublic static ParamTimeMapping For(Instance instance) { var globalAtZero Animator.GetGlobalAnimationTime(instance, 0); var rate Animator.GetGlobalAnimationTime(instance, 1) - globalAtZero; return new ParamTimeMapping(globalAtZero, rate); } public bool IsIdentity GlobalAtLocalZero 0 Rate 1; // 无外层剪辑重映射的常见情形 public double ToGlobal(double localU) GlobalAtLocalZero Rate * localU; public double ToLocal(double globalTime) Math.Abs(Rate) MinRate ? GlobalAtLocalZero : (globalTime - GlobalAtLocalZero) / Rate;它缓存了形如global GlobalAtLocalZero Rate · localU的一次函数GlobalAtLocalZero是“参数本地时间 0 在时间线上对应的小节”Rate是每 1 单位本地时间对应的时间线跨度即该参数所处的剪辑整体拉伸比。该映射由参数实例所在的外层剪辑链组合推导见BuildTimeMapping()的注释clip 拖动会连续改变它因此每一帧/每次使用都重新构建。IsIdentity为 true 时无外层剪辑所有换算退化为恒等这正是文档第 9 步回归测试的前提。当两条参数行处于不同剪辑、甚至一条在剪辑内一条在剪辑外时它们各自持有不同的ParamTimeMapping——这就是 Dope Sheet 中“两条拉伸不同的剪辑可以共存于同一时间线、每行独立换算”的根本原因。二、前置条件与验证环境按文档要求进行下述操作前请确认对应 .tests-manual/timeline-clip-time-display.md 的 prerequisites打开一个启用了自身 Composition Settings的项目合成需要有自己的时间基准设置准备一段时长 5 秒或更长的短视频用于创建[VideoClip]时间线格式设为Bars并开启吸附Snapping。涉及的时间线基础概念标尺、时间光栅、Dope/Curve 模式切换、播放快捷键等可参考 .help/docs/using/Timeline.md。三、Setup一条拉伸剪辑 两键淡出操作步骤按Home将播放头移到时间线起点。把视频文件拖入时间线的剪辑区域、放在第 0 小节处创建出[VideoClip]。选中该剪辑在其右键菜单中打开Edit Clip Times将Clip Start/End设为0/4确认Source Start/End显示相同值即 100% 速度恒等映射。将播放头移到第1小节按住Alt点击 Parameter Window 中的Color输入——Dope Sheet 中会新增一行标注为VideoClip.Color的条带行下称“Color 行”。将播放头移到第2小节把 Color 的 alpha 设为0。拉伸按住Alt将剪辑的结束手柄从第 4 小节拖到第8小节标签显示 50.0%。此时 Edit Clip Times 应显示 Clip0/8、Source0/4。后续所有步骤保持该剪辑处于选中状态使其行持续可见。预期结果第 2 到 4 小节之间会播放一个淡出效果——即内容小节 1 与 2 处的两枚关键帧在 50% 拉伸后实际作用在时间线第 2 与第 4 小节。这一步骤通过剪辑右键菜单的Edit Clip Times时间剪辑编辑器写入TimeRange与SourceRangeTimeRange为0→8、SourceRange为0→4按 TimeClip.cs 中Speed SourceRange.Duration / TimeRange.Duration的计算得到4 / 8 0.5即 50% 速度。注意Alt是文档强调的“重映射拉伸”专用修饰键——普通拖动结束手柄会同步修改 SourceRange保持速度而按住Alt只改TimeRange从而改变映射速率。四、关键帧绘制在播放位置Keys draw at playback positions操作观察VideoClip.Color行与 keyset strip标尺正下方的圆点条带。预期结果两枚关键帧绘制在第2与第4小节——正好位于淡出在听觉/视觉上发生的位置下方条带圆点与行内关键帧具有相同的 X 坐标用./,将播放头移到第2小节时播放头、行内关键帧、条带圆点以及参数窗口的 keyframe 指示器完全一致。源码佐证Dope Sheet 绘制每个关键帧时先经映射把本地时间换算成时间线坐标见 Editor/Gui/Windows/TimeLine/DopeSheetArea.csvar vDefGlobalU (float)_currentParamMapping.ToGlobal(vDef.U); ... var posOnScreen new Vector2( TimeLineCanvas.Current.TransformX(vDefGlobalU) - KeyframeIconWidth * T3Ui.UiScaleFactor / 2 1, layerArea.Min.Y);_currentParamMapping在每行绘制入口由parameter.BuildTimeMapping()构建同文件第 146 行因此每个参数行独立换算。keyframe 指示器、播放头跳转逻辑同样以ToGlobal结果为准同文件第 837 行点击关键帧时Playback.TimeInBars _currentParamMapping.ToGlobal(vDef.U)。keyset strip 的圆点绘制亦使用同一套mapping.ToGlobal见 Editor/Gui/Windows/TimeLine/KeySetStrip.cs 第 395–403 行附近从而保证“行内关键帧 X 条带圆点 X 播放头位置”。五、拉伸剪辑使关键帧在屏幕上同步滑动操作按住Alt把剪辑结束手柄从第 8 小节拖回第4100% 速度再拖回8。预期结果100% 时关键帧绘制在第1与第2小节回到 50% 时又位于第2与第4小节拖动过程中关键帧实时跟随手柄滑动释放时不发生跳变。这正是ParamTimeMapping每帧重建的原因拖动剪辑手柄会连续改变TimeRange即连续改变Rate映射斜率。关键帧的本地U值不变但其ToGlobal结果随Rate连续变化于是屏幕上表现为“粘在手柄上的平滑滑动”。文档注释TimeLineCanvas.cs 第 1053–1055 行明确写道该映射“由外层时间剪辑组合而成每帧/每次使用重建——剪辑拖动会持续改变它”。六、拖动关键帧落在鼠标所指处1:1 跟随操作把第 4 小节处的关键帧拖到第6小节观察它吸附到光栅。播放第 2–7 小节。预期结果关键帧与鼠标1:1 跟随最终落在第 6 小节而不是落在“一半距离”处淡出现在在第 6 小节结束Ctrl Z可将其恢复到第 4 小节。源码实现的关键在拖动命令的分发见 DopeSheetArea.csvar newDragTime TimeLineCanvas.Current.InverseTransformX(ImGui.GetIO().MousePos.X); if (!ImGui.GetIO().KeyShift) if (_snapHandler.TryCheckForSnapping(newDragTime, out var snappedValue, ...)) newDragTime (float)snappedValue; // dt 是播放时间增量UpdateDragCommand 会按每行本地时间缩放它 TimeLineCanvas.Current.UpdateDragCommand(newDragTime - _currentParamMapping.ToGlobal(vDef.U), 0);鼠标在画布上的 X 位置先被反变换为播放时间再与该关键帧当前的全局位置ToGlobal(vDef.U)相减得到播放时间增量 dtUpdateDragCommand将这个 dt 通过各行的映射缩放为本地时间增量见 AnimationCanvas.cs 将命令转发给所有TimeObjectManipulators的分发逻辑。因此在 50% 剪辑内鼠标移动 2 小节关键帧本地U只移动 1 单位但屏幕位置移动了 2 小节——视觉上与鼠标完全同步。Ctrl Z可撤销是因为整个拖动被封装为一条MacroCommand(Move Timeline Items)AnimationCanvas.cs 第 158–169 行、228 行进入撤销栈。七、围栏选择与条带点选所见即所选中操作在行背景上拖出围栏fence恰好框住绘制在第 2 小节的关键帧点击第 4 小节处的条带圆点。预期结果围栏只选中矩形框视觉覆盖到的关键帧且只有那一枚点击圆点后第 4 小节的关键帧被选中其图标变为填充态。围栏选择由AnimationCanvas.HandleFenceUpdate驱动围栏更新/完成时调用UpdateSelectionForArea(selectionFence.BoundsInScreen, selectMode)见 AnimationCanvas.cs随后分发给参与该区域的操控器ParticipatesInFence用于让剪辑泳道在围栏完全落在关键帧行上时退出参与同文件第 138–155 行注释。关键帧命中测试hit-test使用绘制时相同的ToGlobal位置因此“围栏框到哪、就选中哪”与屏幕像素严格一致。条带圆点点击则通过 KeySetStrip.cs 中的映射换算找到对应关键帧簇并填充图标。八、从条带进行簇拖动Cluster drag操作把第 2 小节处的条带圆点拖到第3小节。预期结果该圆点代表的关键帧移动到第 3 小节——移动距离与鼠标完全一致尽管剪辑是 50%播放时淡出从第 3 小节开始Ctrl Z可恢复。条带簇拖动的实现见 KeySetStrip.cs第 121、168 行附近拖动开始时记录抓取偏移_dragGrabOffset mouseU - _draggingMappings[0].ToGlobal(_draggingKeys[0].U)之后每帧把“目标锚点鼠标播放时间 − 偏移”经由各键所属行的ToGlobal/ToLocal往返换算后写回键的本地U。由于映射是每行独立的簇内位于不同映射行的键会被分别换算最终屏幕上所有键都以“恰好鼠标距离”平移——这就是 50% 剪辑内也能 1:1 移动的原因。九、混合行未剪辑算子与剪辑参数并行操作在剪辑外添加任意算子例如[Value]在第 2 与第 4 小节各Alt click一次创建关键帧然后同时选中两个算子使两行都显示。用围栏跨两行选中全部四枚关键帧拖动选区范围指示器SRI的中间条将选区整体右移一小节。预期结果拖动前两行的关键帧都位于第 2 与第 4 小节——跨行对齐拖动后所有关键帧绘制在第 3 与第 5 小节并在那里播放未剪辑行在其曲线中移动了 1 小节剪辑内行在内部只移动了 0.5 小节——但屏幕结果相同选区范围指示器覆盖第 3–5 小节即绘制位置。这是“播放时间坐标系”价值的集中体现[Value]行的ParamTimeMapping是恒等IsIdentity trueVideoClip.Color行的Rate是 0.5。SRI 中间条拖动以播放时间为统一增量下发恒等行本地移动 1 小节剪辑行本地移动 0.5 小节两者ToGlobal后都得到 1 小节的屏幕位移。选区时间范围的合并同样经过逐行mapping.ToGlobal见 DopeSheetArea.cs 第 1175–1201 行GetSelectionTimeRange相关逻辑因此 SRI 标出的是 3–5 的绘制区间。SRI 的整体交互语义开始/结束手柄拉伸、中间条平移、吸附规则见 .help/docs/using/Timeline.md 的 “The selection range indicator” 一节。十、跨不同映射行的吸附Snapping操作连续按Ctrl Z直到两行的关键帧再次位于不同位置。缓慢把一枚[Value]关键帧拖向某枚VideoClip.Color关键帧的绘制位置。预期结果当两枚关键帧在屏幕上视觉对齐的那一刻触发吸附——尽管一枚活在普通时间、另一枚活在 50% 剪辑内。吸附由SnapHandlerForU水平时间吸附处理器见 AnimationCanvas.cs负责。关键点在于吸附目标值通过mapping.ToGlobal(vDefinition.U)采集见 DopeSheetArea.cs 第 1240–1254 行把各键的全局位置作为吸附锚点而拖动中的键同样换算到播放时间参与比较——吸附比较发生在播放时间域内因此“屏幕上对齐”与“吸附触发”天然等价。跨行吸附因此不关心两键各自处于何种映射。十一、回归验证恒等剪辑行为不变操作将剪辑恢复为 Clip0/4、Source0/4100%、恒等快速重复一遍关键帧拖动、围栏选择与条带点选。预期结果一切行为与此功能改动前完全一致。此时TimeRange SourceRangeParamTimeMapping.Rate 1、GlobalAtLocalZero 0IsIdentity成立ToGlobal/ToLocal退化为恒等换算。代码路径中的换算分支仍然执行结果等同直通因此不会产生回归差异——这也是ParamTimeMapping.IsIdentity标记存在的意义让调用方在常见情形下跳过无谓换算TimeLineCanvas.cs 第 1073–1074 行同时保证恒等剪辑下新旧行为逐像素一致。十二、已知的 raw-time 区域非缺陷文档明确声明以下区域仍然显示/操作在原始曲线时间raw curve time属于已知范围而非缺陷使用时应与本文所述播放时间行为区分全屏Curve模式时间线内的内联曲线窗格inline curve pane复制 / 粘贴与Duplicate操作的时间偏移。换言之“播放时间绘制与编辑”已覆盖 Dope Sheet 主视图关键帧行、keyset strip、SRI、拖动、围栏、吸附曲线编辑视图与批量偏移操作尚未接入播放时间换算。十三、机制总结与源码索引一次“播放时间中编辑关键帧”的完整链路数据侧TimeClip以TimeRange/SourceRange定义仿射映射TimeClip.csSpeed属性给出速率换算侧ParamTimeMapping.For(instance)通过Animator.GetGlobalAnimationTime组合外层剪辑链产出GlobalAtLocalZero Rate · localUTimeLineCanvas.cs绘制侧Dope Sheet 行与 keyset strip 均以ToGlobal(vDef.U)定位DopeSheetArea.cs、KeySetStrip.cs交互侧新建键、拖动键、围栏、SRI、吸附全部在播放时间域完成再以ToLocal写回各行的本地时间DopeSheetArea.cs、AnimationCanvas.cs命令侧整体拖动封装为可撤销的MacroCommandAnimationCanvas.cs。时间线整体交互背景keyset strip 的三态圆点、SRI 拉伸/平移、TimeWarp 手柄、剪辑编辑与重映射可进一步阅读 .help/docs/using/Timeline.md其中包含与本主题配套的完整用户文档。执行本指南所述步骤时请以本文各步的“预期结果”为通过标准尤其是第 4、6、9 步中“关键帧绘制在播放位置”“拖拽 1:1 跟随”“跨行拖动结果一致”三项——它们是播放时间坐标系是否生效的直接判据。【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表