Node Forge 现在还不像一个完整产品, 更像一台边跑边焊的机器。
这篇不想写成技术白皮书, 也不想把 commit message 摊平了贴上来。它应该更像游戏的 dev log: 这一回做了什么, 为什么值得记一笔, 哪个地方最折磨人, 最后到底把哪条链路打通了。
目前项目分成两半:
node-forge: editor, DSL, desktop shellnode-forge-render-server: 真正负责渲染、headless 输出和测试基线
进度条
| 编号 | 时间 | 主题 | 这一回发生了什么 |
|---|---|---|---|
| #0 | 2026-03-03 | 开坑 | 先把骨架立起来 |
| #1 | 2026-02-19 ~ 2026-03-04 | Bloom | 终于有东西开始发光 |
| #2 | 2026-02-03 ~ 2026-02-17 | Gradient Blur | 不是更糊, 是更会糊 |
| #3 | 2026-01-07 ~ 2026-02-25 | Gaussian Blur | 最普通的节点, 最不该糊弄 |
| #4 | 2026-01-18 ~ 2026-01-20 | Instanced Draw | 项目第一次开始认真谈性能 |
| #5 | 2026-01-21 ~ 2026-02-28 | Color Space | 那层总也撕不掉的塑料膜 |
| #6 | 2026-02-20 ~ 2026-03-02 | HDR Pipeline | 把亮部从牢里放出来 |
| #7 | 2026-01-07 ~ 2026-02-20 | Headless Render | 把渲染从窗口里解放出来 |
Dev Log
2026-03-03 · Dev Log #0 · 开坑
如果只看表面, Node Forge 很像“一个节点编辑器 + 一个 renderer”。 但我真正想搭的, 其实是一条能从图编辑、到实时预览、再到离线输出都串起来的完整链路。也就是说, 它不只是拿来摆节点的 UI, 而是一块可以反复试验图形学想法的试验田。
所以这篇日志的目标也很明确: 不追求一次讲全, 只记录那些真正让项目往前拱了一下的更新。最好每一条都能回答一个问题: 这次到底把什么打通了?
2026-02-19 ~ 2026-03-04 · Dev Log #1 · Bloom: 终于有东西开始发光
我一开始把 Bloom 当成“抛光画面”的收尾效果, 结果做着做着发现, 它其实更像整条渲染链的测谎仪。 只要 Bloom 看起来不对, 基本就说明前面某个地方在撒谎: 要么亮部早就被压扁了, 要么 downsample / upsample 顺序不对, 要么合成阶段把能量吃掉了。
这一回真正落地的东西其实不少。编辑器这边先补了 Upsample、BloomNode、参数入口和示例场景, 让它至少能被摆出来、调起来。渲染器那边则要更脏一点: bloom shader、pass graph、纹理处理、kernel 调整、采样 clamp, 后面还把它拖进了相机、动画和 HDR 场景里继续打。
这条线做完之后最明显的变化, 不是“多了一个 node”, 而是画面第一次有了那种真的在发光的感觉。它开始不像一个只会把像素拼起来的 demo, 而像一个终于会处理亮度层次的 renderer。

2026-02-03 ~ 2026-02-17 · Dev Log #2 · Gradient Blur: 不是更糊, 是更会糊
普通 blur 的问题在于它太平均了。你让它模糊, 它就老老实实整片一起糊掉, 但很多时候我想要的不是“更模糊”, 而是“模糊应该往哪边长, 在哪儿停, 在哪儿突然变狠”。
所以这一回做的其实不是又一种 blur, 而是给 blur 加性格。前面先在测试和示例里反复折腾 blur-gradient 场景, 后面编辑器补上 GradientBlur 节点和例子, render-server 再把多 pass shader 生成、node compiler 注册和 schema 接起来。看上去像是一个点功能, 实际上动到的是整条 effect assembly 的组织方式。
最烦的地方是它的尺寸和采样范围不能只看自己。你得看最终是谁在消费这张图, 看几何区域怎么变, 看 UV 方向是不是又在某个环节悄悄翻了一次。最后能跑起来的时候, 我最满意的不是“效果图更花了”, 而是它终于从一锅端的 blur 变成了可以写镜头语言的 blur。

2026-01-07 ~ 2026-02-25 · Dev Log #3 · Gaussian Blur: 最普通的节点, 最不该糊弄
Gaussian Blur 是那种很容易被低估的功能。因为“做一个模糊”听起来太简单了, 简单到像是任何 renderer 都理应自带的默认配置。
但真开始做就会发现, 麻烦根本不在“能不能糊”, 而在谁负责分辨率、输入到底该是 image 还是 pass、sigma 大到什么程度还值得继续加 tap, 还有 blur 该不该为了别的效果提前让出抽象边界。
这一段提交记录看起来也很诚实: 先有 GuassianBlurPass 节点和 UI, 再补 pipeline、WGSL case 和采样修正, 后面一轮一轮把输入类型改掉、对 downsample factor = 1 做优化、调大 sigma 的 tap count、再让它能从依赖里反推分辨率。完全不是“一次做完”, 而是一块基础设施慢慢被磨平的过程。
现在回头看, Gaussian Blur 真正的价值不是它自己, 而是后面很多东西终于可以放心站在它身上了。Gradient Blur 站上来了, Bloom 也站上来了, 一堆 blend case 也跟着站上来了。

2026-01-18 ~ 2026-01-20 · Dev Log #4 · Instanced Draw: 项目第一次开始认真谈性能
做到 instancing 这里的时候, 项目的气质其实变了一下。 前面很多工作都还是“先让它成立”, 到这一步开始出现另一种问题: 如果场景里重复物体变多, 你还打算一个一个 draw 下去吗?
所以这条线一上来就不是为了好看, 是为了不那么贵。DSL 和编辑器补了 instancing zone、TransformGeometry、SetTransform、边界警告和示例, render-server 则继续往下接 Index、实例化相关类型、stage-aware 编译和实例矩阵烘焙。很明显, 这不是一个孤立功能, 而是图结构和执行模型都要一起改。
我还挺喜欢这段历史里一个很朴素的判断: instancing 最怕偷偷越界。编辑器如果不早点把 zone boundary 卡严, 到 renderer 里你根本不知道自己读到的是 per-vertex 还是 per-instance。也就是说, 这一步做的不是“快一点”, 而是先把“哪些东西允许一起快”说清楚。
2026-01-21 ~ 2026-02-28 · Dev Log #5 · Color Space: 那层总也撕不掉的塑料膜
颜色空间问题最讨厌的地方在于, 它通常不会让画面直接炸掉。 它只会让一切都“差一点”: 图是对的, 但不透; 颜色是对的, 但不亮; alpha 也在工作, 但混起来像隔着一层塑料膜。
这一段的提交记录基本就是在和这种塑料膜搏斗。render-server 先补 colorspace controls、测试、image encoding 稳定化和 premultiplied alpha, 编辑器再把 ImageTexture 的 encoding / alpha 选项露出来, 后面继续推进 straight-alpha 预乘、HDR alpha clamp 和一大堆基线修正。表面看起来只是“多了几个选项”, 其实是在把一套原来模模糊糊的默认行为钉死。
这种活儿最不性感, 但特别要命。因为它不解决, 后面任何更炫的效果都会有一种底子发虚的感觉。Bloom 会糊, blend 会脏, 参考图比对也会开始变得不可信。
2026-02-20 ~ 2026-03-02 · Dev Log #6 · HDR Pipeline: 把亮部从牢里放出来
HDR 这一回的体感特别强。它不是“画面更亮了”, 而是终于不再急着把所有高亮信息一把按回 LDR 里。
这条线一旦开工, 改动就很难只停在 renderer 内部。渲染器这边要补 rgba16float、half、EXR 输出、HDR-native presentation、display encoding; UI 那边也得跟上 HDR 指示器、clamp 切换、diff 统计和观察工具。再往后, 还得把 export texture 和 present texture 拆开, 因为“拿来显示的那套东西”和“拿来导出的那套东西”根本不是同一个问题。
HDR 真正麻烦的地方, 是它很容易把项目里原本模模糊糊的约定全部逼出来。颜色空间到底怎么走, alpha 到哪一步该 clamp, clipboard / export 能不能偷走现场显示的纹理, 这些之前还能糊过去的事, 到这里都糊不过去了。它像一次系统级体检, 把很多旧问题一起照出来。

2026-01-07 ~ 2026-02-20 · Dev Log #7 · Headless Render: 把渲染从窗口里解放出来
一旦开始想导图、做 baseline、做自动化测试, “必须开着窗口盯着看”就会突然显得很原始。 于是 headless render 这条线很自然就冒出来了: 既然 renderer 本来就在做同一件事, 那它就不该只能挂在 UI 后面当发动机罩里的零件。
这段时间里, 桌面端先接了外部 renderer 进程管理、连接开关、输出目录选择和 render-to-file。render-server 这边继续往下补 headless 生命周期、--output CLI、DSL json render cases、窗口尺寸推导测试, 后来又把 EXR 输出也并进来。也就是说, 这不是“额外支持一个命令行参数”, 而是让整条渲染链第一次可以脱离交互界面独立存活。
这条线我特别喜欢, 因为它会强迫很多偷懒做法现形。没有窗口以后, 尺寸从哪来, 输出目标由谁决定, 资源什么时候释放, WebSocket 心跳和 shutdown 谁先谁后, 每一个都不能再靠“反正 UI 在那儿”混过去。它像是把系统从试玩版拉向工具版的那一步。
以后怎么记
后面如果继续写, 我想保持这种粒度: 不把每个 commit 都拿出来邀功, 只记那些真的让项目气质发生变化的更新。
大概还是会保留这四个问题:
- 这次想解决什么
- 真正动到了哪几层
- 最难缠的坑是什么
- 做完之后, 项目哪里终于不一样了