# 《前端图形学从入门到放弃》003 三维世界

` 本篇涵盖的内容包括：`

# 如何画一个正方体？

``````<!-- 一个顶点着色器提供裁剪空间坐标值 -->
attribute vec3 a_position;
uniform mat4 u_matrix;
// 这个是后续空间变化需要的，这一步     void main() {
vec4 position = u_matrix * vec4(a_position,1.0);
gl_Position = vec4(position.xyz,1.0);
}
</script>
<!-- 一个片断着色器提供颜色值 -->
precision mediump float;
void main() {
// 输出颜色固定即可，我选的是(1.0,0.1,.45)，rgb都除以255       gl_FragColor = vec4(vec3(1.0,0.1,.45), 1.0); //     }

</script>``````

``````var data = new Float32Array([
0.2, 0.2, 0.2,
-0.2, 0.2, 0.2,
-0.2, -0.2, 0.2,
0.2, -0.2, 0.2,
0.2, 0.2, -0.2,
-0.2, 0.2, -0.2,
-0.2, -0.2, -0.2,
0.2, -0.2, -0.2,
]); ``````

``````//顶点索引数组 var indexes = new Uint8Array([
//右侧四个点         0, 1, 2, 3,
//左侧四个顶点         4, 5, 6, 7,
//左右对应关系         0, 4,
1, 5,
2, 6,
3, 7
]); ``````

`````` var indexesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexesBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexes, gl.STATIC_DRAW);
var vBuffer = gl.createBuffer();
// 顶点需要是 ARRAY_BUFFER  gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW); ``````

``````//LINE_LOOP模式绘制右侧四个点 gl.drawElements(gl.LINE_LOOP, 4, gl.UNSIGNED_BYTE, 0);
//LINE_LOOP模式从第五个点开始绘制左侧四个点 gl.drawElements(gl.LINE_LOOP, 4, gl.UNSIGNED_BYTE, 4);
//LINES模式绘制连线左右点连线 gl.drawElements(gl.LINES, 8, gl.UNSIGNED_BYTE, 8); ``````

``````<div id="control">
<div class="item item-x">
<span>x:</span>
<input type="range" id="item-x" value="0" min="-1" max="1" step="0.01" >
</div>
<div class="item item-y">
<span>y:</span>
<input type="range" id="item-y" value="0" min="-1" max="1" step="0.01" >
</div>
<div class="item">
<span>z:</span>
<input type="range" id="item-z" value="0" min="-1" max="1" step="0.01" >
</div>
<div class="item item-x">
<span>x轴角度:</span>
<input type="range" id="item-r-x" value="0" min="-3.14" max="3.14" step="0.001" >
</div>
<div class="item item-y">
<span>y轴角度:</span>
<input type="range" id="item-r-y" value="0" min="-3.14" max="3.14" step="0.001" >
</div>
<div class="item">
<span>z轴角度:</span>
<input type="range" id="item-r-z" value="0" min="-3.14" max="3.14" step="0.001" >
</div>
</div>``````

``````var m4 = {  // 用来存放三位变换方法的对象   transform: function (x, y, z) {
return [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1,
];
},
rotateX: function (deg) {
var c = Math.cos(deg);
var s = Math.sin(deg);
return [
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
0, 0, 0, 1,
]
},
rotateY: function (deg) {
var c = Math.cos(deg);
var s = Math.sin(deg);
return [
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
0, 0, 0, 1,
]
},
rotateZ: function (deg) {
var c = Math.cos(deg);
var s = Math.sin(deg);
return [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]
},
} ``````

``````var m4 = {
// .......   multiply: function (a, b) {
var a00 = a[0 * 4 + 0];
var a01 = a[0 * 4 + 1];
var a02 = a[0 * 4 + 2];
var a03 = a[0 * 4 + 3];
var a10 = a[1 * 4 + 0];
var a11 = a[1 * 4 + 1];
var a12 = a[1 * 4 + 2];
var a13 = a[1 * 4 + 3];
var a20 = a[2 * 4 + 0];
var a21 = a[2 * 4 + 1];
var a22 = a[2 * 4 + 2];
var a23 = a[2 * 4 + 3];
var a30 = a[3 * 4 + 0];
var a31 = a[3 * 4 + 1];
var a32 = a[3 * 4 + 2];
var a33 = a[3 * 4 + 3];
var b00 = b[0 * 4 + 0];
var b01 = b[0 * 4 + 1];
var b02 = b[0 * 4 + 2];
var b03 = b[0 * 4 + 3];
var b10 = b[1 * 4 + 0];
var b11 = b[1 * 4 + 1];
var b12 = b[1 * 4 + 2];
var b13 = b[1 * 4 + 3];
var b20 = b[2 * 4 + 0];
var b21 = b[2 * 4 + 1];
var b22 = b[2 * 4 + 2];
var b23 = b[2 * 4 + 3];
var b30 = b[3 * 4 + 0];
var b31 = b[3 * 4 + 1];
var b32 = b[3 * 4 + 2];
var b33 = b[3 * 4 + 3];
return [
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33,
];
},
multiplys: function (list) {
var that = this;
return list.reduce(function (a, b) {
return that.multiply(a, b);
})
},
// ....... } ``````

`````` var xNode = document.querySelector('#item-x');
var yNode = document.querySelector('#item-y');
var zNode = document.querySelector('#item-z');
var rXNode = document.querySelector('#item-r-x');
var rYNode = document.querySelector('#item-r-y');
var rZNode = document.querySelector('#item-r-z');
// 。。。。。       loop();
function loop() {
var mx = m4.rotateX(rXNode.value);
var my = m4.rotateY(rYNode.value);
var mz = m4.rotateZ(rZNode.value);
var mTransform = m4.transform(xNode.value,yNode.value,zNode.value);
var matrix = m4.multiplys([mTransform,mz,my,mx]);
gl.uniformMatrix4fv(u_matrix, false, matrix);
// 把矩阵传入顶点作色器         gl.clearColor(0.75, 0.85, 0.8, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//LINE_LOOP模式绘制右侧四个点         gl.drawElements(gl.LINE_LOOP, 4, gl.UNSIGNED_BYTE, 0);
//LINE_LOOP模式从第五个点开始绘制左侧四个点         gl.drawElements(gl.LINE_LOOP, 4, gl.UNSIGNED_BYTE, 4);
//LINES模式绘制连线左右点连线         gl.drawElements(gl.LINES, 8, gl.UNSIGNED_BYTE, 8);
requestAnimationFrame(loop)
} ``````

demo

# 如何成为一个“有深度”的正方体？

``````<div class="item">
<span>z透视参数:</span>
<input type="range" id="item-z-factor" value="0" min="0" max="2" step="0.001" >
</div>
// .......
<script>
//........ var zFactorNode = document.querySelector("#item-z-factor")
// ........ </script>``````

``````var zFactorMatrix = [
1,0,0,0,
0,1,0,0,
0,0,1,zFactorNode.value,
0,0,0,1
];
var matrix = m4.multiplys([zFactorMatrix,mTransform,mz,my,mx]); ``````

demo

out_x = in_x+0+0+0；out__y = in_y_+0+0+0_；out_z = in_z_+0+0+0_；

out_w = in_w_+1_

# 正方体要离家出走了！

``````var data = new Float32Array([
10, 10, 80,
-10, 10, 80,
-10, -10, 80,
10, -10, 80,
10, 10, 60,
-10, 10, 60,
-10, -10, 60,
10, -10, 60,
]); ``````

``````var m4 = {
// ......   orthographic: function (t, b, l, r, n, f) {
//先把空间移动到0，0，0     var trans = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
-(r + l) / 2, -(t + b) / 2, -(n + f) / 2, 1,
]
//在把空间缩放到[-1,1]     var scale = [
2 / (r - l), 0, 0, 0,
0, 2 / (t - b), 0, 0,
0, 0, 2 / (n - f), 0,
0, 0, 0, 1,
]
return this.multiply(scale, trans);
},
//...... } ``````

``var Ortho = m4.orthographic(25,-25,25,-25,45,95); ``

``var matrix = m4.multiplys([Ortho, mTransform, mx, my, mz]); ``

1. 如何加入透视？
2. 如何让物体绕着自己旋转
3. 如何让相机移动与旋转
4. 如何盯住物体

WebGL 三维透视投影
Marschner, S., & Shirley, P. (2018). _Fundamentals of computer graphics_. Place of publication not identified: A K Peters/CRC Press.

2k 声望
127 粉丝
0 条评论