#爱播爱播最新地址 视频 官方 https://455555.xyz
一个面向现代浏览器的极简 WebGL 2.0 场景图渲染引擎。
无依赖 · 零抽象泄漏 · 原始着色器控制权
TinyGL 是一款轻量级的 WebGL 3D 渲染引擎,围绕**场景图(Scene Graph)**模式构建,专为需要在浏览器中实现高质量 3D 渲染的开发者设计。不同于 Three.js 的全功能框架路线,TinyGL 追求的是:
- 极小体积 — 核心库 gzip 后约 12 kB,适合嵌入式与移动端场景
- 无隐藏开销 — 所有渲染路径可追溯,不引入不可见的 draw call
- 原生着色器 — GLSL 代码完全由开发者掌控,引擎仅提供 uniform 绑定与 varying 管道
- WASM 友好 — 数学库核心路径预留 WASM 编译接口(目前以 JS TypedArray 实现)
TinyGL 的设计哲学受 Brutalism(粗野主义) 风格影响:不修饰、不包装、不做过度抽象。API 暴露底层 WebGL 调用语义,让开发者对每一步 GPU 指令都有清晰认知。
| 场景 | 说明 |
|---|---|
| 3D 数据可视化 | GIS、点云、科学计算渲染 |
| 产品配置器 | 轻量嵌入式 3D 展示 |
| 创意编码 | Shader art、生成艺术、互动装置 |
| 教育/原型 | 理解 WebGL 管线与 3D 数学的教学工具 |
┌─────────────────────────────────────────────────────────┐
│ Application Layer │
│ (用户代码 / 游戏逻辑 / 交互控制) │
├─────────────────────────────────────────────────────────┤
│ Scene Graph API │
│ Scene ──┬── Group ──┬── Mesh (Geometry + Material) │
│ │ └── Light (Point / Directional) │
│ └── Camera (Perspective / Orthographic) │
├─────────────────────────────────────────────────────────┤
│ Render Pipeline │
│ Culling ──▶ Sorting ──▶ Uniform Upload ──▶ Draw Calls │
├──────────┬──────────────────────┬────────────────────────┤
│ Math Lib │ Shader System │ WebGL 2.0 Backend │
│ mat4 │ Vertex Shader (GLSL)│ VAO / VBO / FBO │
│ vec3 │ Fragment Shader │ Texture Units │
│ vec4 │ Uniform Binder │ Blend / Depth / Stencil│
│ quat │ Varying Pipeline │ MSAA / MRT (WIP) │
├──────────┴──────────────────────┴────────────────────────┤
│ Platform / Build │
│ esbuild (bundle) · npm (publish) · Tape (test) │
└─────────────────────────────────────────────────────────┘
npm install tinygl-engine以下代码展示了一个完整的 TinyGL 场景搭建流程:创建渲染器、定义几何体、编写着色器、挂载到场景图并启动渲染循环。
import { TinyGL, Scene, PerspectiveCamera, Mesh, BoxGeometry, mat4 } from 'tinygl-engine';
// ── 1. 初始化渲染器 ──
const canvas = document.getElementById('viewport');
const renderer = new TinyGL(canvas, {
antialias: true,
alpha: false,
powerPreference: 'high-performance'
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x0a0a0a, 1.0);
// ── 2. 创建场景与相机 ──
const scene = new Scene();
const camera = new PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);
camera.lookAt(0, 0, 0);
// ── 3. 定义着色器材质 ──
const material = new ShaderMaterial({
vertexShader: `
attribute vec3 aPosition;
attribute vec3 aNormal;
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat4 uNormalMatrix;
varying vec3 vNormal;
varying vec3 vWorldPos;
void main() {
vec4 worldPos = uModelMatrix * vec4(aPosition, 1.0);
vWorldPos = worldPos.xyz;
vNormal = mat3(uNormalMatrix) * aNormal;
gl_Position = uProjectionMatrix * uViewMatrix * worldPos;
}
`,
fragmentShader: `
precision mediump float;
varying vec3 vNormal;
varying vec3 vWorldPos;
uniform vec3 uLightDir;
uniform vec3 uBaseColor;
void main() {
vec3 N = normalize(vNormal);
vec3 L = normalize(uLightDir);
float diff = max(dot(N, L), 0.0);
float ambient = 0.15;
vec3 color = uBaseColor * (ambient + diff * 0.85);
gl_FragColor = vec4(color, 1.0);
}
`,
uniforms: {
uLightDir: { value: [1.0, 1.5, 2.0] },
uBaseColor: { value: [0.85, 0.22, 0.12] }
}
});
// ── 4. 创建网格并挂载到场景 ──
const geometry = new BoxGeometry(2, 2, 2);
const mesh = new Mesh(geometry, material);
// 使用 mat4 进行变换
mat4.translate(mesh.localMatrix, mesh.localMatrix, [0, 1, 0]);
mat4.rotateY(mesh.localMatrix, mesh.localMatrix, performance.now() * 0.001);
scene.add(mesh);
// ── 5. 渲染循环 ──
function animate(time) {
requestAnimationFrame(animate);
// 动态旋转
mat4.rotateY(mesh.localMatrix, mat4.create(), time * 0.001);
mat4.rotateX(mesh.localMatrix, mesh.localMatrix, time * 0.0005);
renderer.render(scene, camera);
}
animate(0);
// ── 6. 响应窗口尺寸变化 ──
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});TinyGL 的着色器系统采用 显式声明 模式,不自动注入任何 uniform 或 attribute。开发者需要自行在 GLSL 中声明所有变量,引擎负责将 JavaScript 侧的 uniform 值绑定到 GPU。
┌──────────────────────────────────────────────────┐
│ Vertex Shader (顶点着色器) │
│ │
│ 输入: attribute — 顶点位置、法线、UV、自定义数据 │
│ uniform — 模型矩阵、视图矩阵、投影矩阵 │
│ 输出: varying — 传递给片元着色器的插值数据 │
│ 终点: gl_Position — 裁剪空间坐标 │
├──────────────────────────────────────────────────┤
│ Fragment Shader (片元着色器) │
│ │
│ 输入: varying — 来自顶点着色器的插值数据 │
│ uniform — 光源参数、材质参数、时间等 │
│ 输出: gl_FragColor — 最终像素颜色 │
└──────────────────────────────────────────────────┘
| GLSL 类型 | JavaScript 输入格式 | 示例 |
|---|---|---|
uniform float |
Number |
0.75 |
uniform vec2 |
[Number, Number] |
[1.0, 0.5] |
uniform vec3 |
[Number, Number, Number] |
[1.0, 0.0, 0.0] |
uniform vec4 |
[Number, Number, Number, Number] |
[1, 1, 1, 1] |
uniform mat4 |
Float32Array(16) |
mat4.create() |
uniform sampler2D |
WebGLTexture |
textureUnit |
// 通过 geometry.setAttribute 添加自定义顶点属性
geometry.setAttribute('aCustomAttr', {
data: new Float32Array([...]),
size: 3, // 每顶点分量数
type: gl.FLOAT,
normalized: false
});TinyGL 内置一套面向列主序(column-major)的线性数学工具集,兼容 WebGL uniformMatrix4fv 的内存布局要求。所有函数均为纯函数,不修改输入参数(除非明确命名 out 参数)。
import { mat4 } from 'tinygl-engine/math';
const out = mat4.create(); // 单位矩阵
const translation = mat4.create();
const rotation = mat4.create();
mat4.translate(translation, mat4.create(), [0, 2.5, -3]);
mat4.rotateY(rotation, mat4.create(), Math.PI / 4);
// 组合变换:先旋转再平移
mat4.multiply(out, translation, rotation);
// 透视投影矩阵
const proj = mat4.create();
mat4.perspective(proj, Math.PI / 3, aspect, 0.1, 1000);
// 观察矩阵
const view = mat4.create();
const eye = [0, 5, 10], center = [0, 0, 0], up = [0, 1, 0];
mat4.lookAt(view, eye, center, up);import { vec3 } from 'tinygl-engine/math';
const a = [1, 0, 0];
const b = [0, 1, 0];
const cross = vec3.cross([], a, b); // 叉积
const dot = vec3.dot(a, b); // 点积
const len = vec3.length(a); // 模长
const norm = vec3.normalize([], a); // 归一化
const lerp = vec3.lerp([], a, b, 0.5); // 线性插值import { quat } from 'tinygl-engine/math';
const q = quat.create();
quat.fromEuler(q, Math.PI / 6, 0, Math.PI / 3); // 欧拉角转四元数
quat.normalize(q, q);
// 四元数转旋转矩阵
const rotMat = mat4.create();
mat4.fromQuat(rotMat, q);| 模块 | 方法 | 说明 |
|---|---|---|
mat4 |
.create() |
创建 4x4 单位矩阵 |
mat4 |
.multiply(out, a, b) |
矩阵乘法 |
mat4 |
.translate(out, a, v) |
平移变换 |
mat4 |
.rotateX/Y/Z(out, a, rad) |
绕轴旋转 |
mat4 |
.scale(out, a, v) |
缩放变换 |
mat4 |
.perspective(out, fov, asp, near, far) |
透视投影 |
mat4 |
.ortho(out, l, r, b, t, n, f) |
正交投影 |
mat4 |
.lookAt(out, eye, center, up) |
观察矩阵 |
mat4 |
.invert(out, a) |
矩阵求逆 |
mat4 |
.transpose(out, a) |
矩阵转置 |
mat4 |
.fromQuat(out, q) |
四元数转矩阵 |
vec3 |
.create() |
零向量 |
vec3 |
.cross(out, a, b) |
叉积 |
vec3 |
.dot(a, b) |
点积 |
vec3 |
.normalize(out, a) |
归一化 |
vec3 |
.lerp(out, a, b, t) |
线性插值 |
vec3 |
.transformMat4(out, a, m) |
矩阵变换 |
quat |
.create() |
单位四元数 |
quat |
.fromEuler(out, x, y, z) |
欧拉角转换 |
quat |
.multiply(out, a, b) |
四元数乘法 |
quat |
.slerp(out, a, b, t) |
球面插值 |
TinyGL 的场景图采用树形结构,每个节点继承自 Node3D 基类,支持层级变换与全局矩阵自动更新。
| 类 | 继承自 | 说明 |
|---|---|---|
Node3D |
— | 场景图基础节点,提供 localMatrix / worldMatrix |
Scene |
Node3D |
场景根节点,管理渲染队列 |
Group |
Node3D |
逻辑分组容器,不影响渲染 |
Mesh |
Node3D |
可渲染网格,绑定 Geometry + Material |
Camera |
Node3D |
抽象相机基类 |
PerspectiveCamera |
Camera |
透视投影相机 |
OrthographicCamera |
Camera |
正交投影相机 |
Geometry |
— | 顶点数据容器(VBO 属性声明) |
ShaderMaterial |
— | 自定义 GLSL 着色器材质 |
PointLight |
Node3D |
点光源(衰减参数可配) |
DirectionalLight |
Node3D |
平行光(方向 + 颜色) |
const group = new Group();
const child = new Mesh(geometry, material);
group.add(child); // 添加子节点
group.remove(child); // 移除子节点
group.traverse((node) => { // 深度遍历
console.log(node.type);
});
// 世界矩阵访问(自动计算父级变换累积)
console.log(child.worldMatrix);TinyGL 的每帧渲染遵循以下管线流程:
┌────────────┐ ┌────────────┐ ┌──────────────────┐ ┌────────────┐
│ Update │───▶│ Frustum │───▶│ Uniform Upload │───▶│ Draw │
│ Scene Graph│ │ Culling │ │ (per material) │ │ Calls │
└────────────┘ └────────────┘ └──────────────────┘ └────────────┘
│ │ │ │
遍历场景图 基于相机 将 mat4/vec3/uniform 调用
更新 worldMatrix 视锥体剔除 上传至 GPU uniform gl.drawElements
& dirty flags 不在视野内的 缓冲区 或 gl.drawArrays
节点跳过渲染
- Scene Graph Update — 自顶向下遍历场景图,计算每个节点的
worldMatrix = parent.worldMatrix * localMatrix,标记 dirty 脏标志 - Frustum Culling — 将每个 Mesh 的包围球(Bounding Sphere)变换到世界空间后,与相机视锥体的 6 个平面进行相交测试
- Uniform Upload — 按材质分组(material batching),同一材质的 Mesh 共享 uniform 绑定状态,减少 GPU 状态切换
- Draw Calls — 通过 VAO 绑定顶点属性,执行索引化或非索引化绘制
TinyGL 使用 esbuild 作为构建工具,追求极致的打包速度与极小的产物体积。
aibo/
├── src/
│ ├── core/ # 渲染器核心 (TinyGL, WebGL context)
│ ├── scene/ # 场景图 (Scene, Node3D, Mesh, Camera)
│ ├── geometry/ # 几何体 (BoxGeometry, PlaneGeometry, SphereGeometry)
│ ├── material/ # 材质系统 (ShaderMaterial, UniformBinder)
│ ├── math/ # 数学库 (mat4, vec3, quat)
│ ├── shader/ # 着色器编译与链接
│ └── utils/ # 工具函数
├── test/ # Tape 单元测试
├── esbuild.config.js # 构建配置
├── package.json
└── README.md
// esbuild.config.js
const esbuild = require('esbuild');
esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
minify: true,
format: 'esm',
target: ['es2020', 'chrome80', 'firefox78'],
external: [], // 零外部依赖
outdir: 'dist',
sourcemap: true,
treeShaking: true, // 摇树优化
define: {
'process.env.NODE_ENV': '"production"'
}
}).catch(() => process.exit(1));# 开发构建(带 sourcemap)
npm run build:dev
# 生产构建(minified)
npm run build
# 运行测试
npm test使用 Tape 作为测试框架,聚焦数学库精度与 WebGL 状态验证。
npm test测试覆盖范围:
mat4— 矩阵运算精度(乘法、求逆、分解)vec3— 向量运算(叉积、归一化边界条件)quat— 四元数旋转等价性验证Scene Graph— 父子变换累积、worldMatrix 一致性Shader Compilation— GLSL 语法校验、uniform 绑定完整性
- 实例化渲染(Instancing) — 对大量相同几何体使用
InstancedMesh,通过 instance attribute 偏移变换,将 N 个 draw call 合并为 1 个 - 材质批处理 — 尽量让同一场景中使用相同 Material 的 Mesh 相邻排列,减少 GPU 状态切换
- 纹理图集 — 将小贴图合并到一张大图集上,减少 texture unit 绑定次数
- 避免 uniform 过度更新 — 仅在值变化时上传 uniform,利用 dirty flag 机制
- 使用
OES_element_index_uint— 当索引超过 65535 时启用 32 位索引,避免拆分 draw call FLOATvsHALF_FLOAT— 非颜色属性(位置、法线)优先使用 Float32;颜色与 UV 可降为 HalfFloat 节省带宽- Mipmap — 所有非RenderTarget 纹理都应生成 mipmap,设置
gl.generateMipmap,避免远处采样时的 shimmer 伪影
- Frustum Culling — 始终启用视锥体剔除,对静态场景可预计算 BVH 加速
- 脏标志系统 — 仅在 localMatrix 或 parent 变化时才重新计算 worldMatrix
- 离屏预编译 — 着色器在场景加载时异步编译链接,不阻塞首帧渲染
数学库核心热路径(mat4.multiply、vec3.transformMat4 等)预留 WASM 编译接口。未来将通过 Rust 编译为 WASM 模块,替代纯 JS TypedArray 实现,预期在批量矩阵运算场景中获得 3-5x 加速。
// 预期用法(WASM 模块就绪后)
import { initWASMMath } from 'tinygl-engine/wasm';
await initWASMMath(); // 加载 .wasm 模块
// 后续所有 mat4/vec3 调用自动走 WASM 路径
- Fork 本仓库
- 创建特性分支:
git checkout -b feature/your-feature - 编写/更新测试:
npm test - 确保所有测试通过
- 提交 PR,附上变更说明
代码风格:无分号、2 空格缩进、JSDoc 注释覆盖所有公开 API。
- 核心 Scene Graph 与渲染管线
- mat4 / vec3 / quat 数学库
- BoxGeometry, PlaneGeometry, SphereGeometry
- ShaderMaterial 自定义着色器
- PerspectiveCamera / OrthographicCamera
- Frustum Culling
- InstancedMesh 实例化渲染
- PBR 材质(基于物理的渲染)
- Shadow Mapping 阴影
- Post-processing 后处理管线(FBO + 全屏四边形)
- glTF 2.0 模型加载
- WASM 数学加速模块
- WebGPU 后端(实验性)
本项目基于 Mozilla Public License 2.0 (MPL-2.0) 开源。
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
MPL-2.0 是一个弱 Copyleft 许可证,允许在闭源项目中引用本库文件,但对库本身的修改必须以相同许可证开源。
TinyGL — 让 WebGL 回归本质
由 aidizhi 维护 · 在线演示与实验场景:aiboaibo.com
爱播爱播 © 2024-2026