UGC1.0 代表案例:AI 换色与 ASTC 贴图链路
这篇用两个真实案例回答“你在 UGC1.0 做过什么”。AI 换色体现复杂异步业务闭环,ASTC 体现客户端内容管线、性能与兼容性。面试时先讲一个案例,面试官继续追问时再展开另一个。
面试官:你在 UGC1.0 做过哪些有代表性的工作?
30 秒回答
我在 UGC1.0 做过地图数据与发布链路、AI 创作工具、元件与编辑模式,以及长期线上维护。比较能代表我工作深度的是 AI 换色和 UGC 贴图 ASTC 化。
AI 换色不是调用一次接口,而是完成场景筛选、截图与结构化数据导出、云端任务、结果下载、三组预览、确认应用、撤销重做和自动保存的完整闭环。ASTC 则是为 UGC 图片补齐端侧压缩、双规格异步处理、上传和移动端加载链路。我直接负责客户端流程、状态管理、工具和工程接入;模型算法、云服务与审核策略由对应团队负责。
90 秒回答
AI 换色解决的是创作者不会配色、逐个对象修改成本高的问题。客户端先找出当前场景中可换色的对象,保存对象身份和颜色槽位,同时采集场景图;用户可以输入主题词,也可以给定一组颜色。客户端把场景图和结构化对象数据上传,提交生成任务,收到结果后下载三组候选数据,逐组临时应用、截图并恢复原状态,最终让用户选择一组确认。确认时不是直接覆盖,而是形成可撤销事务,并把变更对象纳入自动保存。
ASTC 解决的是 UGC 图片在移动端的显存、加载和分发问题。我补了查看与转码工具,并接入端侧 ASTC 编码。发布阶段对小图和大图使用两个异步压缩任务,全部成功后再进入上传;运行时识别 ASTC 头和设备能力,再创建对应压缩纹理。优化前部分设备的处理时间会超过十秒,因此后来把轮询式处理改成异步回调,并对线程数、对象生命周期和失败清理做了治理。现有证据能说明问题和机制,但没有完整基准报告,所以我不会编造压缩率或耗时收益。
面试官:AI 换色的完整架构是什么?
一句话结论
它是一条“场景状态采集 -> 云端生成 -> 本地可逆预览 -> 编辑事务提交”的异步内容生产链,客户端既是任务编排者,也是编辑状态一致性的守门人。
flowchart LR
A["筛选可换色对象<br/>记录稳定身份与颜色槽"]
B["记录相机并截图<br/>导出结构化场景数据"]
C["获取临时凭证<br/>上传图片与结构数据"]
D["提交主题词或色板<br/>等待生成任务"]
E["下载三组候选结果"]
F["临时应用 -> 截图 -> 恢复<br/>生成本地预览"]
G["用户确认候选"]
H["提交撤销/重做事务<br/>标记自动保存"]
A --> B --> C --> D --> E --> F --> G --> H这条链中有三类状态不能混在一起:
| 状态 | 例子 | 所有者 |
|---|---|---|
| 编辑真值 | 对象当前颜色、材质槽、对象身份 | 编辑领域与地图数据 |
| 任务状态 | 上传中、生成中、下载中、失败、超时 | AI 换色任务模型 |
| 页面状态 | 选中的候选、按钮禁用、预览图 | UI |
如果页面直接拥有编辑真值,关闭页面或任务失败后就很容易留下半完成状态。
面试官:为什么同时上传图片和结构化数据?
图片提供整体视觉语境,例如画面区域、相邻颜色和场景风格;结构化数据提供精确的对象身份、颜色槽和可修改范围。只给图片,结果很难可靠映射回具体对象;只给对象列表,又缺少视觉关系。
所以服务返回的也不应只是“几种 RGB”,而应是能映射回对象与颜色槽的结果。客户端应用前还要校验对象是否仍存在、类型和槽位是否匹配,不能无条件覆盖当前场景。
面试官:单色对象和多色对象怎样统一?
关键是不要把“对象颜色”建模成一个字段,而要建模成 对象身份 + 可换色槽集合。单色对象只有一个槽,多色对象可以有多个槽;每个槽保留原值和候选值。这样服务结果、预览、确认以及撤销重做都使用同一种结构。
ActorId
-> SlotId / ColorType
-> BeforeColor
-> CandidateColor这个抽象还能避免一个常见错误:只按数组位置回写颜色。一旦对象增删或服务返回顺序变化,位置映射就会错;稳定身份和槽标识才是可靠关联。
面试官:三组结果是怎样生成预览的?
客户端不会为了预览永久改三次地图。每个候选都按同一套步骤执行:保存相关对象的 beforeMap,临时应用 afterMap,用相同相机采集预览图,然后立即恢复原状态。用户确认后才把选中的 afterMap 作为一次编辑事务提交。
这里要重点保证两件事:
- 预览生成期间不触发不可逆保存,也不把临时状态暴露给其他编辑入口。
- 无论截图成功、失败还是页面退出,都执行恢复和资源清理,避免场景停留在某个候选状态。
面试官:确认换色后如何支持撤销和重做?
确认时记录完整的前后状态,而不是只记录“选中了第几个方案”。撤销应用 beforeMap,重做应用 afterMap,并把变更对象标记给地图自动保存系统。
原因是候选索引只在本次任务中有意义,任务缓存清理后无法重建;前后状态才是可持久、可验证的编辑事务。批量换色在用户语义上是一次操作,所以撤销栈也应只增加一个事务,而不是每个对象一条。
面试官:异步链路怎样处理超时、重复请求和页面退出?
任务状态机
Idle
-> Preparing
-> Uploading
-> Requesting
-> Downloading
-> Preloading
-> Ready
-> Applying
-> Completed
任意处理中状态 -> Failed / TimedOut / Cancelled -> Cleanup -> Idle我的处理原则是:
- 用任务身份隔离本次生成,回调先判断自己是否仍是当前任务。
- 请求期间禁用重复提交,并设置冷却,避免重复扣费和结果互相覆盖。
- 上传、请求、下载和预览各自有错误语义;服务繁忙与普通网络错误分开提示。
- 网络请求真正成功发出后再启动结果超时,避免把前置上传耗时误判成服务超时。
- 页面退出、断线、重连或新任务开始时,旧回调只能清理,不能再修改当前 UI 和场景。
- 收口到统一完成函数,负责停止定时器、复位请求标记、上报耗时和释放临时数据。
这里追求的是可重试和幂等消费,不会宣称异步网络链路能天然做到 exactly-once。
面试官:图片取色和主题词生成有什么区别?
主题词描述语义目标,例如“赛博朋克”或“冬日”;图片取色先从参考图提取色板,再把色板作为约束提交。两者共享后半段生成、下载、预览和确认链路,区别只在输入构建。
图片入口还受平台能力限制。相册访问、图片解码或云端运行环境不可用时,应显式隐藏或降级,而不是让用户进入一个必然失败的流程。
面试官:你个人负责到哪里?
我直接做的是客户端主链路,包括可换色对象采集、多颜色对象支持、主题词和色板入口、上传与请求编排、结果下载、候选预览、确认应用、撤销重做、自动保存、超时与重连处理、冷却、错误提示和数据上报。
算法如何生成配色、服务如何调度模型、内容审核规则如何制定,不是我独立负责的。我需要定义并联调输入输出契约,处理客户端失败恢复,但不会把算法效果归为个人实现。
面试官:为什么要把 UGC 图片转成 ASTC?
UGC 图片来源不受控,如果统一解码成 RGBA,磁盘体积、运行时显存、上传时间和加载峰值都会放大。ASTC 是移动 GPU 可直接采样的块压缩格式,可以在画质和体积之间选择块尺寸,减少运行时解压到未压缩纹理的压力。
但 ASTC 不是越小越好。块越大,体积通常越小,细节损失也越明显;块越小,质量更好但体积和带宽更高。选择时要结合图片用途、展示尺寸、平台支持和审核源图需求,而不是只追求压缩率。
面试官:ASTC 链路具体怎样做?
flowchart LR
SRC["UGC 原始图片"]
CHECK["尺寸 / 格式 / 安全检查"]
SMALL["小规格异步压缩"]
LARGE["大规格异步压缩"]
JOIN["汇合结果<br/>任一失败则整体失败"]
UPLOAD["上传并写入资源元数据"]
LOAD["运行时识别 ASTC<br/>检查设备能力并创建纹理"]
SRC --> CHECK
CHECK --> SMALL
CHECK --> LARGE
SMALL --> JOIN
LARGE --> JOIN
JOIN --> UPLOAD --> LOAD编码器把像素按块压缩,并在产物前写入 ASTC 文件头、块大小和纹理尺寸。运行时先识别格式与设备支持,再决定能否按 ASTC 像素格式创建纹理。原图或可审核格式仍要按内容安全链路保留;ASTC 是运行分发制品,不等于审核输入。
面试官:为什么要异步压缩,并且有两个压缩器?
压缩是 CPU 密集任务,直接放在游戏线程会卡住编辑和发布界面。发布又需要小图和大图两份产物,所以用两个独立异步任务并行执行,在汇合点统一判断成功或失败。
项目里对两种规格采用了不同的工作线程数,本质是在总核数约束下按任务体量分配预算。线程数不是写死后永远正确,还要评估目标机型、前后台状态、发热和与游戏线程的竞争。所有回调都完成后再释放压缩器,避免后台线程访问已经销毁的对象。
面试官:多线程压缩最容易出现什么问题?
主要有四类:
- 编码上下文或输出缓冲被多个任务错误共享。
- 外层对象销毁后,后台回调仍捕获悬空指针。
- 一个任务成功、另一个失败时,状态机提前进入上传。
- 取消或退出后只清理 UI,没有停止或隔离旧任务回调。
处理方式是让压缩任务持有明确生命周期,结果状态分别记录,只在汇合点推进;跨线程共享对象使用线程安全所有权;完成、失败和取消都走同一清理入口。客户端回调最终切回适合操作引擎对象的线程。
面试官:设备不支持 ASTC 怎么办?
发布数据要保留格式、尺寸和版本元信息,加载时先检查文件头和设备能力。支持时走 GPU 原生压缩纹理;不支持时必须有明确的兼容策略,例如选择其他制品或拒绝使用并给出可观测错误,不能把 ASTC 字节当普通图片强行解码。
我能确认项目中做了 ASTC 识别和设备能力判断。完整的全平台备用制品覆盖率没有现成报告,因此面试中会把“应有的降级设计”和“已验证的项目事实”分开说。
面试官:你怎样证明这项优化有效?
不能只看“能打开”。我会按四组指标验收:
| 维度 | 验收内容 |
|---|---|
| 质量 | 典型图片和极端细节图的主观对比,必要时补 PSNR/SSIM |
| 性能 | 编码耗时、游戏线程阻塞、加载耗时和峰值内存 |
| 资源 | 原图、ASTC 制品、传输字节和运行时显存占用 |
| 稳定性 | 低端机、取消、后台切换、失败重试、双任务部分失败和格式损坏 |
当时的明确问题是部分设备处理时间超过十秒,代码也能证明后来改成了异步并行和回调汇合;但缺少完整的改造前后基准表,所以现阶段不应该对外写具体百分比。
面试官:这两个案例给你最大的架构反思是什么?
第一,UGC 工具的难点不是把能力放进页面,而是把一次用户意图做成可恢复、可取消、可撤销、可观测的事务。AI 换色涉及网络与生成,ASTC 涉及多线程与制品,但本质上都需要明确状态机和统一清理。
第二,作者源、预览态和发布制品必须分开。原始地图与图片是作者数据,AI 候选只是预览,确认后才进入编辑真值;原图承担审核与重建,ASTC 承担运行分发。混淆这些角色会让撤销、审核、兼容和故障恢复全部变复杂。
第三,性能优化必须建立测量闭环。源码能说明用了异步、多线程和压缩格式,却不能替代基准数据。后续我会在方案立项时同步定义耗时、内存、体积、失败率和画质样本,避免只留下“做过优化”而没有可信结果。
快速背诵版
AI 换色
我负责的是 AI 换色客户端闭环:筛选可换色对象并记录颜色槽,采集场景图和结构化数据,上传并提交主题词或色板任务,下载三组候选,再通过临时应用、截图、恢复生成预览。用户确认后把整批改色作为一次可撤销事务提交,并进入自动保存。难点主要是多色对象映射、异步任务隔离、超时重连、页面退出后的回调清理,以及预览态不能污染编辑真值。算法和服务不是我实现的,我负责客户端协议、状态和体验闭环。
ASTC
我做 ASTC 是为了解决 UGC 图片在移动端的分发、显存和加载问题。我补了查看转码工具和端侧编码链路,把小图、大图压缩改成两个异步任务,全部完成后再上传;运行时识别 ASTC 头并检查设备支持。这里最重要的不是“用了 ASTC”,而是压缩任务不能阻塞游戏线程,多线程对象要安全持有,部分失败要统一收口,原图审核与运行制品也要分开。现有材料没有完整量化报告,所以我只陈述可核实的问题与机制。
责任边界
| 内容 | 面试表述 |
|---|---|
| AI 换色客户端主流程与持续迭代 | 可说“我负责/我实现” |
| 多色对象、候选预览、撤销重做、自动保存、异常处理 | 可说“我具体实现” |
| AI 模型、云端调度、审核策略 | 说“协作联调/上下游” |
| ASTC 查看转码工具、端侧压缩和上传接入 | 可说“我实现/推进” |
| ASTC 编解码库原理与完整平台降级 | 可解释设计,不冒充全部由我原创 |
| 未留存的压缩率、耗时和业务提升数字 | 不对外给具体数值 |