版权声明:本文为博主原创文章,欢迎读者转载学习,转载请注明文章出处。 https://blog.csdn.net/qq_37338983/article/details/83045821
本专栏所有文章示例代码均可在我的gitee码云上获取,读者可自行下载:https://gitee.com/babyogl/learnWebGL;本文demo代码在chapter-03下的rectangle-01.html,读者可以自行下载查看;
前面三节笔者分别实现了:用WebGL绘制一个三角形,WebGL中的矩阵运算:平移、旋转和缩放, WebGL绘制矩形等几个demo,也许细心的读者会发现代码很凌乱,而且实现一个例子往往需要很多行代码,那有没有更简洁的代码表达方式?当然有,我们可以把复用多次的代码封装起来。
步骤一:
我们将寻找着色器变量的位置和创建的缓冲区作为着色器项目的一个属性,这样做可以方便参数的传递:
//创建着色器程序
let program = initShader(gl, vShaderSource, fShaderSource);
program.pLocation = getAttribute(gl, program, 'a_position');
program.rLocation = getUniform(gl, program, 'u_resolution');
program.cLocation = getUniform(gl, program, 'u_color');
//创建缓冲区
program.pBuffer = gl.createBuffer();
步骤二:
我们将菜单栏编写为一个函数initGui接受gl和program两个参数,从这里就可以看出步骤1的好处:
function initGui(gl, program) {
let gui = new dat.GUI();
gui.add(guiField, 'x', 0, gl.canvas.width-200).onChange(function(e) {
translate[0] = e;
drawScene(gl, program);
});
gui.add(guiField, 'y', 0, gl.canvas.height-200).onChange(function(e) {
translate[1] = e;
drawScene(gl, program);
});
let ui = document.getElementById('ui');
ui.appendChild(gui.domElement);
}
步骤三:
设置矩形坐标:
function setRectangle(gl, x, y, width, height) {
let x1 = x, x2 = x + width;
let y1 = y, y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2
]), gl.STATIC_DRAW);
}
将画图封装为函数drawScene,同样接收gl,program为参数:
function drawScene(gl, program) {
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
//告诉WebGL如何从剪辑空间转换为像素
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
//清除canvas
gl.clear(gl.COLOR_BUFFER_BIT);
//应用着色器程序
gl.useProgram(program);
//开启顶点属性
gl.enableVertexAttribArray(program.pLocation);
//绑定缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, program.pBuffer);
setRectangle(gl, translate[0], translate[1], width, height);
//获取缓冲区数据
gl.vertexAttribPointer(program.pLocation, 2, gl.FLOAT, false, 0, 0);
//设置分辨率
gl.uniform2f(program.rLocation, gl.canvas.width, gl.canvas.height);
//设置颜色
gl.uniform4fv(program.cLocation, color);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
最后:
完整示例:
!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>平移</title>
<style>
body {
margin: 0px;
overflow: hidden;
}
canvas {
border: 3px solid blue;
display: block;
}
#ui {
position: absolute;
left: 810px;
top: 10px;
}
</style>
</head>
<body>
<canvas id="translate" width="800" height="600"></canvas>
<div id="ui"></div>
<script type="text/javascript" src="../libs/webgl-utils.js"></script>
<script type="text/javascript" src="../libs/m3.js"></script>
<script type="text/javascript" src="../libs/shader.js"></script>
<script type="text/javascript" src="../libs/dat.gui.min.js"></script>
<script id="v-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;//分辨率
varying vec4 v_color;
void main()
{
vec2 zeroToOne = a_position / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
v_color = vec4(gl_Position.xyz * 0.5, 0.6);
}
</script>
<script id="f-shader" type="x-shader/x-vertex">
#ifdef GL_ES
precision mediump float;
#endif
uniform vec4 u_color;
varying vec4 v_color;
void main()
{
gl_FragColor = v_color.rbga;
}
</script>
<script type="text/javascript">
"use strict";
let translate = [0, 0];
let width = 200, height = 200;
let color = [Math.random(), Math.random(), Math.random(), 1];
let guiField = {
x: 0,
y: 0
};
main();
function main() {
let canvas = document.getElementById('translate');
let gl = canvas.getContext('webgl', {antialias: true, depth: false});
if (!gl) {
alert("您的浏览器不支持WebGL!")
}
//获取顶点和片段着色器文本
let vShaderSource = document.getElementById('v-shader').text;
let fShaderSource = document.getElementById('f-shader').text;
//创建着色器程序
let program = initShader(gl, vShaderSource, fShaderSource);
program.pLocation = getAttribute(gl, program, 'a_position');
program.rLocation = getUniform(gl, program, 'u_resolution');
program.cLocation = getUniform(gl, program, 'u_color');
//创建缓冲区
program.pBuffer = gl.createBuffer();
//绑定缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, program.pBuffer);
drawScene(gl, program);
//设置菜单
initGui(gl, program);
}
function initGui(gl, program) {
let gui = new dat.GUI();
gui.add(guiField, 'x', 0, gl.canvas.width-200).onChange(function(e) {
translate[0] = e;
drawScene(gl, program);
});
gui.add(guiField, 'y', 0, gl.canvas.height-200).onChange(function(e) {
translate[1] = e;
drawScene(gl, program);
});
let ui = document.getElementById('ui');
ui.appendChild(gui.domElement);
}
//获取着色器中的attribute变量的位置
function getAttribute(gl, program, name) {
return gl.getAttribLocation(program, name);
}
//获取着色器中的uniform变量的位置
function getUniform(gl, program, name) {
return gl.getUniformLocation(program, name)
}
function drawScene(gl, program) {
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
//告诉WebGL如何从剪辑空间转换为像素
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
//清除canvas
gl.clear(gl.COLOR_BUFFER_BIT);
//应用着色器程序
gl.useProgram(program);
//开启顶点属性
gl.enableVertexAttribArray(program.pLocation);
//绑定缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, program.pBuffer);
setRectangle(gl, translate[0], translate[1], width, height);
//获取缓冲区数据
gl.vertexAttribPointer(program.pLocation, 2, gl.FLOAT, false, 0, 0);
//设置分辨率
gl.uniform2f(program.rLocation, gl.canvas.width, gl.canvas.height);
//设置颜色
gl.uniform4fv(program.cLocation, color);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
//设置矩形坐标
function setRectangle(gl, x, y, width, height) {
let x1 = x, x2 = x + width;
let y1 = y, y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2
]), gl.STATIC_DRAW);
}
</script>
</body>
</html>
效果:
下一节,笔者将带大家一起实现用WebGL写字的骚操作。敬请期待!