WebGL简明教程之:【2】使用缓冲区绘制三角形

纯色三角形

我们首先借助缓冲区绘制一个三角形:

完整的代码如下:

<canvas width=200 height=200 style="outline:1px solid gray;">
 非常抱歉,您的浏览器不支持canvas!
</canvas>
<!-- 顶点着色器 -->
<script type='x-shader/x-vertex' id='vs'>
 attribute vec4 a_position;
 void main(){
 gl_Position=a_position;
 }
</script>
<!-- 片段着色器 -->
<script type='x-shader/x-fragment' id='fs'>
 precision mediump float;
 uniform vec4 u_color;
 void main(){
 gl_FragColor=u_color;
 }
</script>
<script>
 var gl = document.getElementsByTagName('canvas')[0].getContext('webgl');
 var loadShader = function (type, source) {
 var shader = gl.createShader(type);
 gl.shaderSource(shader, source);
 gl.compileShader(shader);
 return shader;
 };
 var vertexShader = loadShader(gl.VERTEX_SHADER, document.getElementById('vs').innerHTML),
 fragmentShader = loadShader(gl.FRAGMENT_SHADER, document.getElementById('fs').innerHTML);
 var glProgram = gl.createProgram();
 gl.attachShader(glProgram, vertexShader);
 gl.attachShader(glProgram, fragmentShader);
 gl.linkProgram(glProgram);
 gl.useProgram(glProgram);
 // 设置三角形的颜色(红色)
 var u_color = gl.getUniformLocation(glProgram, 'u_color');
 gl.uniform4f(u_color, 1, 0, 0, 1);
 // 创建缓冲区
 var buffer = gl.createBuffer();
 // 把缓冲区对象绑定到目标
 gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
 // 准备好点的数据
 var data = new Float32Array([
 -0.7, -0.7, 0,
 0.7, -0.7, 1,
 0, 0.7, 0
 ]);
 // 写入数据到缓冲区
 gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
 // 获取变量位置
 var a_position = gl.getAttribLocation(glProgram, "a_position");
 // 把缓冲区对象分配给目标变量
 gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, data.BYTES_PER_ELEMENT * 3, 0);
 // 连接目标对象和缓冲区对象
 gl.enableVertexAttribArray(a_position);
 // 绘制一个三角形
 gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>

接着,我们将来解读上面这段代码。

着色器

三角形一共有3个点,因此不能再写死了,需要定义变量使用缓冲区进行传递,顶点着色器修改如下:

attribute vec4 a_position;
void main(){
 gl_Position=a_position;
}

虽然三角形是纯色的,颜色可以写死,不过我们想演示一下如何通过变量设置颜色,因此片元着色器也进行修改:

precision mediump float;
uniform vec4 u_color;
void main(){
 gl_FragColor=u_color;
}

设置单个颜色

和点不同,颜色就一个值,无需借助缓冲区,比较简单,我们先看下具体代码:

var u_color = gl.getUniformLocation(glProgram, 'u_color');
gl.uniform4f(u_color, 1, 0, 0, 1);

颜色值是rgba(1,0,0,1),也就是不透明的红色。

借助缓冲区设置点

首先,准备好缓冲区对象:

var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

然后,准备好数据,并写入缓冲区中:

var data = new Float32Array([
 -0.7, -0.7, 0,
 0.7, -0.7, 1,
 0, 0.7, 0
]);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

最后,把缓冲区中的数据分配给点变量a_position即可:

var a_position = gl.getAttribLocation(glProgram, "a_position");
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, data.BYTES_PER_ELEMENT * 3, 0);
gl.enableVertexAttribArray(a_position);

绘制

gl.drawArrays(gl.TRIANGLES, 0, 3);

如此,一个红色的三角形就画好了。那么,既然点可以传递3个,可不可以每个点的颜色也可以不一样?当然可以了。

渐变色三角形

现在,我们再把这个三角形变成渐变色的,先看看最终效果:

同样的,先看看完整代码,后续我们一一进行必要的解释:

<canvas width=200 height=200 style="outline:1px solid gray;">
 非常抱歉,您的浏览器不支持canvas!
</canvas>
<!-- 顶点着色器 -->
<script type='x-shader/x-vertex' id='vs'>
 attribute vec4 a_position;
 attribute vec4 a_color;
 varying vec4 v_color;
 void main(){
 gl_Position=a_position;
 v_color=a_color;
 }
</script>
<!-- 片段着色器 -->
<script type='x-shader/x-fragment' id='fs'>
 precision mediump float;
 varying vec4 v_color;
 void main(){
 gl_FragColor=v_color;
 }
</script>
<script>
 var gl = document.getElementsByTagName('canvas')[0].getContext('webgl');
 var loadShader = function (type, source) {
 var shader = gl.createShader(type);
 gl.shaderSource(shader, source);
 gl.compileShader(shader);
 return shader;
 };
 var vertexShader = loadShader(gl.VERTEX_SHADER, document.getElementById('vs').innerHTML),
 fragmentShader = loadShader(gl.FRAGMENT_SHADER, document.getElementById('fs').innerHTML);
 var glProgram = gl.createProgram();
 gl.attachShader(glProgram, vertexShader);
 gl.attachShader(glProgram, fragmentShader);
 gl.linkProgram(glProgram);
 gl.useProgram(glProgram);
 var buffer = gl.createBuffer();
 gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
 // 准备好点的数据
 var data = new Float32Array([
 -0.7, -0.7, 0, 1, 0, 0,
 0.7, -0.7, 1, 0, 1, 0,
 0, 0.7, 0, 0, 0, 1
 ]);
 // 写入数据到缓冲区
 gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
 // 点的位置
 var a_position = gl.getAttribLocation(glProgram, "a_position");
 gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, data.BYTES_PER_ELEMENT * 6, 0);
 gl.enableVertexAttribArray(a_position);
 // 点的颜色
 var a_color = gl.getAttribLocation(glProgram, "a_color");
 gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, data.BYTES_PER_ELEMENT * 6, data.BYTES_PER_ELEMENT * 3);
 gl.enableVertexAttribArray(a_color);
 // 绘制一个三角形
 gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>

使用缓冲区设置点的颜色

着色器

只有顶点着色器可以传递多个数据,因此,需要先改造顶点着色器后通过管道实现:

attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 v_color;
void main(){
 gl_Position=a_position;
 v_color=a_color;
}

然后,片段着色器借助桥梁进行接收:

precision mediump float;
varying vec4 v_color;
void main(){
 gl_FragColor=v_color;
}
这里的varying类型的变量就相当于桥梁,当然,桥梁可以有多个。

借助缓冲区设置颜色

点的设置和之前一样,我们只需要修改一下点颜色的设置即可:

var a_color = gl.getAttribLocation(glProgram, "a_color");
gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, data.BYTES_PER_ELEMENT * 6, data.BYTES_PER_ELEMENT * 3);
gl.enableVertexAttribArray(a_color);

余下的,就和之前一样了。

作者:zxl20070701原文地址:https://segmentfault.com/a/1190000043336251

%s 个评论

要回复文章请先登录注册