自由学习记录(202)

你一直下意識認為:權重是綁在骨骼的空間位置上的

但這是錯誤的綁定關係,中間有緩衝層,

PCG Shape Grammar

符號/Module

└─ 按生成規則組合

└─ 形成圍欄、牆體、建築、太空站

VS Code 的解譯器不是單純只有一份全域選擇。現在的 Python Environments 系統可以給 Workspace,甚至 Workspace 內不同 Python Project 指派不同環境;這類專案映射會寫入 Workspace 設定,而具體選中的環境還會由擴充套件另行記住。Visual Studio Code

为什么 crack 会是drug?

crack cocaine 加热时会发出轻微的 cracking sound ,即噼啪声,因此叫 crack 。这个 crack 和「裂开、噼啪响」是同一个词源。

而「鞭炮」通常是:

  • firecracker:鞭炮、爆竹
  • set off firecrackers:放鞭炮

不能说 smoke crack 来表示抽鞭炮。

6 月 5 日這次拋售中,美國上市半導體公司的總市值約減少 1.3 萬億美元( 1.2 個馬斯克**)** ;納斯達克綜合指數跌 4.18% ,費城半導體指數跌 10.3%Reuters+1

一家公司可能只有很少一部分股票在今天真正成交,但最後一筆成交價會被用來重新標記全部股份:

2026 年 6 月 4 日 12:40,證券時報引用 CoinGlass 當時的快照是:

  • 爆倉人數:28.36 萬

  • 總爆倉額:17.38 億美元

  • 多單爆倉:超過 15 億美元

因此:15 ÷ 17.38 ≈ 86.3%

所以影片所說的「85%」應該是把多單爆倉金額占比 約略取整。STCN

另一個稍早或稍晚的 CoinGlass 快照則是:

  • 總爆倉額 17.2 億美元

  • 多單 14.1 億美元

  • 空單 3.05 億美元

  • 爆倉者 285,997 人

這一組算出來,多單占比約為:14.1 ÷ 17.2 ≈ 82% Binance

五大 hyperscaler 的全部資本開支為 6020 億美元,其中約 75%,即約 4500 億美元,直接與 AI 基礎設施有關。

Debit Balances in Customers' Securities Margin Accounts

客戶把股票等資產作為抵押,向券商借錢交易後,尚未歸還的帳面餘額。FINRA 要求會員券商在每月底彙報這項數據。FINRA

危險的是,當帳戶淨值跌破維持保證金要求時,券商可以要求補錢,甚至不等你同意便出售資產。一般 FINRA 維持保證金底線是多頭證券市值的 25%,券商自己的 house requirement 還可以提高到 30% 或 40%。FINRA

UE 重新生成的派生資料

Nanite、渲染緩衝、壓縮資料等屬於派生資料,派生資料=引擎維護=自動重生

physics asset,IK Rig Chains, IK Retargeter Pose, Control Rig,Retargeted Animation,不會自動重新生成,和skeletal mesh不是直接的派生資料關係

ease 在动画领域常常专门暗示"速度曲线被柔化",ease in,ease out, ease in-out 緩入/出

實際能否顯示 Buy / Sell,仍取決於帳戶所在地與 Binance 對該地區的資格限制

grep 本身確實有歷史來源:

复制代码
g/re/p
│ │  └─ print:印出
│ └──── regular expression:符合正規表示式
└────── global:在全文範圍執行

InitialChainLength <= UE_KINDA_SMALL_NUMBER

E:\UE_5.7\Engine\Plugins\Animation\IKRig\Source\IKRig\Private\Retargeter\IKRetargetProcessor.cpp 663line

这条 chain 算出来的 InitialChainLength <= UE_KINDA_SMALL_NUMBER,也就是这条链在初始 pose 里长度几乎为 0。常见成因不是"没找到骨头",而是:

  • start bone == end bone
  • 或者这条链上的骨头虽然不同,但初始 pose 里几乎重合
cpp 复制代码
`InitialChainLength` 这条链不是"全局到处传一个 float 参数",而是缓存成 `FResolvedBoneChain` 的成员,后续通过这个对象被间接消费。

**链路总览**
1. 链定义源头是 [IKRigDefinition.h](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Public/Rig/IKRigDefinition.h:134) 的 `FBoneChain`。这里给出 `ChainName / StartBone / EndBone / IKGoalName`,还没有长度概念。
2. `FResolvedBoneChain` 在 [IKRetargetProcessor.h](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Public/Retargeter/IKRetargetProcessor.h:216) 定义,`InitialChainLength` 成员在 [IKRetargetProcessor.h](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Public/Retargeter/IKRetargetProcessor.h:271)。
3. `FIKRetargetProcessor::Initialize()` 调到 `AllBoneChains.Initialize(...)`,见 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:1220)。
4. `FRetargeterBoneChains::Initialize()` 从 source/target `UIKRigDefinition::GetRetargetChains()` 取出每条 `FBoneChain`,逐条构造 `FResolvedBoneChain`,见 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:957) 和 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:940)。
5. `FResolvedBoneChain` 构造函数在 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:538)。这里做三件事:
   - 把 `StartBone/EndBone` 名字解析成 skeleton bone index
   - 沿父链收集 `BoneIndices`
   - 调 `UpdatePoseFromSkeleton()` 和 `CalculateBoneParameters()`
6. `UpdatePoseFromSkeleton()` 在 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:603)。
   - 它从 `InSkeleton.RetargetPoses.GetGlobalRetargetPose()` 取当前 retarget pose 下的全局骨骼变换
   - 按 `BoneIndices` 生成 `RefPoseGlobalTransforms`
   - 再生成 `RefPoseLocalTransforms`
7. `GetGlobalRetargetPose()` 的内容不是裸 ref skeleton,而是 `FRetargetSkeleton::Initialize()` 里先建出来的 resolved retarget pose,见 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:158)。
8. 这个 resolved retarget pose 的生成在 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:24):
   - 从 `GetRefBonePose()` 开始
   - 转成 global pose
   - 应用 pelvis translation offset
   - 应用 retarget pose 里的 bone delta rotation
   - 必要时再做 pose scale
9. `InitialChainLength` 真正赋值在 `CalculateBoneParameters()`,见 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:895)。
   - `InitialChainLength = 0`
   - 遍历 `RefPoseGlobalTransforms[i] - RefPoseGlobalTransforms[i-1]`
   - 把每段距离累加到 `InitialChainLength`
   - 同时生成 `BoneDistances`
10. 同一个函数里,它还立刻拿 `InitialChainLength` 做归一化分母,见 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:917)。
    - `Divisor = InitialChainLength > UE_KINDA_SMALL_NUMBER ? InitialChainLength : UE_KINDA_SMALL_NUMBER`
    - 然后 `Params.Add(BoneDistances[i] / Divisor)`

**到 warning 和下游的传播**
1. warning 触发点在 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:663) 的 `GetWarnings()`:
   - `if (InitialChainLength <= UE_KINDA_SMALL_NUMBER)` 就报 `Chain too short`
2. 这个 warning 是在每条链构造完后立刻调用的,见 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:942)。
3. 注意它**不会**因为短链而让 `IsValid()` 失败。`IsValid()` 只检查 start/end 是否找到、父子关系是否成立、数组长度是否一致,见 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:594)。
4. 所以短链会继续进入后续 op,只是参数化结果已经退化了。
5. 退化方式是:
   - 如果多骨但总长度接近 0,则 `BoneDistances` 基本全 0
   - `Params` 也就基本全 0
   - `GetTransformAtChainParam()` 在这种情况下几乎只能落到链首/链尾的特殊分支,见 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:671)
   - `GetStretchAtParam()` 也会在初始长度过小的时候回退成 `1.0`,见 [IKRetargetProcessor.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:760)
6. 这些下游消费点最直接能在 [FKChainsOp.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/RetargetOps/FKChainsOp.cpp:254)、[FKChainsOp.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/RetargetOps/FKChainsOp.cpp:289)、[FKChainsOp.cpp](/E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/RetargetOps/FKChainsOp.cpp:418) 看到。
   - 它们直接读 `BoneChain->Params`
   - 或调用 `GetTransformAtChainParam()`
   - 或调用 `GetStretchAtParam()`

一句话概括这条"变量传递链":

`UIKRigDefinition::FBoneChain`

-> `FRetargeterBoneChains::Initialize()` 取出链定义

-> `FResolvedBoneChain` 构造并解析骨索引

-> `UpdatePoseFromSkeleton()` 从当前 resolved retarget pose 生成 `RefPoseGlobalTransforms`

-> `CalculateBoneParameters()` 计算并缓存 `InitialChainLength` 与 `Params`

-> `GetWarnings()` 直接用 `InitialChainLength` 报短链

-> FK/其他 retarget op 主要通过 `Params / GetTransformAtChainParam / GetStretchAtParam` 间接消费这个结果

所以 RTG 预览的实际行为是:故意不把 root motion 提取到组件运动里,而是把它留在骨骼 pose / 世界空间里给 retarget 用。视觉上你会觉得"明明关了 root motion,预览却像开着",但源码层面不是改了资产 checkbox,而是预览评估策略不同。

更直接的旁证是批量导出也刻意这么做,注释写得很明白:ensure WYSIWYG with editor by ensuring the same root motion is applied to the pose, not to the component,见 IKRetargetBatchOperation.cpp (line 414)。

IKChainsOp.cpp (line 289)

IK Chain Op: ... no IK goal assigned ... 'LeftArm/RightArm'

出现在 IKChainsOp.cpp (line 289)。条件非常直接:目标 chain 存在,但 TargetBoneChain->IKGoalName == NAME_None。所以只要这条链被 IK Chains Op 扫到、但没绑 IK Goal,就会报并跳过。

RootMotionGeneratorOp.cpp (line 86)

Root Motion Remap Op, missing source/target root bone None.

Root Motion Remap Op, missing target pelvis bone None.

出现在 RootMotionGeneratorOp.cpp (line 86)。检测方式不是"界面里能不能看到骨骼",而是运行时直接做:

  • SourceSkeleton.BoneNames.Find(Settings.SourceRoot.BoneName)
  • TargetSkeleton.BoneNames.Find(Settings.TargetRoot.BoneName)
  • TargetSkeleton.BoneNames.Find(Settings.TargetPelvis.BoneName)

只要返回 INDEX_NONE 就报。你这里日志里打印的是 None,说明更偏向于这几个 FBoneReference.BoneName 本身就是 NAME_None,而不是"名字写了但骨架里找不到"。

关键点有两个:

  1. 这个 op 初始化时会无条件 检查这三个字段,RootMotionGeneratorOp.cpp (line 86)。

    也就是说,即使你当前 RootMotionSource 不是 GenerateFromTargetPelvis,TargetPelvis 为空照样先报。

  2. 你在 RTG 界面里"每个资产都可以看到骨骼",只说明 UI 有 skeleton 可供下拉显示,不等于这 3 个字段已经有值。骨骼列表 UI 只是通过 RootMotionGeneratorOp.cpp (line 37) 的 GetSkeleton(...) 拿 SourceSkeletonAsset/TargetSkeletonAsset 来显示候选项;真正用于校验的是 Settings.SourceRoot/TargetRoot/TargetPelvis.BoneName。

这三个值的自动填充只在 op 被加入栈时做一次,在 RootMotionGeneratorOp.cpp (line 194):

  • SourceRoot = SourcePreviewMesh 的第 0 根骨
  • TargetRoot = TargetPreviewMesh 的第 0 根骨
  • TargetPelvis = Target IKRig->GetPelvis()

我没搜到插件里有后续"持续自动同步"这 3 个字段的代码;更像是只在 OnAddedToStack() 初始化一次,后面改 preview mesh / 改 IKRig pelvis / 复制资产后,字段可能就和你当前界面看到的东西脱节了。

这些 warning 的触发条件我在 `E:\UE_5.7` 里对到了,结论是:

**Warning 条件**

`IK Retargeter bone chain, Root, was unable to be normalized. Chain too short.`

出现在 IKRetargetProcessor.cpp(</E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/IKRetargetProcessor.cpp:663>)。条件就是这条 chain 算出来的 `InitialChainLength <= UE_KINDA_SMALL_NUMBER`,也就是这条链在初始 pose 里长度几乎为 0。常见成因不是"没找到骨头",而是:

  • `start bone == end bone`

  • 或者这条链上的骨头虽然不同,但初始 pose 里几乎重合

`IK Chain Op: ... no IK goal assigned ... 'LeftArm/RightArm'`

出现在 IKChainsOp.cpp(</E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/RetargetOps/IKChainsOp.cpp:289>)。条件非常直接:目标 chain 存在,但 `TargetBoneChain->IKGoalName == NAME_None`。所以只要这条链被 `IK Chains Op` 扫到、但没绑 IK Goal,就会报并跳过。

`Root Motion Remap Op, missing source/target root bone None.`

`Root Motion Remap Op, missing target pelvis bone None.`

出现在 RootMotionGeneratorOp.cpp(</E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/RetargetOps/RootMotionGeneratorOp.cpp:86>)。检测方式不是"界面里能不能看到骨骼",而是运行时直接做:

  • `SourceSkeleton.BoneNames.Find(Settings.SourceRoot.BoneName)`

  • `TargetSkeleton.BoneNames.Find(Settings.TargetRoot.BoneName)`

  • `TargetSkeleton.BoneNames.Find(Settings.TargetPelvis.BoneName)`

只要返回 `INDEX_NONE` 就报。你这里日志里打印的是 `None`,说明更偏向于这几个 `FBoneReference.BoneName` 本身就是 `NAME_None`,而不是"名字写了但骨架里找不到"。

关键点有两个:

  1. 这个 op 初始化时会**无条件**检查这三个字段,RootMotionGeneratorOp.cpp:86-109(</E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/RetargetOps/RootMotionGeneratorOp.cpp:86>)。

也就是说,即使你当前 `RootMotionSource` 不是 `GenerateFromTargetPelvis`,`TargetPelvis` 为空照样先报。

  1. 你在 RTG 界面里"每个资产都可以看到骨骼",只说明 UI 有 skeleton 可供下拉显示,不等于这 3 个字段已经有值。骨骼列表 UI 只是通过 RootMotionGeneratorOp.cpp(</E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/RetargetOps/RootMotionGeneratorOp.cpp:37>) 的 `GetSkeleton(...)` 拿 `SourceSkeletonAsset/TargetSkeletonAsset` 来显示候选项;真正用于校验的是 `Settings.SourceRoot/TargetRoot/TargetPelvis.BoneName`。

这三个值的自动填充只在 op 被加入栈时做一次,在 RootMotionGeneratorOp.cpp(</E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRig/Private/Retargeter/RetargetOps/RootMotionGeneratorOp.cpp:194>):

  • `SourceRoot = SourcePreviewMesh` 的第 0 根骨

  • `TargetRoot = TargetPreviewMesh` 的第 0 根骨

  • `TargetPelvis = Target IKRig->GetPelvis()`

我没搜到插件里有后续"持续自动同步"这 3 个字段的代码;更像是只在 `OnAddedToStack()` 初始化一次,后面改 preview mesh / 改 IKRig pelvis / 复制资产后,字段可能就和你当前界面看到的东西脱节了。

**Root Motion 预览**

RTG 预览里确实有"把 root motion 留在 pose 里"的专门代码,但不是把你的 `AnimationSequence` 资产勾选自动改成开启。

链路是:

  • RTG 预览场景强制 source/target 组件 `SetProcessRootMotionMode(Ignore)`

IKRetargetEditor.cpp(</E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRigEditor/Private/RetargetEditor/IKRetargetEditor.cpp:407>)

  • RTG 预览 anim proxy 构造时直接 `bIgnoreRootMotion = true`

IKRetargetAnimInstanceProxy.cpp(</E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRigEditor/Private/RetargetEditor/IKRetargetAnimInstanceProxy.cpp:19>)

  • 单节点序列评估时,本来 `FAnimExtractContext` 会先取 `Sequence->bEnableRootMotion`,但 editor 下又被这句覆盖成不提取:

`ExtractionContext.bExtractRootMotion = Proxy->bIgnoreRootMotion ? false : ExtractionContext.bExtractRootMotion;`

AnimSingleNodeInstanceProxy.cpp(</E:/UE_5.7/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstanceProxy.cpp:324>)

  • 真正"把 root 从 pose 里剥掉/重置"的条件是

`(ExtractionContext.bExtractRootMotion && RootMotionReset.bEnableRootMotion) || RootMotionReset.bForceRootLock`

AnimSequence.cpp(</E:/UE_5.7/Engine/Source/Runtime/Engine/Private/Animation/AnimSequence.cpp:1841>)

所以 RTG 预览的实际行为是:**故意不把 root motion 提取到组件运动里,而是把它留在骨骼 pose / 世界空间里给 retarget 用**。视觉上你会觉得"明明关了 root motion,预览却像开着",但源码层面不是改了资产 checkbox,而是预览评估策略不同。

更直接的旁证是批量导出也刻意这么做,注释写得很明白:`ensure WYSIWYG with editor by ensuring the same root motion is applied to the pose, not to the component`,见 IKRetargetBatchOperation.cpp(</E:/UE_5.7/Engine/Plugins/Animation/IKRig/Source/IKRigEditor/Private/RetargetEditor/IKRetargetBatchOperation.cpp:414>)。

如果你要,我下一步可以直接继续沿着 `UIKRetargeter` 资产序列化和 controller/property binding 往下看,确认为什么你的这份 RTG 里 `SourceRoot/TargetRoot/TargetPelvis` 会落成 `None`,是旧字段迁移、复制资产残留,还是 op 初始化时机的问题。

Hierarchy 里 root/pelvis/spine 显示白色,检查的是 retarget chain / hierarchy 映射状态。

这几条 warning 检查的是 Root Motion 这个 op 自己的设置字段。

这不是同一个地方,不会互相保证。

Source Animation

├─ Pelvis Motion

│ 读取 Source Pelvis

│ 按两个人物比例计算

│ 写入 Target Pelvis

│ 结果:身体起伏、重心、蹲起、髋部前后左右运动

├─ FK / IK

│ 在已经确定的 Target Pelvis 基础上处理四肢和脊柱

└─ Root Motion

最后写入 Target Root

结果:目标动画是否拥有可提取的整体移动轨迹

官方默认 Op 顺序也是:

复制代码
Pelvis Motion
→ FK Chains
→ IK Chains
→ IK Solve
→ Root Motion

也就是说,Pelvis Motion 是身体姿态计算的上游;Root Motion 是最后是否生成或复制"根骨骼轨迹"的下游。​Epic Games Developers+1

即使动画是 In-Place,完全不需要角色沿地面前进,骨盆仍然需要上下起伏、左右摆动和旋转。所以 Pelvis Motion 几乎所有人物动画都需要。官方把它定义为负责将 source pelvis 的位置、旋转和位移按比例传到 target pelvis。​Epic Games Developers

root 靜止、pelvis 承載全局位移

Transfer the pelvis bone's translation animation to the root bone.

把 pelvis 骨骼的「平移動畫資料」轉移到 root bone。

原本記錄在 pelvis 軌道上的位移關鍵幀

重新烘焙到 root bone 的位移軌道

UE 的 Animation Sequence 不是只有一坨不可分割的「動畫」,而是包含各骨骼在不同時間點的 Position、Rotation、Scale 關鍵幀。於是口語上可以說:

复制代码
animation on the pelvis

這個影片裡,更精確地說只轉移了 Translation,並沒有把 pelvis 的全部動畫都搬走。

修復前:

复制代码
root.translation   = 不動
pelvis.translation = 人物向前跑的整體軌跡
pelvis.rotation    = 跑步時的轉胯

修復後:

复制代码
root.translation   = 人物向前跑的整體軌跡
pelvis.translation = 清除原本的整體位移
pelvis.rotation    = 仍然保留

標題之所以使用 Animation From Pelvis,是因為在動畫製作語境中,骨骼可以被看作動畫資料的「承載軌道」:

复制代码
pelvis animation
= pelvis 這根骨的 transform keys

root animation
= root 這根骨的 transform keys

「from pelvis to root」描述的是資料歸屬發生變化:

Transfer Pelvis Translation to the Root Bone

Source:root 的动画轨迹

↓ 按角色相对高度缩放

Target:JieErPeiTa 的动画轨迹

Copy From Source Root 会直接复制源 root 的运动。

Animation Sequence 上勾 Enable Root Motion,只表示这个序列允许被提取 root motion

5.7 里 UAnimSequence 就是用 bEnableRootMotion 决定 HasRootMotion() 的。

但 BlendSpace 本身没有单独的 root motion 开关

真正决定它会不会把 root motion 提取/应用出来的,是拥有它的 AnimInstance 的 RootMotionMode

而 5.7 里 UAnimInstance 默认值是:

RootMotionFromMontagesOnly

所以默认情况下:

  • 你把很多 AnimSequence 都开了 root motion
  • 它们放进普通 BlendSpace
  • 再放进 ABP 状态机里

也还是不会因为这些序列而移动,因为默认只吃 Montage 的 root motion,不吃普通 BlendSpace / Sequence 的。

Simulate In Editor(SIE)

Eject 到底"弹出"了什么

这里的 Eject 类似"飞行员从座舱弹出"的命名:

复制代码
PlayerController / 玩家视角
原本附着在 Pawn 上
        ↓ Eject
脱离 Pawn
        ↓
改用自由的 Editor Viewport Camera
  1. 下面的 Anim Preview Editor -> Edit Selected Instance

    这是预览窗口里那一个临时实例 的当前值。

    你改这里的 Speed / IsFalling / Character,主要是为了让预览跑起来,不等于保存到资产默认值

  2. 下面的 Anim Preview Editor -> Edit Defaults

    这是只针对你这个 AnimBP 自己定义的变量 去改默认值的快捷入口。

    它更像一个"变量面板",不是完整的 class defaults 总表。

Eject 会从玩家控制器脱离,并从当前地点切换到 Simulate In Editor;相反,Possess 会重新附着到玩家控制器。​Epic Games Developers+1

视频中的复现条件是:

复制代码
启动多人 PIE
+ 使用 Dedicated Server
+ 启动后最初一两秒仍是黑屏
+ 此时立即点击 Eject
= Unreal Editor 崩溃

如果等待几秒再 Eject,或者切换成单人 PIE,就不能复现。

不是"临时状态自己崩了",而是 Eject 的编辑器代码执行了下面的切换:

复制代码
读取当前 LocalPlayer
        ↓
取得其 PlayerController
        ↓
读取玩家当前视角的位置和旋转
        ↓
让 Editor Viewport Camera 接到同一位置

这样 Eject 后镜头不会突然跳到其他地方。

但在多人游戏刚启动的黑屏阶段,状态可能是:

复制代码
LocalPlayer 已经存在
PlayerController 尚未创建完成或尚未绑定

当时那段代码只检查了:

复制代码
LocalPlayer != null

却没有继续检查:

复制代码
PlayerController != null

"临时"的到底是什么

PIE/SIE 确实是临时测试状态,但"临时"指的是 World 和运行数据

复制代码
编辑器中的原始 Level
        ↓ 启动 PIE
创建测试用的运行时 World
        ↓
Actor 开始 BeginPlay、Tick、物理、AI、动画
        ↓ Stop
运行时 World 被销毁

例如你在游戏运行期间:

复制代码
角色移动了
物体被破坏了
变量发生变化
物理物体掉到地面

停止 PIE 后,这些运行时变化通常会被丢弃。SIE 中部分属性可以通过 Keep Simulation Changes 写回编辑器世界,但默认不会永久保存。Epic Games Developers

然而,在常见的 Selected Viewport PIE/SIE 模式下,这个临时 World 仍然运行在 Unreal Editor 的进程中

复制代码
UnrealEditor.exe
├─ Editor World
├─ PIE World
├─ Editor Viewport
├─ PlayerController
└─ Eject / Possess 相关编辑器代码

World 是临时的,不代表它拥有独立的进程保护边界。任何未处理的原生 C++ 崩溃都可能让整个 UnrealEditor.exe 退出。

PIE Session

└─ 本次按下 Play 后开始的一轮测试

PIE Game Instance

└─ 这一份运行中的游戏

对应一个 UGameInstance

运行时对象实例

├─ UWorld

├─ ULocalPlayer

├─ APlayerController

├─ APawn

└─ 各种 Actor

多人 PIE 的关键:一个 Editor 里可以有多份游戏世界

大致结构是:

复制代码
UnrealEditor.exe
│
├─ Editor World
│  └─ 你平常编辑的原始关卡
│
├─ PIE Dedicated Server World
│  ├─ Server GameInstance
│  ├─ GameMode
│  └─ 没有 LocalPlayer
│
├─ PIE Client 1 World
│  ├─ Client 1 GameInstance
│  ├─ LocalPlayer 1
│  ├─ PlayerController 1
│  └─ Pawn 1
│
└─ PIE Client 2 World
   ├─ Client 2 GameInstance
   ├─ LocalPlayer 2
   ├─ PlayerController 2
   └─ Pawn 2

它们可以全都在同一个 UnrealEditor.exe 进程里,但仍是不同的 World 和游戏实例。Epic 官方也明确说,PIE 可以在已加载的 Unreal Engine 实例内创建多个 World,用于网络测试和分别调试各个 World。​Epic Games Developers

多个游戏实例

≠ 必然多个 Windows 进程

这对找 Bug 为什么重要

因为很多代码错误不是"这个函数永远错",而是:

这个函数只在某一种运行实例、某个网络角色、某个生命周期阶段中,遇到了开发者没有预料到的对象状态。

视频里的 Bug 就是典型例子。

正常单人启动时,很可能很快形成:

复制代码
LocalPlayer 有效
PlayerController 也有效
Pawn 也已经生成

所以这段有缺陷的代码看起来一直正常:

复制代码
if (EditorPlayer.IsValid())
{
    EditorPlayer->PlayerController->GetPlayerViewPoint(...);
}

开发者心里的隐含假设是:

复制代码
只要 LocalPlayer 存在
→ PlayerController 必然也存在

但多人 Dedicated Server PIE 刚启动的一两秒内,可能处于:

复制代码
LocalPlayer 已创建
PlayerController 尚未建立或尚未关联

于是:

复制代码
EditorPlayer.IsValid() == true

EditorPlayer->PlayerController == nullptr

代码检查了前者,却直接解引用后者,最终产生空指针崩溃。视频确认这个问题只在多人 PIE 启动后的短暂黑屏期间立即按 Eject 时稳定复现;等待几秒或切到单人模式后就无法复现。

UE 把 Standalone 用在了兩個不同維度上

因此它有時看起來像與 Dedicated Server 並列,有時又只是表示"單獨開一個進程"。先把兩個維度拆開

維度一:這個 World 在網路中扮演什麼角色

UE 5.7 的 ENetMode 有四種:

复制代码
NM_Standalone
NM_DedicatedServer
NM_ListenServer
NM_Client

這裡的 Standalone 才真正和 Dedicated Server / Listen Server / Client 並列。​Epic Games Developers+1

复制代码
NM_Standalone
= 沒有網路連線的一份完整遊戲
= 本地同時擁有伺服器邏輯與玩家邏輯
= 不接受遠端 Client 連入

NM_DedicatedServer
= 只當伺服器
= 沒有本地玩家
= 不渲染畫面、不處理玩家輸入
= 等待遠端 Client 連入

NM_ListenServer
= 伺服器 + 本地玩家
= 主機玩家自己也在這個 World 裡玩

NM_Client
= 連到別的 Server
= 顯示畫面、收集輸入
= 不持有權威遊戲狀態

最容易誤解的是 NM_Standalone。它不是"純 Client",也不是"沒有伺服器功能":

复制代码
NM_Standalone
└─ 一個 World 自己把整套遊戲全部算完
   ├─ Server-side gameplay
   ├─ Client-side presentation
   ├─ LocalPlayer
   └─ PlayerController

UE 官方甚至仍把它視為一種 server,因為它具有全部 server functionality,只是不接受遠端連線。​Epic Games Developers

維度二:這份遊戲在哪個 OS 進程裡執行

Play 選單中的:

复制代码
Selected Viewport
New Editor Window
Standalone Game

是在決定顯示方式與進程邊界,不是在決定網路身份。

复制代码
Standalone Game
= 遊戲在自己的 OS 進程中運行

所以不能 Eject、不能切換到 Simulate、不能由 Editor Toolbar 直接 Pause/Stop​Epic Games Developers

因此存在兩個完全不同的"Standalone":

复制代码
Standalone Game
= Process / Display Mode
= 是否脫離 UnrealEditor.exe 單獨執行

NM_Standalone
= Network Mode
= 是否處於非聯網遊戲狀態

它們名稱相同,但回答的是不同問題。

Control Rig 节点的本质是:

复制代码
输入一份已经生成的骨骼 Pose
        ↓
执行指定的 Control Rig Blueprint
        ↓
由 Control Rig 修改骨骼变换
        ↓
输出修改后的 Pose

它自己不代表某一种固定功能,也不会天然执行脚部 IK。它具体做什么,完全取决于该节点的 Control Rig Class 里面写了哪些 RigVM / Forward Solve 逻辑。常见用途包括脚部贴地、手部 IK、瞄准、脊柱修正和其他程序化骨骼调整。Epic 官方将它定义为在 Animation Blueprint 内调用 Control Rig,以程序化方式处理动画姿势。​编辑Epic Games Developers+1

Game Animation Sample Project(GASP)

ctrl b跳到资产,ctrl e跳到资产Editor

找到当前正在使用这个 ABP 的、世界中那一个具体 Character 实例,并保存对它的引用。

Character Class

└─ 类型/模板

例如 ACharacter、BP_PlayerCharacter_C

Character Object

└─ 游戏运行时生成的具体对象

例如 BP_PlayerCharacter_C_0

Character Object Reference

└─ 指向 BP_PlayerCharacter_C_0 的引用

表示"以后要访问的是这个对象"

复制代码
名词修饰名词
Aim + Input
└─ 用于 Aim 的 Input

也就是:

复制代码
Aim Input = 瞄准输入/瞄准指令

Character Movement Component

根据累计的输入向量更新加速度,并包含网络预测和校正。

Sandbox Character

└─ 使用 Character Movement Component 的版本

并列展示两种移动后端:

复制代码
SandboxCharacter_CMC
└─ 使用 UCharacterMovementComponent

SandboxCharacter_Mover
└─ 使用 UMoverComponent / Mover Framework

Mover 更强调把移动拆成:

复制代码
Input Commands
Movement Modes
Mode Transitions
Shared Settings
Simulation State
Networking Backend

Mover 更强调把移动拆成:

复制代码
Input Commands
Movement Modes
Mode Transitions
Shared Settings
Simulation State
Networking Backend

相同的玩家输入
        ↓
┌──────────────────────┐
│ CMC 版本              │
│ CharacterMovement    │
└──────────────────────┘

或者

┌──────────────────────┐
│ Mover 版本            │
│ MoverComponent       │
└──────────────────────┘
        ↓
产生实际位置、速度和移动状态

所以 CMCMover 不是两种动画;它们是两套负责实际移动模拟的实现。

Enhanced Input 官方把 Input Action 定义成"玩家能够执行的一件事",例如 Crouch、Fire、Walk。Input Action 可以输出 Boolean、1D、2D 或 3D 数据,不要求所有 Input 都是方向向量。​Epic Games Developers

所以这些名字其实属于不同类型:

复制代码
Move Input
└─ 连续方向和力度
   通常是 Vector2D

Sprint Input
└─ 是否请求冲刺
   通常是 Boolean

Aim Input
└─ 是否请求进入瞄准状态
   通常是 Boolean

Strafe Input
└─ 是否请求进入 Strafe 移动模式
   通常是 Boolean 或 Toggle

Jump Input
└─ 一次离散动作请求

提供的 Blueprint 数据也正好体现了这一点:

复制代码
IA_Move
└─ ActionValue 是 Vector2D
   └─ 传给 AddMovementInput

IA_Sprint
└─ ActionValue 是 Boolean
   └─ 写入 WantsToSprint

IA_Aim
└─ ActionValue 是 Boolean
   └─ 写入 WantsToAim

IA_Strafe
└─ 注释明确写着 Strafe Input (toggle)
   └─ 每次触发反转 WantsToStrafe

当前 AnimInstance

↓ Owning Component

创建它的 SkeletalMeshComponent

↓ Owner / Outer 链

拥有该组件的 Actor
↓ Cast
确认这个 Actor 是不是 Character

Blueprint 是普通 Actor------LevelButton,不是被玩家控制的 Character 或 PlayerController。因此,Q 事件只有在这个 Actor 已经获得输入权限时才会触发,例如:

复制代码
Begin Overlap
└─ Enable Input
   └─ Player Controller 0

或者在 Actor 的 Details 中设置:

复制代码
Auto Receive Input
└─ Player 0

普通 Actor 需要通过 Enable Input 指定提供输入的 Player Controller,之后 Key Event 才能响应;也可以在进入 Trigger 时启用、离开时禁用。​Epic Games Developers

Get Owning Component 的定义就是:返回"创建当前 AnimInstance 的 Skeletal Mesh Component";而 UActorComponent::GetOwner() 会沿着 Outer 链得到拥有该组件的 Actor。​Epic Games Developers+1

UE 里有一整套同构名字:

复制代码
FInterpTo   → Float Interpolate To
VInterpTo   → Vector Interpolate To
RInterpTo   → Rotator Interpolate To
CInterpTo   → Color Interpolate To

这里重点不是"把英文缩得很漂亮",而是让类型前缀形成规律

复制代码
F = Float
V = Vector
R = Rotator

复制代码
Make Rot from X
│    │        └─ 已知 X 轴方向
│    └────────── Rotator
└─────────────── 构造

实际逻辑是:你只提供一个 X 方向 Vector,UE 把它作为局部 X 轴,再自动计算互相垂直的 Y、Z 轴,最后返回一个 Rotator。官方也明确写的是 "Builds a rotator given only an XAxis"。​编辑Epic Games Developers

为什么不是 Make Rotation from X

因为 UE 内部区分:

复制代码
Rotation = 旋转这个抽象概念
Rotator  = UE 中用 Pitch / Yaw / Roll 保存旋转的数据类型

节点返回的是 Rotator 类型,所以内部命名更接近

复制代码
MakeRotFromX

RotRotator 的截断,不只是普通英文 rotation 的随意简称。

In Rot = Input Rotator

Delta Rot = Delta Rotator

Desired Rot = Desired Rotator

Control Rot = Control Rotation

Actor Rot = Actor Rotation

Pitch → 抬头 / 低头

Yaw → 向左看 / 向右看

Roll → 歪头,耳朵靠近肩膀

正向 Pitch 的描述就是 nose upYaw 则是绕对象自身的 Up Axis 转动。Epic Games Developers

横着理解:

复制代码
PlayerController
→ Set View Target with Blend
→ New View Target:某个 Actor

所以它不是 CameraActor 的函数,也不是 Character 的函数。

责任链是:

复制代码
PlayerController
└─ 持有当前玩家的观看目标 View Target
   └─ 通过 PlayerCameraManager 计算最终画面

New View Target 为什么是 Actor,而不是 Camera Component

复制代码
CameraActor
Character
Pawn
任何带 Camera Component 的 Actor

这些 Actor 都可以作为 View Target。UE 会从该 Actor 获取相机视图。

复制代码
Set View Target
+ 在旧 View Target 和新 View Target 之间做镜头过渡

真正管理和混合最终摄像机结果的是该玩家对应的 PlayerCameraManager,但你通常通过 PlayerController 节点发出切换命令。

Paragon

└─ Epic 以前的一款游戏

└─ Epic 后来把其中的角色资产免费发布

└─ Shinbi 是其中一个角色

turn off the cloth sim

完整是:

turn off the cloth simulation

Ultra Dynamic Sky

這裡是資產名稱的首字母縮寫:

Ultra

Dynamic

Sky

他前面先說完整名,後面就直接說 UDS

thanks to UDS

= 多虧了 Ultra Dynamic Sky。

Area of Effect

意思是「範圍效果/範圍攻擊」。

overpowered

原句:

it is a bit OP

= 它現在有點太強了/強得失衡。

underpowered

= 太弱、低於應有強度。

my FPS would tank

這裡 tank 是動詞:

暴跌。

整句:

我的幀率會直接掉得很慘。

FPS 也可以是:

first-person shooter

IKEA

這不是縮寫式技術詞,但名字本身原本是首字母組合:

Ingvar

Kamprad

Elmtaryd

Agunnaryd

不過英語使用者通常不會現場拆它,只把 IKEA 當品牌名讀。

parry 是:

用武器把對方的攻擊「格開、撥開」。

它不是單純 block 那種硬擋。

在遊戲裡可以這樣分:

复制代码
block
→ 把攻擊擋住
→ 可能仍然消耗耐力、承受部分傷害

parry
→ 在正確時機把攻擊撥開
→ 通常會讓敵人失衡,創造反擊窗口

你這段裡:

we do have parry in the game, too

And the major caveat is that we control only the material emissive input.

elongatedstretched 很接近,但画面感略有区别:

  • elongated:结果状态变得细长、狭长。

  • stretched:强调被"拉伸"这个过程或效果。

官方把这种方式称为 Runtime IK Retargeting:不提前生成一套新的 Animation Sequence,而是在运行时由 Retarget Pose From Mesh 把源 Skeletal Mesh 的姿势转换给目标角色。Epic Games Developers

Runtime IK Retargeting 的优势是"不生成新的 Animation Sequence",而是在运行时动态转换。Epic Games Developers

例如 Substance 3D Designer 2026。2026 版在 Steam 的正式發售日期是 2026 年 4 月 14 日

tech animator

→ 技術動畫師

→ 負責動畫進引擎後的 Rig、Blueprint、邏輯、系統整合與除錯

UE 5.8 的 Sequencer/動畫介面更接近 Maya,讓原本長期在 Maya、MotionBuilder 等 DCC 裡工作的動畫師,可以更自然地直接進引擎工作。

复制代码
操作系统
└─ 把一批虚拟内存页交给 Unreal 进程

Unreal Engine 内存分配器
└─ 再从这些内存中切出一小块
   └─ 放置某个类实例

所以"这个实例具体位于哪个地址",通常是引擎的内存分配器决定的;但引擎能使用哪些虚拟地址、这些地址最终映射到哪块物理 RAM,则由操作系统管理。

以一个 AActor 实例为例:

复制代码
AActor* Actor = GetWorld()->SpawnActor<AActor>();

1. UE 请求创建一个 AActor
2. UE 的 UObject 系统计算对象需要多少内存
3. UE 内存分配器寻找一块合适的空闲区域
4. 在那里构造 AActor 实例
5. 返回实例地址,保存进 Actor 指针
6. UObject 系统登记并跟踪这个对象

Epic 明确规定,UObject 不能直接用普通 new 创建,而由 Unreal 的对象系统分配并进行垃圾回收。Epic Games Developers+1

Windows 给每个进程一套独立的虚拟地址空间。例如 UE 看见:

复制代码
0x000001F84A201000

这首先是一个虚拟地址,并不表示某个固定 RAM 芯片位置。

Windows 负责:

复制代码
虚拟地址
→ 映射到物理内存页
→ 必要时换出到页面文件
→ 控制不同进程之间的内存隔离

因此 UE 通常不知道对象最终落在物理 RAM 的哪颗芯片、哪一行。

UE 通常不会为了每一个几十字节的小对象都直接向 Windows 单独申请一次。那样系统调用成本高,碎片也严重。

它会先取得较大的内存区域,然后通过自己的 allocator 分配小块:

复制代码
Windows 给 UE 一大片内存
└─ UE allocator 建立多个 pool
   ├─ 一块给 Actor A
   ├─ 一块给 Actor B
   ├─ 一块给 Component C
   └─ 剩余部分继续复用

UE 5.7 中的 FMemory 是引擎统一的内存操作接口;FMallocBinned3 则是用于处理大小内存池的优化虚拟内存分配器之一。​Epic Games Developers+1

普通 C++ 类

复制代码
FMyClass* Value = new FMyClass();
delete Value;

通常由程序员自己控制生命周期。实际底层分配可能仍经过 UE 重载或 FMemory,但它不是 UObject GC 管理的对象。

不繼承 UObject、不進入 Unreal Reflection / GC 系統的原生 C++ 類型。

例如:

复制代码
class FMyData
{
public:
    int32 Value;
};

這就是普通 C++ 類。它沒有:

复制代码
UCLASS()
GENERATED_BODY()

也不繼承:

复制代码
UObject
AActor
UActorComponent

判斷標準

U → UObject 派生類

A → Actor 派生類

F → 非 UObject 類型或 struct

S → Slate Widget

I → Interface

T → Template

Lobby → Territory → Flag Capture → Hold Ball → Lobby

其中 Territory 是「佔領區域並得分」的模式。影片前面就說:

loads a hold territory level

hold that territory and gain score

也就是「守住那塊區域來累積分數」。

Event Touch Jump Start

lobby 最原始的意思是:

建築入口附近的大廳、前廳。

例如飯店、電影院、辦公樓進門後的公共區域,都可以叫 lobby

遊戲裡把這個空間概念借過來,變成:

正式進入比賽前,玩家先集合、等待、選模式或組隊的地方。

multiplayer lobby

「玩家可以進入對方世界」「臨時多人實例」

B 是權威主機,因此有主機優勢,而且 B 斷線,整個會話通常也會結束,

運行的依然是自己的一台電腦,重新創建了一個新的 level, 在新的level裡可以只有game State切換了,其他的世界顯示資源都保持不變,

gamestate切換之後,

每一幀,玩家a和玩家b都上傳自己的location,

每一幀,玩家x接收額外的b信息,加入玩家b的位置數據渲染

PlayerState 對所有人公開、可複製的玩家狀態

100 miles away from the coast

單純測量距離:離海岸100英里

100 miles off the coast

帶有地理定位感:在海岸外海100英里處

Cinderella story 通常指:

一個原本不起眼、弱小、被忽視的人或地方,突然獲得機會,進入遠超原本地位的舞台。

at this point is in the carriage headed to the ball 可以補完整成:

at this point, Taiwan is in the carriage that is headed to the ball

也就是:

此時,台灣正坐在前往舞會的馬車裡。

nay /neɪ/ 是正式表決語言中的「反對」,與 yesyea 相對。

shuck 是什麼

shuck /ʃʌk/ 是:

去掉玉米、堅果或貝類外面的殼。

在牡蠣語境裡,通常就是:

撬開牡蠣殼,把牡蠣肉取出來。

famous milk oysters,

如果你能在颱風、乾旱,甚至六級地震同時出現的情況下,仍然讓最先進晶片製程保持穩定,那麼你形成的工程紀律,是身處穩定氣候地區的競爭者很難比得上的。

If you can keep a cutting-edge chip process stable during a typhoon or drought and a magnitude-six earthquake simultaneously, you have an engineering discipline that competitors in stable climates simply cannot match.

Public 官方明確說,Generated Assets 使用的是「廣泛的公開金融資訊」,包括公司基本面與歷史表現等,而不是宣稱使用內幕資料或獨家非公開資訊。​Public Help

它和一般 ChatGPT 的差別主要在這裡:

复制代码
你輸入:
「找出營收成長超過20%、自由現金流為正的半導體公司」

Public:
理解條件
↓
掃描股票池
↓
取得結構化財務資料
↓
篩選公司
↓
決定持股與權重
↓
回測對比 S&P 500
↓
直接建立可投資組合
↓
在券商帳戶裡買入與再平衡

Public 把這個功能稱為 Generated Assets :用自然語言建立一個自訂指數,之後可以修改持股、權重、回測,最後直接投資。​Public+1

而普通 ChatGPT 通常比較像:

复制代码
理解你的投資想法
+
搜尋與解釋公司資料
+
幫你整理篩選邏輯

但通常不能直接:
建立券商內的正式投資組合
持續管理每個持倉
執行再平衡
直接完成交易

cluster(產業聚落/集群)

把半導體所需的大學、人才、晶圓廠、材料商和設備供應商,刻意壓縮在很小的地理範圍內。

新竹科學園區內有大約二十座晶圓廠,既有最尖端製程,也有成熟製程;而大學、供應商和工廠又全部靠得非常近,形成一個難以複製的高密度產業集群。

The people that the government forced to move off their land in this area and the surrounding area were not thrilled.

take the cup off the table

把杯子從桌上拿走

get off the chair

move off the land

thrilled 本來是:

非常興奮、非常高興

所以 not thrilled 字面是「沒有很高興」,但日常語氣常是委婉地表示:

很不爽、很不滿、並不樂意

thermonuclear war 本义是"热核战争",涉及氢弹级别的核战争。乔布斯并不是真的要打仗,而是在用极端夸张的说法表示:

我要不惜代价和 Android/Samsung 斗到底。

为什么 Samsung 会让他这么愤怒?

因为当时 Apple 一方面把芯片订单交给 Samsung,另一方面 Samsung 自己也生产手机。

作者后面就说,乔布斯看到 Samsung Galaxy 手机后,认为它从外形、软件到包装都在模仿 iPhone。

IKEA 的情況卻反過來很荒謬:

复制代码
IKEA
→ 設計並製造家具零件
→ 把一堆板子和螺絲賣給你
→ 你付了錢
→ 還要自己負責最後組裝

所以表面上兩者都像:

別人設計,你負責把東西做出來。

但商業關係其實完全相反:

复制代码
晶片代工
設計公司付錢給工廠工作

IKEA
顧客付錢給 IKEA
結果顧客自己工作

這就是 joke 的核心:

IKEA 厲害到不是它付錢請你組裝,而是你付錢給它,還替它完成最後一道工序。

gets the full first year of their factory capacity

新製程剛量產時,Apple 能鎖定非常大比例的早期產能。

不是說全台積電所有工廠一年都只服務 Apple,而是指相關新製程線的早期容量,Apple 具有極強的優先權。

为什么 Apple 愿意付更高价格抢第一年?

因为:

复制代码
Apple 最早拿到下一代芯片
↓
新 iPhone / Mac 可以先使用更强、更省电的处理器
↓
形成产品领先

与此同时,台积电也受益:

复制代码
Apple 承诺购买巨量芯片
↓
台积电敢于提前投入昂贵新工厂
↓
不用担心新产能建好后没人使用

work out the kinks 原本是把绳子、管子里的扭结弄平,后来表示:

解决刚开始运行时的各种小问题。

Apple 会承受早期较贵的晶片,但换来的是领先使用权。

gets first crack

because Apple gets first crack...

get first crack at something 是:

获得第一个尝试或优先使用的机会。

anchor tenant

anchor tenant 是商业地产里的「主力租户」:

一个本身足够有吸引力,可以把顾客、其他商家和资本一起拉来的核心租户。

例如购物中心引入一家大型百货或超市,这家店就是 anchor tenant。

者举的例子是纽约第五大道 Apple Store。那里原本有一大片地下商业空间,但普通人不愿无缘无故走下楼,所以地下空间价值很低。后来 Apple 进驻,地面建起著名玻璃方盒,吸引大量人流,连带提高整栋建筑和周边空间的价值。

这就是后面的 flywheel

飞轮一开始很重,很难推动;但一旦开始转,就会因为惯性越来越稳定,持续带动系统。

為什麼會變濁?因為它變成:

复制代码
worth + y

中間的 th 夾在有聲音的環境裡,日耳曼語系裡很多這種位置會變得更容易濁化。類似:

复制代码
bath → bathe
breath → breathe
cloth → clothe
worth → worthy

但你現在不用把它當作必背規則。你可以只保存一個工程化策略:

th 不確定時,先讀清音 /θ/,大多數內容詞能交流;之後遇到高頻詞再校正成 /ð/。

聽多了,mother, brother, weather, worthy

bento 來自日語 弁当 / bentō,意思是便當

lunch box

泛指午餐盒,任何國家風格都可以

bento box

更像日式分格便當盒,強調分類、整齊、份量搭配

現在英文裡也常被借去做比喻。比如設計、UI、產品展示裡說 bento box layout,通常不是講吃的,而是說:

像便當盒一樣,把資訊分成一格一格的卡片式布局。

例如 Apple 網站常見那種:

复制代码
大卡片 + 小卡片 + 圖片 + 標題
整齊排列成不同尺寸的格子

term + colon

prose 就是普通段落文字,不是詩、表格、條列或碎片式筆記。compact prose 就是資訊密度比較高、段落連續、不把每個小點拆成很多短行的寫法。

term + colon 是更具体的描述,字面就是:

一个术语后面加冒号。

label-colon formatting 更像一个格式名称,意思是:

用"标签 + 冒号"来组织内容的排版方式。

看到 chem-/chron-/chrom-/psych-/arch-/chor-/chord,ch 优先读 /k/。其他 ch 默认 /tʃ/。

"看起来像希腊词"。

法语来源的 /ʃ/ 更不能靠感觉,直接当高频例外表:

chef /ʃef/

machine /məˈʃiːn/

champagne /ʃæmˈpeɪn/

chauffeur /ʃoʊˈfɜːr/

chic /ʃiːk/

brochure /broʊˈʃʊr/

parachute /ˈpær.ə.ʃuːt/

「英語裡多少詞不受拼詞法約束」:法語來源是最大麻煩之一

Latin 的拼讀相對有模式,但不是本族英語模式。它常常是:

复制代码
prefix + root + suffix

大致判斷:

复制代码
-gue / -que / -age / -tion / -ment / -ous / -ure
soft g/c
重音可能偏後
ch 有時讀 /ʃ/,如 machine, chef

所以你問「英語裡多少詞不受拼詞法約束」:法語來源是最大麻煩之一

Greek 詞的特徵:

复制代码
bio / geo / psycho / photo / thermo / chrono / morph / phon / graph / logy / pod / saur
ph = /f/
ch 常 = /k/,如 chemistry, chromatic
y 常作 /ɪ/ 或 /aɪ/

Greek 詞其實很適合「算法讀音」,因為它高度模塊化:

复制代码
sauro + pod + a
thermo + nuclear
chrono + logical
morph + ology

它看起來長,但一旦你認出詞根,反而比法語詞穩。

turnover = 一轮东西被翻过去、换出去、交出去、流转掉

loitering

IPA: /ˈlɔɪtərɪŋ/

可交流讀音:LOY-ter-ing

意思:閒逛;逗留;在某處無明確目的地徘徊。法律/保安語境裡常是「可疑逗留」。

incentive

IPA: /ɪnˈsentɪv/

可交流讀音:in-SEN-tiv

意思:誘因;激勵;讓人願意做某事的好處或刺激

复制代码
看到陌生詞:incentive
├─ 1 來源層
│  Latin / French layer
│  背後有 incinere / incent- 這種「唱起來、激起」的路線
│  現代英語裡核心是:刺激行動的東西
│
├─ 2 使用圈層
│  經濟 / 商業 / 管理 / 政策 / 行為分析 / 日常
│  incentive structure = 激勵結構
│  financial incentive = 金錢激勵
│  perverse incentive = 反向激勵

synthetic

IPA: /sɪnˈθetɪk/

可交流讀音:sin-THET-ik

意思:合成的;人造的;非天然的;綜合性的

复制代码
看到陌生詞:synthetic
├─ 1 來源層
│  Greek → Latin/French → English scientific/formal layer
│  syn- = together,一起
│  thesis / thet- = putting / placing,放置、組合
│
├─ 2 使用圈層
│  科技 / 化學 / 材料 / AI / 哲學 / 語言學 / 日常
│  synthetic material = 合成材料
│  synthetic data = 合成數據
│  synthetic biology = 合成生物學

PlayerController / Character Blueprint

└─ BeginPlay / SetupInput

└─ Get Local Player

→ Get Enhanced Input Local Player Subsystem

→ Add Mapping Context

Add 到 Enhanced Input Local Player Subsystem

官方說 UE6 Early Access 目標是 2027 年底 ,完整 UE6.0 在那之後 12--18 個月 。也就是說,完整 6.0 大概是 2028 末到 2029 上半年這個區間。​编辑Unreal Engine

Tim Sweeney 的說法是「UE5 plus UEFN equals UE6」。目標是你用一套 UE6 workflow 做內容,然後可以發到 PC、主機、手機、Fortnite,甚至未來其他 UE6 game ecosystem。

Blueprint

├─ 強依賴 UE Editor

├─ 強依賴 Actor/UObject 生態

├─ 視覺圖難做 source control / diff / merge

├─ 對 AI/codegen 不夠乾淨

├─ 跨項目可攜性差

└─ 大規模多人/分散式語義不是它一開始的設計核心

Verse

├─ text-based,適合版本控制、生成、分析

├─ typed language,語義更明確

├─ 面向 UEFN / creator ecosystem

├─ 目標支撐可組合、可移植 gameplay logic

├─ 和 transaction / rollback / distributed simulation 路線更接近

└─ 未來可以再做視覺化編輯器生成 Verse

Verse 的 software transactional memory,這不是裝飾詞。它指向 Epic 想做的東西:遊戲邏輯像 transaction 一樣執行,可以失敗、回滾、提交,未來更容易放到分散式服務器上跑。

傳統 UE multiplayer 大多是:

复制代码
一個 match / 一張 map / 一個 shard
→ 主要由一台 authoritative server 負責
→ 玩家、AI、物理、互動、replication 都壓在這台 server 上

這種模式簡單、可靠,但上限很硬:

复制代码
玩家多了 → server tick 壓力上升
AI 多了 → CPU 壓力上升
互動物件多了 → replication 壓力上升
地圖太大 → relevancy / streaming / state 管理變複雜

分散式服務器想解決的是:

复制代码
同一個大世界
├─ 區域 A 由 server A 算
├─ 區域 B 由 server B 算
├─ 大型副本 / 地下城 / 城市 / 戰場可拆到不同 server
├─ 玩家跨區域時轉移 authority
└─ 整體看起來像一個連續世界

Epic 在 UE6 路線裡明確說,他們的目標是把現有「像單線程那樣寫的 Verse game code」自動分發到多台 server 上。這就是為什麼 Verse 的 transactional semantics 重要:它讓引擎更容易判斷哪些狀態改動可以提交、回滾、分發。​Unreal Engine

更大玩家數

傳統單 server:

复制代码
100 人戰場
→ server 還能勉強處理

1000 人同場
→ movement / combat / visibility / replication 爆炸

分散式:

复制代码
1000 人不一定都壓在一台 server
→ 按區域 / 空間 / activity 分拆
→ 每台 server 只處理自己負責的部分

所以它適合 MMO、大型社交空間、大型戰場、Fortnite-style user generated worlds。

適合 MMO、大型社交空間、大型戰場、Fortnite-style user generated worlds。

第二,更大的世界,不需要把玩家硬切 instance

傳統做法常常是:

复制代码
主城 1
主城 2
主城 3
副本 A
副本 B

玩家其實被分流到不同 instance 裡。這很穩,但割裂感強。

分散式世界想要的是:

复制代码
一個大世界
玩家走到不同區域
背後 server authority 轉移
前台玩家感覺仍然在同一個世界

這對你之前想的「玩家可以進入對方世界 / temporary server / lobby 回來」很相關。未來如果底層更強,這種世界切換就不一定要靠你手寫一堆 server orchestration 邏輯。

更多 AI / NPC / 模擬物件

單 server 最怕的不是只有玩家,還有:

复制代码
大量 NPC
大量物理互動
大量建築/破壞
大量掉落物
大量可互動裝置
大量生態模擬

分散式後可以把不同模擬切出去:

复制代码
城市人群 → server A
野外怪物 → server B
副本戰鬥 → server C
交易/經濟狀態 → backend service
大型事件 → 專門 simulation server

這讓遊戲可以從「地圖裡放幾百個 active actors 就怕」走向「世界裡同時有很多活的系統」。

更適合 Fortnite / Roblox / UGC 生態

這其實是 Epic 最在意的。

如果每個創作者都做自己的 gameplay object,傳統做法會很亂:

复制代码
創作者 A 的 Blueprint
創作者 B 的 Blueprint
創作者 C 的 C++ plugin
各自有 Tick、RPC、replication、狀態保存邏輯

要把這些東西放在同一個可共享生態裡,很難保證安全、性能、同步一致。

Verse + Scene Graph 想把它變成:

复制代码
每個 smart asset / gameplay object
├─ 有明確 entity/component 結構
├─ 行為用 Verse 描述
├─ 狀態改動可被 transaction 管理
├─ 可以被工具分析
├─ 可以被 AI 生成/修改
└─ 可以更安全地放進大規模共享世界

Scene Graph 官方文檔也說它是 Verse native system,用來建立 interactive custom-built objects 和 gameplay experiences。​Epic Games Developers

更容易做跨區域、跨平台、長生命週期世界

例如你做一個大型線上世界:

复制代码
台北玩家
東京玩家
洛杉磯玩家
歐洲玩家

如果全部壓到單個 region,延遲很差。

如果拆成多個 region,又要同步世界狀態。

分散式架構至少給了引擎一個方向:

复制代码
近端互動 → 由附近 server 處理
全局狀態 → 用 transaction / replication / persistence 同步
玩家跨區域 → authority handoff

但要注意:這不是免費魔法。

分散式 server 的代價很大:

复制代码
好處:
├─ 更大玩家數
├─ 更大世界
├─ 更多 AI / 模擬
├─ 更少硬切房間
├─ 更適合 UGC / smart assets
└─ 更接近真正 persistent world

代價:
├─ 延遲更複雜
├─ 狀態一致性更難
├─ 跨 server combat 很難
├─ debugging 更難
├─ server 成本更高
├─ cheating / authority 邊界更複雜
└─ 引擎必須幫你管理大量底層細節

所以 Verse 的 transaction / rollback 思路不是裝飾。它是在替這些問題鋪底:

复制代码
玩家攻擊
→ 改血量
→ 觸發死亡
→ 掉落物生成
→ 任務進度更新
→ UI / replication 通知

如果這些狀態跨多台 server,普通「到處 Set Variable」會很危險。

transaction 的思想是:

复制代码
這組改動要麼一起成功
要麼失敗後回滾
不要留下半成功狀態

這就是為什麼 Epic 要從 Actor/Blueprint 轉向更可分析、更可約束的 Verse/Scene Graph。不是因為普通 Blueprint 做不了遊戲,而是因為它不適合自動拆到多台 server 上保證一致性。

Actor / Blueprint

非常適合:

├─ 單項目遊戲

├─ 單 server authority

├─ 傳統 UE gameplay

├─ 團隊內部快速開發

└─ 編輯器內可視化 scripting

但不夠適合 Epic 下一步想要的:

├─ 多服務器分散式 simulation

├─ 跨遊戲 smart asset

├─ 大量創作者共享可組合 gameplay object

├─ AI 生成 / 分析 / 遷移 gameplay logic

├─ Fortnite / UE / Fab 生態互通

└─ 更嚴格的狀態提交、回滾、同步語義

UE 想做的是:一個開發者做出的 gameplay object / smart asset,不只是「導入模型能用」,而是它的行為、組件、狀態邏輯也能更容易被其他項目接上。

現在 Blueprint 資產互用:

├─ 依賴某個父類

├─ 依賴某個 GameMode / Controller / Interface

├─ 依賴 project settings

├─ 依賴 plugin

├─ 依賴命名、collision、input、replication 設定

├─ 依賴特定 Actor lifecycle

└─ 拿到別的項目常常要手動修一堆引用

Epic 想要的新方向:

├─ object 用 entity/component 表達

├─ behavior 用 Verse 表達

├─ 狀態改動更可分析

├─ 依賴關係更顯式

├─ 更容易被轉換、檢查、沙盒化

├─ 更容易被 AI 和工具生成

└─ 更容易跨項目、跨遊戲、跨服務器運行

entities and components 定義世界物件;entity 是 components 和 child entities 的容器,behavior 由 components 提供。Epic Games Developers Verse API 也把 entity 定義為 SceneGraph 的 base object,物件由一個或多個 entities 構成,behavior 通過 components 加到 entities 上。​Epic Games Developers

現在你用 Blueprint 做一個「會自動開關的門」:

复制代码
BP_AutoDoor
├─ StaticMeshComponent
├─ BoxCollision
├─ Timeline
├─ OnBeginOverlap
├─ Cast To MyCharacter
├─ Play Animation
├─ 可能依賴某個 Input Action
├─ 可能依賴某個 GameInstance 變量
└─ 可能只在你的項目裡能正常跑

別人拿去用,問題可能立刻出現:

复制代码
他的 Character 類不叫 MyCharacter
他的 Collision Profile 不一樣
他的 Input Mapping 不一樣
他的 GameMode 不一樣
他的 networking 模式不一樣
他的項目沒有你的 Interface / Enum / Material / Timeline 依賴

Epic 想要的是更像:

复制代码
AutoDoor smart asset
├─ entity
├─ transform_component
├─ mesh_component
├─ trigger_component
├─ door_behavior_component written in Verse
├─ 明確 exposed properties
├─ 明確 events
└─ 明確可被其他 scene / project / world 接入的接口

這樣別人使用時,不是把整個 BP 連同一堆隱性依賴搬過去,而是把一個更標準的 entity/component/Verse behavior 搬過去。

Unreal Fest 會議內容 / Epic 生態內的技術演示

接著馬上說 LLM 不擅長低層 3D spatial operations,所以要把 Unreal 的 PCG 和 LLM 接起來。

Q&A 裡他們還說,目前他們是從 core out 做起,先做 properties、assets、levels 等核心 tool sets;有些 gameplay systems,例如 State Tree、Behavior Tree,現在 tool sets 只能 read,還不能 write;未來想補 profiling、debugging 這些後段開發工作。

接下來 early next year:

面向 linear content 的 image/video model workflow

Movie Render Graph + depth/styleframe/video generation

复制代码
Linear content
├─ 電影
├─ 電視劇
├─ 廣告片
├─ MV
├─ 動畫短片
├─ 預告片
├─ 虛擬製片鏡頭
├─ cinematic sequence
└─ 任何觀眾只能按既定順序觀看的內容

和它相對的是 interactive content

复制代码
Interactive content
├─ 遊戲
├─ 可交互 VR / AR
├─ 模擬器
├─ Fortnite island
├─ playable demo
└─ 玩家輸入會改變結果的內容

原文說他們想加一個 hazard zone:flashing lamps、steam、玩家靠近時有 danger sense。然後讓模型讀 warning lamp 的現有 material graph,在正確位置插入新邏輯;接著用 Niagara template 擴展蒸汽效果;再通過 UMG 做 HUD;最後用 Blueprint logic 把 proximity trigger 連到 material、Niagara system 和 HUD。

把 UE viewport stream 給本地圖像模型,右邊每幀 stamp 一張新圖,所以不穩定也不是 realtime。然後他 prompt 了 sunset lighting,接著試「what it would look like if there had just been a fire in this apartment」,再試 underwater murky pond。

這裡的流程是:

复制代码
UE Viewport
→ stream 到本地 diffusion image model
→ prompt:「剛剛發生過火災的公寓」
→ image model 在右邊生成一種燒過/煙燻/災後氛圍的圖像結果

重點:它沒有真的改 UE 裡的材質、Niagara、Blueprint 或物理。

它只是給你一個「diffusion lens」:

复制代码
UE 真實場景還是原來那個
右邊 AI 圖像結果把它重新風格化成:
├─ sunset
├─ after fire
├─ underwater
├─ charcoal drawing
└─ watercolor painting

所以要分清:

复制代码
hazard zone:
真的在 UE 裡做了互動邏輯
Material + Niagara + UMG + Blueprint

apartment fire look:
用 image model 對 UE viewport 做即時/近即時風格化
主要是概念預覽,不是可玩的火災系統

https://wikis.khronos.org/opengl/Compute_Shader

Compute Shader:

你自己 dispatch

你自己決定跑多少組工作

你自己決定每個 invocation 處理哪份資料