WebGL着色器使用
1.编译 2.链接 3.使用 4.绘图
第 ① 步:编译着色器
1.1着色器源码:
let vShader_source = `
attribute vec4 aPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
attribute float size; //每个顶点的大小
void main(){
// gl_Position = uModelViewMatrix * aPosition;
gl_Position = uProjectionMatrix * uModelViewMatrix * aPosition;
gl_PointSize = size;
}`;
let fShader_source = `
precision mediump float;
uniform bool uBoolFrame;
uniform vec4 vColor;
void main(){
if(uBoolFrame){
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
else{
gl_FragColor = vColor;
}
}`;
1.2编译着色器:
//------>>>第1步:编译着色器
//顶点着色器
let vShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vShader, vShader_source);
gl.compileShader(vShader);
if (!gl.getShaderParameter(vShader, gl.COMPILE_STATUS)) {
console.error('----->>>vShader 编译错误:', gl.getShaderInfoLog(vShader));
}
//片元着色器
let fShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fShader, fShader_source);
gl.compileShader(fShader);
if (!gl.getShaderParameter(fShader, gl.COMPILE_STATUS)) {
console.error('----->>>fShader 编译错误:', gl.getShaderInfoLog(fShader));
}
第 ② 步:链接着色器程序
//------>>>第2步:链接着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vShader);
gl.attachShader(shaderProgram, fShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
console.error('------>>>着色器链接失败: ' + gl.getProgramInfoLog(program));
}
第 ③ 步:使用着色器程序
//------>>>第3步:使用着色器程序
gl.useProgram(shaderProgram);
第 ④ 步:绘图
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
附:使用着色器的简单案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL</title>
<style>
table {
position: absolute;
right: 0;
}
</style>
<!-- <script src="./gl-matrix.js"></script> -->
<script src="./gl-matrix-min.js"></script> //从http://glmatrix.net/获取 v2.6.1
</head>
<body>
<table>
<tr>
<th>
长: <input id='long' onchange="change()" type="number" value="100">
</th>
</tr>
<tr>
<th>
宽: <input id='width' onchange="change()" type="number" value="100">
</th>
</tr>
<tr>
<th>
高: <input id='height' onchange="change()" type="number" value="100">
</th>
</tr>
</table>
<canvas id="canvas" width="400" height="400"> </canvas>
<script>
let vShader_source = `
attribute vec4 aPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
attribute float size; //每个顶点的大小
void main(){
// gl_Position = uModelViewMatrix * aPosition;
gl_Position = uProjectionMatrix * uModelViewMatrix * aPosition;
gl_PointSize = size;
}`;
let fShader_source = `
precision mediump float;
uniform bool uBoolFrame;
uniform vec4 vColor;
void main(){
if(uBoolFrame){
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
else{
gl_FragColor = vColor;
}
}`;
const modelViewMatrix = mat4.create();
window.onload = function main() {
let canvas = document.getElementById('canvas');
let gl = canvas.getContext('webgl');
gl.clearColor(0.5, 1.0, 0.5, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
//------>>>第1步:编译着色器
//顶点着色器
let vShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vShader, vShader_source);
gl.compileShader(vShader);
if (!gl.getShaderParameter(vShader, gl.COMPILE_STATUS)) {
console.error('----->>>vShader 编译错误:', gl.getShaderInfoLog(vShader));
}
//片元着色器
let fShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fShader, fShader_source);
gl.compileShader(fShader);
if (!gl.getShaderParameter(fShader, gl.COMPILE_STATUS)) {
console.error('----->>>fShader 编译错误:', gl.getShaderInfoLog(fShader));
}
//------>>>第2步:链接着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vShader);
gl.attachShader(shaderProgram, fShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
console.error('------>>>着色器链接失败: ' + gl.getProgramInfoLog(program));
}
//------>>>第3步:使用着色器程序
gl.useProgram(shaderProgram);
//修改size
gl.vertexAttrib1f(gl.getAttribLocation(shaderProgram, 'size'), 10.0);
//使用顶点缓冲区上传顶点数据
//1.创建
let vertexBuffer = gl.createBuffer();
//2.绑定
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
//3.写入数据
let vertices = new Float32Array([
// 前
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// 后
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// 上
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// 下
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// 右
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// 左
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0,
]);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
//4.分配给变量
let aPosition_Location = gl.getAttribLocation(shaderProgram, 'aPosition');
gl.vertexAttribPointer(aPosition_Location, 3, gl.FLOAT, false, 0, 0);
//5.开启变量
gl.enableVertexAttribArray(aPosition_Location);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
const indices = new Uint16Array([
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, // 左
]);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
mat4.translate(modelViewMatrix, modelViewMatrix, [0.0, 0.0, -8.0]);
gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), false, modelViewMatrix); //第三个参数指是否转置矩阵,必须为false
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, 45 * Math.PI / 180, 1, 0.001, 100.0);
gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), false, projectionMatrix);
//------>>>第4步:绘图
const uModelViewMatrix_Location = gl.getUniformLocation(shaderProgram, 'uModelViewMatrix');
const uBoolFrame_Location = gl.getUniformLocation(shaderProgram, 'uBoolFrame');
function render() {
requestAnimationFrame(render);
gl.clearDepth(1.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.rotate(modelViewMatrix, modelViewMatrix, Math.PI / 200, [0, 1, 0]);
mat4.rotate(modelViewMatrix, modelViewMatrix, Math.PI / 300, [1, 0, 0]);
mat4.rotate(modelViewMatrix, modelViewMatrix, Math.PI / 400, [0, 0, 1]);
gl.uniformMatrix4fv(uModelViewMatrix_Location, false, modelViewMatrix);
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
//绘制线框
gl.uniform1i(uBoolFrame_Location, 1);
gl.drawElements(gl.LINE_LOOP, 36, gl.UNSIGNED_SHORT, 0);
gl.uniform1i(uBoolFrame_Location, 0);
}
render();
// 两秒变色
let vColor_Location = gl.getUniformLocation(shaderProgram, 'vColor');
// setInterval(() => {
// gl.uniform4f(vColor_Location, Math.random(), Math.random(), Math.random(), 1.0);
// }, 2000);
let i = 0;
setInterval(() => {
i++;
if (i >= 200) {
i = 0;
}
gl.uniform4f(vColor_Location, 1 - i/200, 0.0, i/200, 1.0);
}, 10);
}
//修改长、宽、高
const initModelViewMatrix = mat4.create();
mat4.translate(initModelViewMatrix, initModelViewMatrix, [0.0, 0.0, -8.0]);
function change() {
let long = document.getElementById('long').value;
let width = document.getElementById('width').value;
let height = document.getElementById('height').value;
mat4.scale(modelViewMatrix, initModelViewMatrix, [long / 100, width / 100, height / 100]);
console.log(`长:${long},宽:${width},高:${height}`);
}
</script>
</body>
</html>