# twjl
**Repository Path**: nodets/twjl
## Basic Information
- **Project Name**: twjl
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-09-12
- **Last Updated**: 2025-09-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
[非官方,只是学习过程中添加中文注释]
=====================================================
[](https://github.com/greggman/twgl.js/actions/workflows/test.yml)
TWGL: 一个极简的 WebGL 辅助库。该库的唯一目的是让使用 WebGL API 更加简洁。
## 太长不看版
如果想快速完成任务,请使用 [three.js](http://threejs.org)。如果想用低级方式操作 WebGL,可以考虑使用 [TWGL](http://github.com/greggman/twgl.js/)。
## 最简单的例子
不包括着色器(这是一个简单的四边形着色器),下面是完整的代码:
```html
```
[在线演示](http://twgljs.org/examples/tiny.html).
## 为什么?是什么?怎么做?
WebGL 是一个非常冗长的 API。设置着色器、缓冲区、属性和统一变量需要大量代码。一个简单的带光照的立方体在 WebGL 中可能会轻松调用超过 60 次 API。
其核心功能只有以下几个主要函数:
* `twgl.createProgramInfo` 编译着色器并创建属性和统一变量的设置器
* `twgl.createBufferInfoFromArrays` 创建缓冲区和属性设置
* `twgl.setBuffersAndAttributes` 绑定缓冲区并设置属性
* `twgl.setUniforms` 设置统一变量
* `twgl.createTextures` 创建各种类型的纹理
* `twgl.createFramebufferInfo` 创建帧缓冲区和附件
还有一些额外的辅助函数和较低级别的函数,但以上 6 个函数是 TWGL 的核心。
比较使用 TWGL 和原生 WebGL 实现带点光源的立方体的代码。
### 编译着色器并查找位置
TWGL
```javascript
const programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
```
WebGL
```javascript
// 注意:这里假设你已经有 30 行用于编译 GLSL 的代码
const program = twgl.createProgramFromScripts(gl, ["vs", "fs"]);
const u_lightWorldPosLoc = gl.getUniformLocation(program, "u_lightWorldPos");
const u_lightColorLoc = gl.getUniformLocation(program, "u_lightColor");
const u_ambientLoc = gl.getUniformLocation(program, "u_ambient");
const u_specularLoc = gl.getUniformLocation(program, "u_specular");
const u_shininessLoc = gl.getUniformLocation(program, "u_shininess");
const u_specularFactorLoc = gl.getUniformLocation(program, "u_specularFactor");
const u_diffuseLoc = gl.getUniformLocation(program, "u_diffuse");
const u_worldLoc = gl.getUniformLocation(program, "u_world");
const u_worldInverseTransposeLoc = gl.getUniformLocation(program, "u_worldInverseTranspose");
const u_worldViewProjectionLoc = gl.getUniformLocation(program, "u_worldViewProjection");
const u_viewInverseLoc = gl.getUniformLocation(program, "u_viewInverse");
const positionLoc = gl.getAttribLocation(program, "a_position");
const normalLoc = gl.getAttribLocation(program, "a_normal");
const texcoordLoc = gl.getAttribLocation(program, "a_texcoord");
```
### 为立方体创建缓冲区
TWGL
```javascript
const arrays = {
position: [1,1,-1,1,1,1,1,-1,1,1,-1,-1,-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,1,1,1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,-1,1,-1,1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,-1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,-1,-1],
normal: [1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1],
texcoord: [1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1],
indices: [0,1,2,0,2,3,4,5,6,4,6,7,8,9,10,8,10,11,12,13,14,12,14,15,16,17,18,16,18,19,20,21,22,20,22,23],
};
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
```
WebGL
```javascript
const positions = [1,1,-1,1,1,1,1,-1,1,1,-1,-1,-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,1,1,1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,-1,1,-1,1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,-1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,-1,-1];
const normals = [1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1];
const texcoords = [1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1];
const indices = [0,1,2,0,2,3,4,5,6,4,6,7,8,9,10,8,10,11,12,13,14,12,14,15,16,17,18,16,18,19,20,21,22,20,22,23];
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
const texcoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texcoords), gl.STATIC_DRAW);
const indicesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
```
### 设置立方体的属性和索引
TWGL
```javascript
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
```
WebGL
```javascript
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLoc);
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(normalLoc);
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.vertexAttribPointer(texcoordLoc, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(texcoordLoc);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
```
### 设置带光照立方体的统一变量
TWGL
```javascript
// 初始化时
const uniforms = {
u_lightWorldPos: [1, 8, -10],
u_lightColor: [1, 0.8, 0.8, 1],
u_ambient: [0, 0, 0, 1],
u_specular: [1, 1, 1, 1],
u_shininess: 50,
u_specularFactor: 1,
u_diffuse: tex,
};
// 渲染时
uniforms.u_viewInverse = camera;
uniforms.u_world = world;
uniforms.u_worldInverseTranspose = m4.transpose(m4.inverse(world));
uniforms.u_worldViewProjection = m4.multiply(viewProjection, world);
twgl.setUniforms(programInfo, uniforms);
```
WebGL
```javascript
// 初始化时
const u_lightWorldPos = [1, 8, -10];
const u_lightColor = [1, 0.8, 0.8, 1];
const u_ambient = [0, 0, 0, 1];
const u_specular = [1, 1, 1, 1];
const u_shininess = 50;
const u_specularFactor = 1;
const u_diffuse = 0;
// 渲染时
gl.uniform3fv(u_lightWorldPosLoc, u_lightWorldPos);
gl.uniform4fv(u_lightColorLoc, u_lightColor);
gl.uniform4fv(u_ambientLoc, u_ambient);
gl.uniform4fv(u_specularLoc, u_specular);
gl.uniform1f(u_shininessLoc, u_shininess);
gl.uniform1f(u_specularFactorLoc, u_specularFactor);
gl.uniform1i(u_diffuseLoc, u_diffuse);
gl.uniformMatrix4fv(u_viewInverseLoc, false, camera);
gl.uniformMatrix4fv(u_worldLoc, false, world);
gl.uniformMatrix4fv(u_worldInverseTransposeLoc, false, m4.transpose(m4.inverse(world)));
gl.uniformMatrix4fv(u_worldViewProjectionLoc, false, m4.multiply(viewProjection, world));
```
### 加载 / 设置纹理
TWGL
```javascript
const textures = twgl.createTextures(gl, {
// 2 的幂次图像
hftIcon: { src: "images/hft-icon-16.png", mag: gl.NEAREST },
// 非 2 的幂次图像
clover: { src: "images/clover.jpg" },
// 来自画布
fromCanvas: { src: ctx.canvas },
// 来自 6 张图像的立方体贴图
yokohama: {
target: gl.TEXTURE_CUBE_MAP,
src: [
'images/yokohama/posx.jpg',
'images/yokohama/negx.jpg',
'images/yokohama/posy.jpg',
'images/yokohama/negy.jpg',
'images/yokohama/posz.jpg',
'images/yokohama/negz.jpg',
],
},
// 来自单张图像的立方体贴图(可以是 1x6、2x3、3x2、6x1)
goldengate: {
target: gl.TEXTURE_CUBE_MAP,
src: 'images/goldengate.jpg',
},
// 来自 JavaScript 数组的 2x2 像素纹理
checker: {
mag: gl.NEAREST,
min: gl.LINEAR,
src: [
255,255,255,255,
192,192,192,255,
192,192,192,255,
255,255,255,255,
],
},
// 来自类型化数组的 1x8 像素纹理
stripe: {
mag: gl.NEAREST,
min: gl.LINEAR,
format: gl.LUMINANCE,
src: new Uint8Array([
255,
128,
255,
128,
255,
128,
255,
128,
]),
width: 1,
},
});
```
WebGL
```javascript
// 假设我已经加载了所有图片
// 2 的幂次图像
const hftIconTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, hftIconImg);
gl.generateMipmaps(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
// 非 2 的幂次图像
const cloverTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, hftIconImg);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// 来自画布
const cloverTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, ctx.canvas);
gl.generateMipmaps(gl.TEXTURE_2D);
// 来自 6 张图像的立方体贴图
const yokohamaTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, posXImg);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, negXImg);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, posYImg);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, negYImg);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, posZImg);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, negZImg);
gl.generateMipmaps(gl.TEXTURE_CUBE_MAP);
// 来自单张图像的立方体贴图(可以是 1x6、2x3、3x2、6x1)
const goldengateTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
const size = goldengate.width / 3; // 假设是 3x2 纹理
const slices = [0, 0, 1, 0, 2, 0, 0, 1, 1, 1, 2, 1];
const tempCtx = document.createElement("canvas").getContext("2d");
tempCtx.canvas.width = size;
tempCtx.canvas.height = size;
for (let ii = 0; ii < 6; ++ii) {
const xOffset = slices[ii * 2 + 0] * size;
const yOffset = slices[ii * 2 + 1] * size;
tempCtx.drawImage(element, xOffset, yOffset, size, size, 0, 0, size, size);
gl.texImage2D(faces[ii], 0, format, format, type, tempCtx.canvas);
}
gl.generateMipmaps(gl.TEXTURE_CUBE_MAP);
// 来自 JavaScript 数组的 2x2 像素纹理
const checkerTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([
255,255,255,255,
192,192,192,255,
192,192,192,255,
255,255,255,255,
]));
gl.generateMipmaps(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// 来自类型化数组的 1x8 像素纹理
const stripeTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 1, 8, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, new Uint8Array([
255,
128,
255,
128,
255,
128,
255,
128,
]));
gl.generateMipmaps(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
```
### 创建帧缓冲区和附件
TWGL
```javascript
const attachments = [
{ format: RGBA, type: UNSIGNED_BYTE, min: LINEAR, wrap: CLAMP_TO_EDGE },
{ format: DEPTH_STENCIL, },
];
const fbi = twgl.createFramebufferInfo(gl, attachments);
```
WebGL
```javascript
const fb = gl.createFramebuffer(gl.FRAMEBUFFER);
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.drawingBufferWidth, gl.drawingBufferHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
const rb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, rb);
```
### 设置统一变量和统一块结构及数组
给定如下 GLSL 结构数组:
```glsl
struct Light {
float intensity;
float shininess;
vec4 color;
}
uniform Light lights[2];
```
TWGL
```javascript
const progInfo = twgl.createProgramInfo(gl, [vs, fs]);
...
twgl.setUniforms(progInfo, {
lights: [
{ intensity: 5.0, shininess: 100, color: [1, 0, 0, 1] },
{ intensity: 2.0, shininess: 50, color: [0, 0, 1, 1] },
],
});
```
WebGL
```javascript
// 假设我们已经编译并链接了程序
const light0IntensityLoc = gl.getUniformLocation('lights[0].intensity');
const light0ShininessLoc = gl.getUniformLocation('lights[0].shininess');
const light0ColorLoc = gl.getUniformLocation('lights[0].color');
const light1IntensityLoc = gl.getUniformLocation('lights[1].intensity');
const light1ShininessLoc = gl.getUniformLocation('lights[1].shininess');
const light1ColorLoc = gl.getUniformLocation('lights[1].color');
...
gl.uniform1f(light0IntensityLoc, 5.0);
gl.uniform1f(light0ShininessLoc, 100);
gl.uniform4fv(light0ColorLoc, [1, 0, 0, 1]);
gl.uniform1f(light1IntensityLoc, 2.0);
gl.uniform1f(light1ShininessLoc, 50);
gl.uniform4fv(light1ColorLoc, [0, 0, 1, 1]);
```
如果你只想在 TWGL 中设置第二个光源,可以这样做:
```javascript
const progInfo = twgl.createProgramInfo(gl, [vs, fs]);
...
twgl.setUniforms(progInfo, {
'lights[1]': { intensity: 5.0, shininess: 100, color: [1, 0, 0, 1] },
});
```
### 对比
[TWGL 示例](http://twgljs.org/examples/twgl-cube.html) vs [WebGL 示例](http://twgljs.org/examples/webgl-cube.html)
## 示例
* [最简单示例](http://twgljs.org/examples/tiny.html)
* [TWGL 立方体](http://twgljs.org/examples/twgl-cube.html)
* [纹理](http://twgljs.org/examples/textures.html)
* [基本几何体](http://twgljs.org/examples/primitives.html)
* [2D 线条](http://twgljs.org/examples/2d-lines.html)
* [动态缓冲区](http://twgljs.org/examples/dynamic-buffers.html)
* [缩放环绕](http://twgljs.org/examples/zoom-around.html)
* [文字](http://twgljs.org/examples/text.html)
* [万花筒](http://twgljs.org/examples/kaleidoscope.html)
* [隧道](http://twgljs.org/examples/tunnel.html)
* [GPGPU 粒子](http://twgljs.org/examples/gpgpu-particles.html)
* [项目列表](http://twgljs.org/examples/itemlist.html)
* [无盒天空盒](http://twgljs.org/examples/no-box-skybox.html)
* [跨域](http://twgljs.org/examples/crossorigin.html)
* [顶点数组对象](http://twgljs.org/examples/vertex-array-objects.html)
* [实例化](http://twgljs.org/examples/instancing.html)
### WebGL 2 示例
* [统一缓冲区对象](http://twgljs.org/examples/uniform-buffer-objects.html)
* [3D 纹理色调映射](http://twgljs.org/examples/3d-textures-tone-mapping.html)
* [采样器](http://twgljs.org/examples/samplers.html)
* [WebGL 2 纹理](http://twgljs.org/examples/webgl2-textures.html)
* [3D 纹理体积](http://twgljs.org/examples/3d-texture-volume.html)
* [3D 纹理体积无缓冲区](http://twgljs.org/examples/3d-texture-volume-no-buffers.html)
* [2D 数组纹理](http://twgljs.org/examples/2d-array-texture.html)
* [变换反馈](http://twgljs.org/examples/transform-feedback.html)
* [变换反馈粒子](http://twgljs.org/examples/transform-feedback-particles.html)
* [变换反馈粒子顶点数组](http://twgljs.org/examples/transform-feedback-particles-va.html)
### OffscreenCanvas 示例
* [OffscreenCanvas](http://twgljs.org/examples/offscreencanvas.html)
## ES6 模块支持
* [模块](http://twgljs.org/examples/modules.html)
## AMD 支持
* [amd](http://twgljs.org/examples/amd-compiled.html)
## CommonJS / Browserify 支持
* [browserify](http://twgljs.org/examples/browserify.html)
## 其他特性
* 包含一些可选的 3D 数学函数(完整版)
欢迎使用任何数学库,只要它以扁平的 Float32Array 或 JavaScript 数组存储矩阵即可。
* 包含一些可选的基本几何生成器(完整版)
平面、立方体、球体等。只是为了让入门更容易。
## 使用方法
查看示例。否则有几种不同的版本:
* [twgl-full.module.js](file://d:\cesium\source\twgl.js-main\twgl.js-main\dist\4.x\twgl-full.module.js) es6 模块版本
* [twgl-full.min.js](file://d:\cesium\source\twgl.js-main\twgl.js-main\dist\twgl-full.min.js) 完整版的压缩版本
* [twgl-full.js](file://d:\cesium\source\twgl.js-main\twgl.js-main\src\twgl-full.js) 完整版的连接版本
* [twgl.min.js](file://d:\cesium\source\twgl.js-main\twgl.js-main\dist\twgl.min.js) 最小版本(无 3D 数学,无基本几何体)
* [twgl.js](file://d:\cesium\source\twgl.js-main\twgl.js-main\dist\twgl.js) 连接后的最小版本(无 3D 数学,无基本几何体)
## 下载
* 从 github
[http://github.com/greggman/twgl.js](http://github.com/greggman/twgl.js)
* 从 bower
```bash
bower install twgl.js
```
* 从 npm
```bash
npm install twgl.js
```
或者
```bash
npm install twgl-base.js
```
* 从 git
```bash
git clone https://github.com/greggman/twgl.js.git
```
## 理由及其他闲聊
TWGL 的目标是通过提供一些小型辅助函数来使 WebGL 更加简洁,并减少冗余和消除乏味的操作。TWGL **不是**为了帮助处理着色器的复杂性或编写 GLSL。也不是像 [three.js](http://threejs.org) 那样的 3D 库。它只是试图让 WebGL 不那么冗长。
TWGL 可以被视为 [TDL](http://github.com/greggman/tdl) 的精神继承者。TDL 创建了几个 *类* 来包装 WebGL,而 TWGL 尽量不进行包装。实际上你可以手动创建几乎所有 TWGL 数据结构。
例如,函数 [setAttributes](file://d:\cesium\source\twgl.js-main\twgl.js-main\src\programs.js#L1889-L1896) 接收一个属性对象。
在 WebGL 中,你可能会这样写代码:
```javascript
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLoc);
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(normalLoc);
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.vertexAttribPointer(texcoordLoc, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(texcoordLoc);
gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
gl.vertexAttribPointer(colorLoc, 4, gl.UNSIGNED_BYTE, true, 0, 0);
gl.enableVertexAttribArray(colorLoc);
```
[setAttributes](file://d:\cesium\source\twgl.js-main\twgl.js-main\src\programs.js#L1889-L1896) 只是最简单的代码来为你做这些。
```javascript
// 手动为 TWGL 创建属性
const attribs = {
a_position: { buffer: positionBuffer, size: 3, },
a_normal: { buffer: normalBuffer, size: 3, },
a_texcoord: { buffer: texcoordBuffer, size: 2, },
a_color: { buffer: colorBuffer, size: 4, type: gl.UNSIGNED_BYTE, normalize: true, },
};
twgl.setAttributes(attribSetters, attribs);
```
上面的例子的重点是,TWGL 是一个**轻量级**的封装。它所做的只是试图让常见的 WebGL 操作更加简单和不那么冗长。欢迎将其与原生 WebGL 混合使用。
## API 文档
[API 文档在此](http://twgljs.org/docs/).
## 想学习 WebGL?
试试 [webglfundamentals.org](http://webglfundamentals.org)