90 美元搞定 20 个 Awwwards 级 3D 网站:Dioramas 电影级交互架构与 AI 资产管线全景解析
在传统 Web 3D 开发中,打造一个 Awwwards 级别的交互式 3D 网站往往意味着高昂的工期与人力成本:专业的 3D 建模师进行高模雕刻与拓扑、资深技术美术(TA)烘焙 PBR 贴图、前端工程师手工编写着色器与运镜逻辑,单页研发成本动辄数万美元。而开源框架 Dioramas 的诞生彻底打破了这一壁垒。
Dioramas 提出了一种革命性的全栈范式——“让 3D 场景成为网页本身”。它不仅开源了 20 个涵盖深海潜航、机械发条、粒子风暴、物理烘焙等极具视觉震撼力的完整落地站点,更首次将 Nano Banana 2 图像生成、Meshy 7.1 图生 3D、自动化几何拓扑压制以及现代 Three.js HDR 渲染核心串联为高度工业化的闭环管线。令人惊叹的是,生成全套 20 个网站所需的 65 个高质量 3D 模型与 111 张材质板,总 API 账单仅约 90 美元。本文将深入工程源码,对 Dioramas 的资产管线、渲染核心与代理工作流进行全景拆解。
一、范式重塑:为什么 3D 场景应当“成为网页本身”?
在过去十余年里,绝大多数 Web 3D 网站的设计思路本质上都是“在网页底层垫一个 WebGL Canvas”,上方覆盖传统的 HTML 滚动长图文,或者把 3D 当作一个封闭的 iframe 交互挂件。这种割裂感带来了两大顽疾:
- 叙事与动线脱节:页面的滚动节奏与 3D 相机运镜缺乏有机呼应,用户在阅读文字时视线与 3D 元素互相争抢焦点;
- 性能与质感失衡:为了迎合轻量化往往牺牲材质与光影,导致 3D 资产呈现出廉价的塑料感和灰暗的无环境光质感。
Dioramas 的核心哲学是将每个落地页构想为一个微缩景观(Diorama):
- 场景即页面:页面没有冗杂的多层嵌套与漫无目的的长卷轴。整个网站的视觉中心就是一个超高精度的核心资产;
- 滚动即运镜:滚动不是文本的简单位移,而是驱动摄像机在精密编排的三维轨迹(Camera Choreography)中穿梭,每一处停驻点都是一张经过严格黄金分割构图的电影海报;
- 签名级触控交互(Signature Interaction):每个世界仅保留一个极其契合世界观的触控/鼠标交互。例如在深海探险页中鼠标即潜水器探照灯光束、在锻造工坊中滑动鼠标敲击大马士革钢迸发粒子火花、在甜品工坊中实时计算刚体动力学揉捏马卡龙。
flowchart TD
subgraph Pipeline ["Dioramas 工业级生产管线"]
A["创意企划 Brief<br/>(Markdown 规范文档)"] --> B["AI 图像生成<br/>(Nano Banana 2 @ fal)"]
B --> C["图生 3D PBR 模型<br/>(Meshy 7.1 @ fal)"]
C --> D["几何与材质轻量化压缩<br/>(@gltf-transform + meshopt + sharp)"]
D --> E["Three.js HDR 渲染核心<br/>(src/core/engine.js)"]
E --> F["AI Coding Agent 页面装配<br/>(Lenis + GSAP + Rapier3D)"]
F --> G["Playwright 无头 GPU 自动化质检<br/>(RTX 4090 帧率与构图审查)"]
end
二、资产工业化管线:Prompt 到轻量化 GLB 的全自动流水线
Dioramas 最具启发性的工程实践,在于其建立了一套高容错、可断点续算且成本极其低廉的资产生成流水线(scripts/gen.mjs 与 scripts/optimize.mjs)。
1. 从 Nano Banana 2 到纯白棚拍级产品板
要让 AI 生成的模型具备工业级工业品或艺术品的一致性,输入给 3D 重建算法的 2D 参考图必须绝对纯净。Dioramas 在 scripts/gen.mjs 中定义了一段极其严苛的工程级负向与正向样式后缀(STYLE_SUFFIX):
const STYLE_SUFFIX =
' Single isolated object, centered, full object visible with generous margin, ' +
'three-quarter view from slightly above, plain pure white seamless studio background, ' +
'soft even diffuse lighting, no cast shadows on background, no text, no watermark, ' +
'ultra detailed, sharp focus, product-render clarity, physically plausible materials.';
通过这套提示词规范,Nano Banana 2 输出的图片具备三大特征:
- 零底色污染:纯白无缝影棚背景,彻底杜绝阴影被图生 3D 算法误判为物体几何突起;
- 俯角 45 度视角(Three-quarter view):最大化暴露物体的正面、侧面与顶面结构,为单目深度与几何重建提供最丰富视差信息;
- 真实物理材质(PBR Priors):高光反射与粗糙度过渡符合物理法则,为后续贴图生成打下基底。
2. Meshy 7.1 拓扑重构与状态事务登记
得到参考图后,流水线调用 fal.ai 托管的 meshy/v7.1/image-to-3d 接口。Dioramas 设置目标面数通常为 150,000 三角面,启用 geometry_resolution: '4k' 并开启全套 PBR 材质(法线贴图 Normal Map、粗糙度 Roughness、金属度 Metallic 与基础色彩 BaseColor)。
为了防止网络震荡、进程崩溃导致的重复消费,Dioramas 在 scripts/gen.mjs 中设计了基于 assets/manifest.json 的状态事务锁:
// 发起生成前,先将任务 ID 与状态原子写入本地清单
let requestId = entry?.request_id && !force.has(job.id) && entry.status !== 'failed'
? entry.request_id
: null;
if (!requestId) {
const sub = await fal.queue.submit(endpoint, { input });
requestId = sub.request_id;
await updateManifest(m => {
m.meshes[job.id] = { request_id: requestId, status: 'pending', at: new Date().toISOString() };
});
}
即便构建任务在轮询期间被 Ctrl+C 强行终止,下次重启脚本时也会直接复用该 request_id 进行拉取,单次生成的成本损耗被严格锁定在理论极小值。
3. 几何重组与纹理压制:25MB 到 3MB 的极限瘦身
Meshy 原始输出的 GLB 往往体积庞大(20MB~45MB),且包含大量未焊接顶点与未压缩的高清 PNG 贴图,根本无法直接部署在公网。Dioramas 在 scripts/optimize.mjs 中编排了基于 @gltf-transform 和 meshoptimizer 的极端压缩流水线:
// scripts/optimize.mjs 核心压缩流程
const doc = await io.read(input);
const ops = [
dedup(), // 去除重复属性与访问器
weld(), // 顶点焊接,合并共面几何缝隙
];
if (ratio < 1) {
// 基于误差阈值的自适应网格减面
ops.push(simplify({
simplifier: MeshoptSimplifier,
ratio,
error: 0.0008,
lockBorder: false
}));
}
ops.push(
// 材质贴图转码:PNG 暴力压缩为质量 88 的 WebP,尺寸重采样为 2048x2048
textureCompress({ encoder: sharp, targetFormat: 'webp', resize: [tex, tex], quality: q }),
prune(), // 剪除未被场景引用的空节点与材质
reorder({ encoder: MeshoptEncoder }), // 优化顶点缓存局部性(GPU Cache Locality)
quantize({ quantizePosition: 16, quantizeNormal: 10, quantizeTexcoord: 14 }), // 坐标量化
);
await doc.transform(...ops);
// 最终应用 Meshopt 二进制流压缩
await doc.transform(meshopt({ encoder: MeshoptEncoder, level: 'medium' }));
这套组合拳达成了极其惊人的效果:
- 几何顶点坐标由 32 位浮点数量化为 16 位/10 位定点整数;
- 贴图体积缩减 75% 以上且无肉眼可见的色彩失真;
- 模型整体文件体积从 25MB 骤降至 3~8MB,首次加载时间缩短至秒级。
三、渲染核心架构:如何让 AI 资产散发电影级质感?
AI 生成的模型常常被诟病“缺乏灵魂”、“光影呆滞”。Dioramas 在 src/core/engine.js 中构建了一个现代 Three.js 渲染内核,其核心奥秘在于将电影后期级调色(Color Grading)与物理体积光学完全融合。
1. 延后色调映射(Deferred Tone Mapping)管线
在传统的 Three.js 教学案例中,开发者往往直接在渲染器上开启 renderer.toneMapping = THREE.ACESFilmicToneMapping。但 Dioramas 坚决将主渲染器的色调映射设为 NoToneMapping,统一将色调映射延迟到后处理(Post-processing)阶段:
// src/core/engine.js
this.renderer = new THREE.WebGLRenderer({
canvas, antialias: false, alpha, stencil: false, depth: true,
powerPreference: 'high-performance',
});
this.renderer.outputColorSpace = THREE.SRGBColorSpace;
this.renderer.toneMapping = THREE.NoToneMapping; // 核心:保持全流程 HDR 浮点精度
在后处理合成器中,Dioramas 使用了 HalfFloatType(16 位浮点 HDR 纹理)作为全流程缓冲区:
- HDR 空间特效阶段:先执行 N8AO(高保真环境光遮蔽)与 8 级 Mipmap Bloom(物理辉光)。由于此时所有发光像素均处于 1.0 以上的真实物理亮度区间,辉光的扩散半径与柔和度极其自然;
- 色调映射阶段:应用当前影视工业界公认最高动态范围的 AgX 或 ACES Filmic 色调映射,将超高动态范围平滑压缩至 SDR 显示器;
- 显示空间特效阶段:紧随色调映射之后叠加径向色差(Chromatic Aberration)、微粒胶片噪点(Film Grain)与暗角(Vignette)。
[!IMPORTANT]
色差采样避坑经验:Dioramas 团队在迭代中踩过一个深度坑——ChromaticAberrationEffect在底层会直接采样其输入缓冲区。如果将色差与泛光放在同一渲染 Pass 中,色差的红蓝分量通道会去采样未经过色调映射的原始 HDR 缓冲区,导致高光边缘产生刺眼的色彩炸裂。Dioramas 的解决方案是在 Tone Mapping 之后开辟独立的单通道 EffectPass 执行色差着色。
graph LR
subgraph HDR ["HDR 浮点空间 (HalfFloatType)"]
A["场景几何渲染<br/>RenderPass"] --> B["环境光遮蔽<br/>N8AO PostPass"]
B --> C["多层级泛光<br/>Mipmap Bloom"]
C --> D["光线步进体积光<br/>Volumetric Beams"]
end
subgraph Tone ["色调映射节点"]
D --> E["AgX / ACES<br/>ToneMappingEffect"]
end
subgraph SDR ["显示空间 (Display Space)"]
E --> F["独立色差 Pass<br/>Chromatic Aberration"]
F --> G["胶片颗粒 & 暗角<br/>Noise & Vignette"]
G --> H["子像素抗锯齿<br/>SMAAEffect"]
end
2. 深度感知的光线步进体积聚光灯(Volumetric Spotlights)
在 examples/abyssal(深海)与 examples/reliquary(暗室遗物)中,光束穿透黑暗的丁达尔效应令人叹为观止。Dioramas 在 src/core/volumetric.js 中手写了一套定制的 GLSL 光线步进着色器:
// src/core/volumetric.js 片元着色器核心截断逻辑
void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth, out vec4 outputColor) {
// 从深度缓冲反推场景三维世界坐标
vec4 clip = vec4(uv * 2. - 1., depth * 2. - 1., 1.);
vec4 vp = uProjInv * clip; vp /= vp.w;
vec3 wp = (uCamWorld * vec4(vp.xyz, 1.)).xyz;
vec3 ro = uCamPos;
vec3 rd = wp - ro;
// 核心约束:步进步长严格截止于场景实际几何深度,绝不穿模渗透
float len = min(length(rd), uMaxDist);
rd = normalize(rd);
const int STEPS = 32;
float stepL = len / float(STEPS);
float jitter = fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));
vec3 acc = vec3(0.);
for (int i = 0; i < STEPS; i++) {
float t = (float(i) + jitter) * stepL;
vec3 p = ro + rd * t;
// 叠加三维空间风场与漂移粉尘噪声
vec3 q = p * uNoiseScale + uWind * uTime;
float n = vnoise(q) * 0.65 + vnoise(q * 2.7 + 7.1) * 0.35;
// 计算聚光灯圆锥衰减与距离反比衰减
// ...
}
outputColor = vec4(inputColor.rgb + acc, inputColor.a);
}
这套算法通过在光线向量上引入抖动(Jittering)消除色带,同时将最大采样距离限制在由深度图反解出的世界坐标点,确保光束照在模型表面时会自然中断,真实再现水下探照灯与影棚射灯的物理质感。
3. 基于斜截投影矩阵的平面粗糙度反射(Planar Reflections)
在展示大马士革钢刀、机甲地表或法式甜品大理石台面时,地面的镜面反射是支撑场景真实感的支柱。Dioramas 在 src/core/reflector.js 中没有采用昂贵的全场景 SSR(屏幕空间反射),而是采用了计算机图形学大师 Eric Lengyel 经典的斜截近平面投影技术(Oblique Near-Plane Clipping):
- 创建一个沿地表法线对称的镜像虚拟摄像机(Virtual Mirrored Camera);
- 修改投影矩阵的近裁剪平面,使其与地表几何平面严格重合,彻底剔除地表下方的所有物体,防止水下或地底杂物漏入反射贴图;
- 将镜像场景渲染至具备 Mipmap 的 HDR 渲染目标(
WebGLRenderTarget)中; - 地表 Shader 采样反射纹理时,直接将材质自身的粗糙度贴图(Roughness Map)映射为纹理采样的 LOD 级别(
texture2DLod(uRefl, uv, roughness * lodScale))。这意味着粗糙地表呈现的柔和漫反射模糊几乎零额外开销。
四、AI Coding Agent 的工程化工作流与无头视觉审查
除了代码框架本身,Dioramas 最具借鉴意义的是其“人机协同开发范式”。仓库中的 20 个完整世界并非由单个程序员手工一行行调试完成,而是由 AI 编码智能体(AI Coding Agent)在严格的工程框架下驱动完成。
1. 从 Brief 到 Code 的标准化闭环
每个世界在立项之初,人类创作者仅需编写一份清晰的技术与艺术企划案(docs/briefs/<name>.md),涵盖:
- 世界观设定与核心隐喻;
- 签名级触控交互(Signature Interaction);
- 滚动分段与运镜编排(Camera Choreography);
- 材质、调色与字体设计要求(Art Direction)。
智能体读取 Brief 与 docs/ENGINE.md 后,直接基于 Engine、Assets、Pointer、smoothScroll 进行单文件组装。
2. Playwright + GPU 无头视觉审查矩阵
AI 智能体无法直观“看见”浏览器渲染效果,这是过往 AI 编写 3D 页面最大的痛点。Dioramas 通过 scripts/review.mjs 打造了完整的视觉反馈回路(Visual QA Loop):
- 真实 GPU 无头渲染:利用 Playwright 启动 Chrome,开启
--enable-gpu、--use-angle=d3d11与--enable-unsafe-webgpu,在本地 RTX 4090 或云端 GPU 实例上进行纯真机渲染; - 多步滚动定格抓拍:脚本自动按照
stops = [0, 0.12, 0.25, 0.4, 0.55, 0.7, 0.85, 1.0]在每一个关键运镜停驻点自动模拟滚动、注入鼠标位移,并在沉降(Settle)2.2 秒后抓取高清 PNG; - 移动端双重视口测试:模拟 390x844 竖屏视口,测试页面在触屏环境下的排版与性能;
- 拼接接触印样(Contact Sheet):调用
sharp将全流程屏幕截图平铺拼合成一张宽幅高清晰审查图(shots/review/<slug>.jpg),并输出全局控制台错误与平均帧率(FPS)。
人类艺术总监或视觉多模态智能体只需扫一眼接触印样,即可在几秒钟内发现镜头穿模、文字遮挡、光影过暗等缺陷,并指示智能体针对性修正。
五、现代 Three.js(r186)前线避坑实录
Dioramas 紧跟 Three.js 现代化版本(r186+),在源码注释与开发日志中沉淀了极具价值的第一手避坑经验:
| 陷阱场景 | 底层根因 | Dioramas 标准避坑方案 |
|---|---|---|
| 软阴影类型失效 | PCFSoftShadowMap 在 Three.js r186 中被官方正式废弃并移除 |
统一采用 THREE.PCFShadowMap,通过精细调节光源的 light.shadow.radius 与 bias 消除条纹与锯齿 |
| 环境光贴图强度无响应 | r186 中 material.envMapIntensity 仅在材质显式绑定独立 envMap 时生效;全局使用 scene.environment 时该属性失效 |
废弃逐材质调节环境光强度的旧逻辑,统一通过全局 scene.environmentIntensity 进行动态光照平衡 |
| 透射玻璃折射出白色死区 | 玻璃的 Transmission 材质物理折射会采样背景清除色;若后处理管线 clear alpha 为 0,会折射出白屏 | 任何包含玻璃材质的场景,必须为 scene.background 赋予实体底色或放置不可见的背景挡板(Backdrop Mesh) |
| 手机竖屏 3D 主体被文字遮挡 | 移动端横向空间狭窄,模型居中会导致其与说明文案完全叠合 | 调用 camera.setViewOffset 实施镜头光学平移(Lens Shift),在不破坏透视视角的前提下将模型优雅上移至屏幕上半区 |
六、总结与技术启示
Dioramas 不仅仅是一个 3D 样板间集合,更是一次关于 “AI 如何重塑创意前端工程” 的教科书级演示:
- 单点突破的经济学:以前制作 65 个定制 PBR 3D 资产需要数月时间与昂贵预算,现在通过 Nano Banana 2 + Meshy 7.1 管线,不到 100 美元与几个小时即可全部交付;
- 底层引擎的复用价值:资产虽然来自 AI 生成,但最终决定视觉品质高度的是稳固、严谨的着色器与后期管线。HDR 缓冲区、AgX 色调映射、体积光线步进与平面粗糙度反射构成了坚不可摧的视觉护城河;
- 闭环自动化的开发范式:从企划 Markdown、智能体装配、无头 GPU 截屏矩阵到接触印样审查,全流程自动化让创意迭代的周期被压缩到了分钟级。
对于每一位渴望探索空间计算、次世代创意官网与 AI 资产工程化的开发者而言,Dioramas 的源码库无疑是一座值得深入挖掘的宝藏。
原文链接与参考资料
- 项目开源仓库:blendi-remade/dioramas on GitHub
- Three.js 核心引擎:three.js documentation
- 模型管线优化库:@gltf-transform by Don McCurdy
- 高动态色调映射:AgX Tone Mapping by Troy Sobotka