# WebGLFundamentals.org

Fix, Fork, Contribute

# WebGL 三维正射投影

``````<script id="vertex-shader-2d" type="x-shader/x-vertex">
attribute vec2 a_position;

uniform mat3 u_matrix;

void main() {
// 将位置和矩阵相乘
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
}
</script>
``````

``````<script id="vertex-shader-3d" type="x-shader/x-vertex">
*attribute vec4 a_position;

*uniform mat4 u_matrix;

void main() {
// 将位置和矩阵相乘
*  gl_Position = u_matrix * a_position;
}
</script>
``````

``````  ...

// 告诉属性怎么从 positionBuffer (ARRAY_BUFFER) 中读取位置
*  var size = 3;          // 每次迭代使用 3 个单位的数据
var type = gl.FLOAT;   // 单位数据类型是32位的浮点型
var normalize = false; // 不需要归一化数据
var stride = 0;        // 0 = 移动距离 * 单位距离长度sizeof(type)  每次迭代跳多少距离到下一个数据
var offset = 0;        // 从绑定缓冲的起始处开始
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);

...

// 填充当前 ARRAY_BUFFER 缓冲
// 使用组成 'F' 的数据填充缓冲.
function setGeometry(gl) {
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
// 左竖
0,   0,  0,
30,   0,  0,
0, 150,  0,
0, 150,  0,
30,   0,  0,
30, 150,  0,

// 上横
30,   0,  0,
100,   0,  0,
30,  30,  0,
30,  30,  0,
100,   0,  0,
100,  30,  0,

// 下横
30,  60,  0,
67,  60,  0,
30,  90,  0,
30,  90,  0,
67,  60,  0,
67,  90,  0]),
gl.STATIC_DRAW);
}
``````

``````var m3 = {
translation: function translation(tx, ty) {
return [
1, 0, 0,
0, 1, 0,
tx, ty, 1
];
},

return [
c,-s, 0,
s, c, 0,
0, 0, 1
];
},

scaling: function scaling(sx, sy) {
return [
sx, 0, 0,
0, sy, 0,
0, 0, 1
];
},
};
``````

``````var m4 = {
translation: function(tx, ty, tz) {
return [
1,  0,  0,  0,
0,  1,  0,  0,
0,  0,  1,  0,
tx, ty, tz, 1,
];
},

return [
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
0, 0, 0, 1,
];
},

return [
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
0, 0, 0, 1,
];
},

return [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
},

scaling: function(sx, sy, sz) {
return [
sx, 0,  0,  0,
0, sy,  0,  0,
0,  0, sz,  0,
0,  0,  0,  1,
];
},
};
``````

newX = x * c + y * s;
newY = x * -s + y * c;

newX = x * c + z * s;
newZ = x * -s + z * c;

newY = y * c + z * s;
newZ = y * -s + z * c;

``````  translate: function(m, tx, ty, tz) {
return m4.multiply(m, m4.translation(tx, ty, tz));
},

},

},

},

scale: function(m, sx, sy, sz) {
return m4.multiply(m, m4.scaling(sx, sy, sz));
},
``````

``````  projection: function (width, height) {
// 注意：这个矩阵翻转了 Y 轴，所以 0 在上方
return [
2 / width, 0, 0,
0, -2 / height, 0,
-1, 1, 1
];
},
}
``````

``````  projection: function(width, height, depth) {
// 注意：这个矩阵翻转了 Y 轴，所以 0 在上方
return [
2 / width, 0, 0, 0,
0, -2 / height, 0, 0,
0, 0, 2 / depth, 0,
-1, 1, 0, 1,
];
},
``````

``````  // 计算矩阵
*  var matrix = m4.projection(gl.canvas.clientWidth, gl.canvas.clientHeight, 400);
*  matrix = m4.translate(matrix, translation[0], translation[1], translation[2]);
*  matrix = m4.xRotate(matrix, rotation[0]);
*  matrix = m4.yRotate(matrix, rotation[1]);
*  matrix = m4.zRotate(matrix, rotation[2]);
*  matrix = m4.scale(matrix, scale[0], scale[1], scale[2]);

// 设置矩阵
*  gl.uniformMatrix4fv(matrixLocation, false, matrix);
``````

``````    // 绘制几何体
var primitiveType = gl.TRIANGLES;
var offset = 0;
*    var count = 16 * 6;
gl.drawArrays(primitiveType, offset, count);
``````

``````<script id="vertex-shader-3d" type="x-shader/x-vertex">
attribute vec4 a_position;
+attribute vec4 a_color;

uniform mat4 u_matrix;

+varying vec4 v_color;

void main() {
// 将位置和矩阵相乘.
gl_Position = u_matrix * a_position;

+  // 将颜色传递给片断着色器
+  v_color = a_color;
}
</script>
``````

``````<script id="fragment-shader-3d" type="x-shader/x-fragment">
precision mediump float;

+// 从顶点着色器中传入
+varying vec4 v_color;

void main() {
*   gl_FragColor = v_color;
}
</script>
``````

``````  ...
var colorLocation = gl.getAttribLocation(program, "a_color");

...
// 给颜色创建一个缓冲
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
// 将颜色值传入缓冲
setColors(gl);

...
// 向缓冲传入 'F' 的颜色值

function setColors(gl) {
gl.bufferData(
gl.ARRAY_BUFFER,
new Uint8Array([
// 正面左竖
200,  70, 120,
200,  70, 120,
200,  70, 120,
200,  70, 120,
200,  70, 120,
200,  70, 120,

// 正面上横
200,  70, 120,
200,  70, 120,
...
...
gl.STATIC_DRAW);
}
``````

``````// 启用颜色属性
gl.enableVertexAttribArray(colorLocation);

// 绑定颜色缓冲
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);

// 告诉颜色属性怎么从 colorBuffer (ARRAY_BUFFER) 中读取颜色值
var size = 3;                 // 每次迭代使用3个单位的数据
var type = gl.UNSIGNED_BYTE;  // 单位数据类型是无符号 8 位整数
var normalize = true;         // 标准化数据 (从 0-255 转换到 0.0-1.0)
var stride = 0;               // 0 = 移动距离 * 单位距离长度sizeof(type)  每次迭代跳多少距离到下一个数据
var offset = 0;               // 从绑定缓冲的起始处开始
gl.vertexAttribPointer(
colorLocation, size, type, normalize, stride, offset)
``````

WebGL中的三角形有正反面的概念，正面三角形的顶点顺序是逆时针方向， 反面三角形是顺时针方向。

WebGL可以只绘制正面或反面三角形，可以这样开启

``````  gl.enable(gl.CULL_FACE);
``````

``````           1,   2,   3,
40,  50,  60,
700, 800, 900,
``````

``````           1,   2,   3,
700, 800, 900,
40,  50,  60,
``````

``````  gl.enable(gl.DEPTH_TEST);
``````

``````  // 绘制场景
function drawScene() {
...

// 清空画布和深度缓冲
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

...
``````

``````var m4 = {
orthographic: function(left, right, bottom, top, near, far) {
return [
2 / (right - left), 0, 0, 0,
0, 2 / (top - bottom), 0, 0,
0, 0, 2 / (near - far), 0,

(left + right) / (left - right),
(bottom + top) / (bottom - top),
(near + far) / (near - far),
1,
];
}
``````

``````var left = 0;
var right = gl.canvas.clientWidth;
var bottom = gl.canvas.clientHeight;
var top = 0;
var near = 400;
var far = -400;
m4.orthographic(left, right, bottom, top, near, far);
``````

### 为什么属性类型是 vec4 但是 gl.vertexAttribPointer 的大小是 3

```attribute vec4 a_position;
attribute vec4 a_color;
```

```// 告诉属性怎么从 positionBuffer (ARRAY_BUFFER) 中读取位置
var size = 3;          // 每次迭代使用 3 个单位的数据
var type = gl.FLOAT;   // 单位数据类型是32位的浮点型
var normalize = false; // 不需要归一化数据
var stride = 0;        // 0 = 移动距离 * 单位距离长度sizeof(type)
// 每次迭代跳多少距离到下一个数据
var offset = 0;        // 从绑定缓冲的起始处开始
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);

...
// 告诉颜色属性怎么从 colorBuffer (ARRAY_BUFFER) 中读取颜色值
var size = 3;          // 每次迭代使用3个单位的数据
var type = gl.UNSIGNED_BYTE;   // 单位数据类型是无符号 8 位整数
var normalize = true;  // 标准化数据 (从 0-255 转换到 0.0-1.0)
var stride = 0;        // 0 = 移动距离 * 单位距离长度sizeof(type)
// 每次迭代跳多少距离到下一个数据
var offset = 0;        // 从绑定缓冲的起始处开始
gl.vertexAttribPointer(
colorAttributeLocation, size, type, normalize, stride, offset);
```

• 基础概念
• 图像处理
• 二维平移，旋转，缩放和矩阵运算
• 三维
• 光照
• 组织和重构
• 几何
• 纹理
• 渲染到纹理