# 可视化学习：如何用WebGL绘制3D物体

### 从二维到三维

// vertex
attribute vec2 a_vertexPosition;
attribute vec4 color;

varying vec4 vColor;

void main() {
gl_PointSize = 1.0;
vColor = color;
gl_Position = vec4(a_vertexPosition, 1, 1);
}

// fragment
#ifdef GL_ES
precision highp float;
#endif

varying vec4 vColor;

void main() {
gl_FragColor = vColor;
}

// ...
renderer.setMeshData([{
positions: [
[-0.5, -0.5],
[-0.5, 0.5],
[0.5, 0.5],
[0.5, -0.5]
],
attributes: {
color: [
[1, 0, 0, 1],
[1, 0, 0, 1],
[1, 0, 0, 1],
[1, 0, 0, 1],
]
},
cells: [[0, 1, 2], [2, 0, 3]]
}]);
// ...


// vertex
attribute vec3 a_vertexPosition;
attribute vec4 color;

varying vec4 vColor;

void main() {
gl_PointSize = 1.0;
vColor = color;
gl_Position = vec4(a_vertexPosition, 1);
}


/**
* 生成立方体6个面的24个顶点，12个三角形的索引，定义每个面的颜色信息
* @param size
* @param colors
* @returns {{cells: *[], color: *[], positions: *[]}}
*/
export function cube(size = 1.0, colors = [[1, 0, 0, 1]]) {
const h = 0.5 * size;
const vertices = [
[-h, -h, -h],
[-h, h, -h],
[h, h, -h],
[h, -h, -h],
[-h, -h, h],
[-h, h, h],
[h, h, h],
[h, -h, h]
];

const positions = [];
const color = [];
const cells = [];

let colorIdx = 0;
let cellsIdx = 0;
const colorLen = colors.length;

function quad(a, b, c, d) {
[a, b, c, d].forEach(item => {
positions.push(vertices[item]);
color.push(colors[colorIdx % colorLen]);
});
cells.push(
[0, 1, 2].map(i => i + cellsIdx),
[0, 2, 3].map(i => i + cellsIdx)
);
colorIdx ++;
cellsIdx += 4;
}

quad(1, 0, 3, 2); // 内
quad(4, 5, 6, 7); // 外
quad(2, 3, 7, 6); // 右
quad(5, 4, 0, 1); // 左
quad(3, 0, 4, 7); // 下
quad(6, 5, 1, 2); // 上

return {positions, color, cells};
}


const geometry = cube(1.0, [
[1, 0, 0, 1],   // 红
[0, 0.5, 0, 1], // 绿
[0, 0, 1, 1]    // 蓝
]);


// ...
renderer = new GlRenderer(glRef.value, {
depth: true // 开启深度检测
});
const program = renderer.compileSync(fragment, vertex);
renderer.useProgram(program);
renderer.setMeshData([{
positions: geometry.positions,
attributes: {
color: geometry.color
},
cells: geometry.cells
}]);
renderer.render();


### 投影矩阵：变换WebGL坐标系

[
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, -1, 0,
0, 0, 0, 1
]


// vertex
attribute vec3 a_vertexPosition; // 1:把顶点从vec2扩展到vec3
attribute vec4 color; // 四维向量

varying vec4 vColor;
uniform mat4 projectionMatrix; // 2:投影矩阵-变换坐标系

void main() {
gl_PointSize = 1.0;
vColor = color;
gl_Position = projectionMatrix * vec4(a_vertexPosition, 1.0);
}


### 模型矩阵：让立方体旋转起来

attribute vec3 a_vertexPosition; // 1:把顶点从vec2扩展到vec3
attribute vec4 color; // 四维向量

varying vec4 vColor;
uniform mat4 projectionMatrix; // 2:投影矩阵-变换坐标系
uniform mat4 modelMatrix; // 3:模型矩阵-使几何体旋转

void main() {
gl_PointSize = 1.0;
vColor = color;
gl_Position = projectionMatrix * modelMatrix * vec4(a_vertexPosition, 1.0);
}


import { multiply } from 'ogl/src/math/functions/Mat4Func.js';
// ...
export function fromRotation(rotationX, rotationY, rotationZ) {
let c = Math.cos(rotationX);
let s = Math.sin(rotationX);
const rx = [
1,  0, 0, 0, // 绕X轴旋转
0,  c, s, 0,
0, -s, c, 0,
0,  0, 0, 1
];

c = Math.cos(rotationY);
s = Math.sin(rotationY);
const ry = [
c,  0, s, 0,
0,  1, 0, 0, // 绕Y轴旋转
-s, 0, c, 0,
0,  0, 0, 1
];

c = Math.cos(rotationZ);
s = Math.sin(rotationZ);
const rz = [
c,  s, 0, 0,
-s, c, 0, 0,
0,  0, 1, 0, // 绕Z轴旋转
0,  0, 0, 1
];

const ret = [];
multiply(ret, rx, ry);
multiply(ret, ret, rz);
return ret;
}


// ...
let rotationX = 0;
let rotationY = 0;
let rotationZ = 0;
function update() {
rotationX += 0.003;
rotationY += 0.005;
rotationZ += 0.007;
renderer.uniforms.modelMatrix = fromRotation(rotationX, rotationY, rotationZ);
requestAnimationFrame(update);
}
update();
// ...


### 总结

posted @ 2024-07-10 12:10  beckyye  阅读(1312)  评论(4编辑  收藏  举报