索引
- 引子
- 功能
- 架构
- 风格
- 应用
- 未来
引子
那些活跃的开源项目
- Babylon.js
一个==完整==的JavaScript框架,用于构建HTML5,WebGL,WebVR和Web Audio的3D游戏和体验。
- PlayCanvas
PlayCanvas是一个开源游戏引擎。它使用HTML5和WebGL在所有==现代==浏览器中运行游戏和其他==交互==式3D内容,而无需插件。
- ClayGL
ClayGL是一个用于构建==可扩展==Web3D应用程序的WebGL图形库。
它易于使用,可配置高质量图形效果。受益于==模块化==和tree shaking,它可以缩小到22k(gzip),用于基本的3D应用程序。
目前主要应用到echarts中。
- Three.js
该项目的目的是创建一个==易于使用==,==轻量级==的3D库。该库提供Canvas 2D,SVG,CSS3D和WebGL渲染器。
Zen3D一开始模仿threejs的WebGL渲染库
初始动机:学习WebGL,学习3D渲染。
从学习相机的==矩阵变换原理==与==简单光照模型==开始。
图书推荐:WebGL编程指南
Three.js 最火
- 年头最早?最稳定?最活跃?
- 只做渲染,不做其它
功能
大城小胖提出的钳子锤子理论
2016年,国内Html5游戏引擎竞争激烈:
- cocos-html5 (后改名cocos-js)
- Egret Engine
- LayaBox
各方以推出完善工具流为目标。
“你要是想用我的钳子,必须也买我的锤子”这是一种霸道做法。
他为了宣扬自己的理论,在github上发布了一个叫The Best JavaScript Game Framework的项目。
他的核心思想是:
Do More with Less. 做的事情越少,能做的事情越多。
局限性:
- 仅适用于架构程序员。对脚本程序员或非程序员,需要全面的配套服务。但这是上层需求,是“工具”应该做的事而非底层库。
- 当然不是单纯越少越好,满足通用需求是核心价值。
结论:Threejs由于只实现了核心功能,不搞x大包x大揽,所以能应用到更多的领域,另外,也让它更容易理解和使用。
问题:Threejs的核心x价值是什么?
Three的核心价值
重新审视Three.js
只干了两件事:
- Graph Tree 场景树管理
- Render 渲染
实际上在做什么:
graph TB
3D场景树 --> 一维渲染列表
3D场景树 --> 相机
相机 --> 2D图像
一维渲染列表 --> 2D图像
场景树管理模块
无关渲染API
- 解决的问题
- 怎样描述3D场景(人容易看懂)
- 怎样描述渲染列表(机器容易看懂)
3D场景的描述规范:
graph TB
场景-->物体1
场景-->物体2
物体1-->物体3
物体1-->物体4
物体的描述规范:
graph TB
物体-->形状
物体-->材质
渲染列表:
[{画物体1}, {画物体3}, {画物体2}, ...]
渲染器模块
利用WebGL渲染API进行渲染。
graph TB
读取顶点数据-->执行顶点着色器
执行顶点着色器-->组装图元
组装图元-->光栅化图元
光栅化图元-->执行片段着色器
执行片段着色器-->写入帧缓冲区
单次渲染(one pass)流程与WebGL接口强相关,相对固定。
架构
反思
Threejs在架构上有什么改进的空间?
threejs的Renderer包含了太多的东西。
也许是因为要兼容多种渲染模式造成的。
Three.js封装的Renderer
当你调用render的时候:
renderer.render(scene, camera, target);
实际上做了这些事:
- 更新场景中所有物体的矩阵
- 生成渲染列表(分类,收集, 视锥裁剪,排序...)
- 执行渲染
显然threejs将场景树的更新与渲染做到了一个函数中。
后期与延迟渲染中常常遇到的场景
graph LR
场景-->物体
物体-->形状
物体-->材质1
在后期或延迟渲染中,可能需要替换每个物体的材质(shader),并执行一次渲染
graph LR
场景-->物体
物体-->形状
物体-->材质2
根据物体属性不同,可能替换的材质还不一样
Threejs Renderer做的事情太多了
scene.traverse(object => {
// change material1
});
renderer.render(scene, camera, target);
scene.traverse(object => {
// change material2
});
renderer.render(scene, camera, target);
// ...
实际上:
- 遍历场景替换材质1(遍历浪费)
- 更新场景中所有物体的矩阵
- 生成渲染列表(分类,收集, 视锥裁剪,排序...)
- 执行渲染
- 遍历场景替换材质2(遍历浪费)
- 更新场景中所有物体的矩阵(浪费)
- 生成渲染列表(分类,收集, 视锥裁剪,排序...)(浪费)
- 执行渲染
- ...
如果拆分开Renderer
scene.updateMatrix();
const renderList = getRenderList(scene, camera);
// pass 1
renderer.render(renderList, camera, {
ifRender: item => {
return true;
},
getMaterial: item => {
// 这里可以通过item.object动态判断使用哪种材质
return material1;
}
});
// pass 2
renderer.render(renderList, camera, {
ifRender: item => {
return true;
},
getMaterial: item => {
// 这里可以通过item.object动态判断使用哪种材质
return material2;
}
});
实际上:
- 更新场景中所有物体的矩阵
- 生成渲染列表(分类,收集, 视锥裁剪,排序...)
- 使用材质1渲染
- 使用材质2渲染
能很方便地实现后期处理,前向渲染器/延迟渲染器。
项目风格
项目的语言选择与是否激进。
风格
- ES6但不选择 TypeScript CoffeeScript 等编译语言。
Babylon采用ts开发,一定程度上减小了开发者的受众人群。
- 优先使用新特性(Extensions & WebGL2)但适当兼容。
Babylon在对WebGL2的支持上相对较好,因此它有更强大的粒子系统,更好的渲染效果,更高的性能。
当前大部分浏览器已经支持WebGL2,但很少渲染器能很好利用新特性并做到适当兼容。
WebGL2的粒子 babylon webgl2 babylon webgl2 color Grading
应用
- 3D开发引擎 babylon
- ECS架构的重度3D开发引擎 PlayCanvas,Unity
- 非专业程序员使用的脚本绘图工具 P5.js
- 模型展示器,可以实现方便的后期处理模块 ClayGL Sketchfab
- WebGL新特性探索
graph BT
渲染器-->3D游戏引擎
渲染器-->3D应用引擎
渲染器-->模型展示器
渲染器-->绘图画板
渲染器-->等等
未来
- 与上游工具的联动
graph TB
用户 --> 粒子编辑工具
用户 --> 材质编辑工具
用户 --> 场景搭建工具
用户 --> 逻辑组织工具
粒子编辑工具 --> 3D场景树
材质编辑工具 --> 3D场景树
场景搭建工具 --> 3D场景树
逻辑组织工具 --> 3D场景树
3D场景树 --> 一维渲染列表
3D场景树 --> 相机
相机 --> 2D图像
一维渲染列表 --> 2D图像
- 安利