前一篇 《WebGL学习笔记 | 创建着色器程序》介绍了如何创建着色器程序,这次我们让着色器程序运行起来,并在屏幕上绘制一个点。
完整的着色器程序分为顶点着色器程序和片元着色器程序,我们先看下顶点着色器的程序代码,将它定义为一个JavaScript字符串:
//顶点着色器程序
var VSHADER_SOURCE = `
void main() {
//设置一个坐标点
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
//设置点的大小
gl_PointSize = 4.0;
}
`
顶点着色器是用来描述顶点特性比如:位置和大小,它是指二维或三维空间中的一个点,顶点着色器中有两个内置变量:
上面代码中 gl_Position 内置变量必须被赋值,否则着色器就不能正常工作,gl_PointSize 则不是必须的,它的默认值为1.0 。
注意我们给 gl_Position 赋值了一个矢量 vec4 它内部是由 4 个浮点数组成,但是这里只用了三个即:x、y、z,第四个分量设置为 1.0 在这里被称之为齐次坐标,因为它能够提高处理三维数据的效率,所以被三维图形系统大量使用。
当需要使用齐次坐标表示顶点坐标时,只需要将最后一个分量置为 1.0 即可。
齐次坐标:齐次坐标使用(x, y, z, w)表示,等价于三维坐标(x/w, y/w, z/w),所以如果齐次坐标的第 4 个分量是 1,就可以将它当三维坐标使用。
片元可以理解为逐像素处理过程,严格意义上说片元还包括:像素的位置、颜色和其它信息。
//片元着色器程序
var FSHADER_SOURCE =`
void main() {
//设置点的颜色
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
gl_FragColor 是片元着色器中的唯一内置变量,它控制像素在屏幕上的最终颜色,上面代码中的 vec4 的 4个分量代表颜色的 RGBA 值。
在 JavaScript 中初始化好着色器程序,进行编译、链接,最后一步就是进行绘制操作:
//看上一篇《WebGL学习笔记 | 创建着色器程序》中有讲解...
gl.useProgram(program);
gl.drawArrays(gl.POINTS, 0, 1);
gl.drawArrays 函数非常强大,它可以用来绘制各种图形,该函数规范如下:
gl.drawArrays(mode, first, count)
参数 mode:指定绘制方式,可接收以下常量:gl.POINTS、gl.LINES、gl.LINESTRIP、gl.LINELOOP、gl.TRIANGLES、gl.TRIANGLESTRIP、gl.TRIANGLEFAN first:指定从那个顶点开始绘制(整型数) count:指定绘制需要用到多少个顶点(整型数) 返回值: 无 错误: INVALID_ENUM 传入的 mode 参数不是前述参数之一 INVALID_VALUE 参数 first 或 count 是负数
使用 gl.drawArrays() 时,顶点着色器将被执行 count 次,每次处理一个顶点,我们这里只绘制了一个点,因此count为1。
当顶点着色器执行完成后,片元着色器开始执行,将颜色值赋给 gl_FragColor,最后一个红色的像素点被绘制到了屏幕的中心位置 (0.0, 0.0, 0.0) ,看下图:
本篇教程完整源码如下:
HelloPoint.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Draw a point (1)</title>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400">
Please use a browser that supports "canvas"
</canvas>
<script src="HelloPoint1.js"></script>
</body>
</html>
HelloPoint.js
//顶点着色器代码
var VSHADER_SOURCE = `
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 8.0;
}
`;
//片元着色器代码
var FSHADER_SOURCE =`
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
//创建着色器程序并绘制
function main() {
// 获取canvas标签
var canvas = document.getElementById('webgl');
// 获取webgl上下文对象
var gl = canvas.getContext('webgl')//getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
//创建、编译顶点Shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, VSHADER_SOURCE);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
var error = gl.getShaderInfoLog(vertexShader);
console.log('Failed to compile shader: ' + error);
gl.deleteShader(vertexShader);
return null;
}
//创建、编译片元Shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, FSHADER_SOURCE);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
var error = gl.getShaderInfoLog(fragmentShader);
console.log('Failed to compile shader: ' + error);
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
return null;
}
//创建program对象,关联、链接顶点、片元着色器
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
var error = gl.getProgramInfoLog(program);
console.log('Failed to link program: ' + error);
gl.deleteProgram(program);
}
//启用有着色器程序
gl.useProgram(program);
//通知webgl绘编
gl.drawArrays(gl.POINTS, 0, 1);
}
本文分享自 Creator星球游戏开发社区 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!