一 绘制webGL独特的黑色背景(其他颜色的背景也ok)
1. 首先创建一个canvas标签,获取其DOM元素。
2. 建立视口,并且清除颜色缓存:
const canvas = document.getElementById('canvas');
webgl = canvas.getContext('webgl');
webgl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight);
webgl.clearColor(0, 0, 0, 1);
webgl.clear(webgl.COLOR_BUFFER_BIT);
canvas.clientWidth与webgl.canvas.width之间有什么区别?
二 绘制三角形
1.顶点着色器代码的编写(其中type可以写为 type = "x-shader/x-vertex")
<script id="vertex-shader" type="nojs">
attribute vec4 a_position;
void main(){
gl_Position = a_position;
}
</script>
2.片元着色器代码的编写(其中type可以写为 type = "x-shader/x-fragment")
<script id="fragment-shader" type="nojs">
precision medium float;
void main(){
gl_FragColor = vec4(1,0,0.5,1);
}
3.编译着色器代码并将其与着色程序链接起来(以下代码可封装成为一个函数)
(1)获取着色器代码并创建一个着色器对象,将着色器代码作为源放入该对象中以便后期的编译操作:
//获取着色器代码
var vertexShaderSource = document.getElementById("vertex-shader").text;
var fragmentShaderSource = document.getElementById("fragment-shader").text;
//创建一个着色器对象
var vertexShader = webgl.createShader(webgl.VERTEX_SHADER);
var fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER);
webgl.shaderSource(vertexShader, vertexShaderSource);
webgl.shaderSource(fragmentShader, fragmentShaderSource);
(2)编译着色器代码,并获取编译状态(成功或失败)
webgl.compileShader(vertexShader)
webgl.compileShader(fragmentShader)
var vertexSuccess = webgl.getShaderParameter(vertexShader, webgl.COMPILE_STATUS);
var fragmentSuccess = webgl.getShaderParameter(fragmentShader, webgl.COMPILE_STATUS);
if (!vertexSuccess) {
console.log("erro:vertexShader", webgl.getShaderInfoLog(vertexShader));
}
if (!fragmentSuccess) {
console.log("erro:fragmentShader", webgl.getShaderInfoLog(fragmentShader));
}
(3)创建一个着色程序作为连接,并获取连接状态:
var program = webgl.createProgram();
webgl.attachShader(program, vertexShader);
webgl.attachShader(program, fragmentShader);
webgl.linkProgram(program);
var programSuccess = webgl.getProgramParameter(program, webgl.LINK_STATUS);
if (!programSuccess) {
console.log("erro:programlink", webgl.getProgramInfoLog(program));
}
4.为创建好的着色程序提供数据(即顶点着色器中的变量,一般attribute,uniform需要传值)
(1)获得着色器数据中数据槽的位置(此时只有一个变量位置,没有值)
var positionAttributeLocation = webgl.getAttribLocation(program, "a_position");
(2)数据值一般存在于缓冲当中,即缓冲是存放数据的地方,也是取数据的地方(算是一个中间载体)。创建缓冲,并将其与数据源进行绑定,确定取数据的具体位置。
var positionBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ARRAY_BUFFER, positionBuffer);
(3)向缓冲中存放数据
var positions = [
0, 0,
0, 0.5,
0.7, 0
]
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(positions), webgl.STATIC_DRAW);
5.着色程序以及缓冲创建绑定完后,需要进行下一步的操作也就是渲染。渲染前要记得清除颜色缓冲。
(1)渲染开始就需要使用着色程序
webgl.useProgram(program)
(2)需要从缓冲当中读取相应的数据:先启用对应的属性(获取位置),其次需要获取具体到哪个缓冲去取值,最后设置读取数据的方式。
webgl.enableVertexAttribArray(positionAttributeLocation);
webgl.bindBuffer(webgl.ARRAY_BUFFER, positionBuffer);
webgl.vertexAttribPointer(positionAttributeLocation, 2, webgl.FLOAT, false, 0, 0);
(3)绘制操作
webgl.drawArrays(webgl.TRIANGLES, 0, 3)
这样绘制就基本完成啦。让我们看一下效果:
ps:还记得刚开始那个问题吗?(canvas.clientWidth与webgl.canvas.width之间有什么区别?具体的解释还是去扒理论吧)
实测代码:
// webgl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight);
webgl.viewport(0, 0, webgl.canvas.width, webgl.canvas.height);//区别在这里,用上面那行代码三角形无法显示
完整的代码如下(可直接运行):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
canvas {
width: 100%;
height: 100%;
}
</style>
<!-- 着色器代码 -->
<script id="vertex-shader" type="nojs">
attribute vec4 a_position;
void main(){
gl_Position = a_position;
}
</script>
<script id="fragment-shader" type="nojs">
precision mediump float;
void main(){
gl_FragColor = vec4(1,0,0.5,1);
}
</script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script>
var canvas = document.getElementById('canvas');
webgl = canvas.getContext('webgl');
if (!webgl) {
console.log('浏览器不支持webGL');
}
var vertexShaderSource = document.getElementById("vertex-shader").text;
var fragmentShaderSource = document.getElementById("fragment-shader").text;
var vertexShader = webgl.createShader(webgl.VERTEX_SHADER);
var fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER);
webgl.shaderSource(vertexShader, vertexShaderSource);
webgl.shaderSource(fragmentShader, fragmentShaderSource);
webgl.compileShader(vertexShader)
webgl.compileShader(fragmentShader)
var vertexSuccess = webgl.getShaderParameter(vertexShader, webgl.COMPILE_STATUS);
var fragmentSuccess = webgl.getShaderParameter(fragmentShader, webgl.COMPILE_STATUS);
if (!vertexSuccess) {
console.log("erro:vertexShader", webgl.getShaderInfoLog(vertexShader));
}
if (!fragmentSuccess) {
console.log("erro:fragmentShader", webgl.getShaderInfoLog(fragmentShader));
}
var program = webgl.createProgram();
webgl.attachShader(program, vertexShader);
webgl.attachShader(program, fragmentShader);
webgl.linkProgram(program);
var programSuccess = webgl.getProgramParameter(program, webgl.LINK_STATUS);
if (!programSuccess) {
console.log("erro:programlink", webgl.getProgramInfoLog(program));
}
var positionAttributeLocation = webgl.getAttribLocation(program, "a_position");
var positionBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ARRAY_BUFFER, positionBuffer);
var positions = [
0, 0,
0, 0.5,
0.7, 0
]
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(positions), webgl.STATIC_DRAW);
// webgl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight);
webgl.viewport(0, 0, webgl.canvas.width, webgl.canvas.height);//区别在这里,用上面那行代码三角形无法显示
webgl.clearColor(0, 0, 0, 1);
webgl.clear(webgl.COLOR_BUFFER_BIT);
webgl.useProgram(program)
webgl.enableVertexAttribArray(positionAttributeLocation);
webgl.bindBuffer(webgl.ARRAY_BUFFER, positionBuffer);
webgl.vertexAttribPointer(positionAttributeLocation, 2, webgl.FLOAT, false, 0, 0);
webgl.drawArrays(webgl.TRIANGLES, 0, 3)
</script>
</html>