着色器流程
上一章里我们用WebGL绘制了一个10像素的红色正方形。 在绘制过程中我们使用到一个新的概念,着色器。对着色器的概念我们也做了解释。
在三维场景中,仅仅用线条和颜色把图形画出来是远远不够的,你必须考虑光照射上去之后,或者观察者视角发生了变化, 对场景会有什么影响。 类型我们现实中看待物体一样。着色器可以高度灵活的完成这些工作,提供各种渲染效果。
js读取了着色器的相关信息,然后在WebGL系统中可以调用。
这就是整个流程,菱形部分为说明,矩形为具体流程。
简化之后就是
- 执行加载的js程序
- 顶点着色器,片元着色器
- 颜色缓存区
着色器代码解析
结合刚才的知识,我们再来看下上一章说着色器部分的代码
//顶点着色器程序
var VSHADER_SOURCE="" +
"void main(){\n" +
" gl_Position = vec4(0.0,0.0,0.0,1.0);\n" +//设置坐标
" gl_PointSize = 10.0;\n" +//设置尺寸
"}\n";
//片元着色器程序
var FSHADER_SOURCE = "" +
"void main(){\n" +
" gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n" +//设置颜色
"}\n";
function main() {
//首先获取到canvas的dom对象
var canvas = document.getElementById("canvas");
//获取到WebGL的上下文
var gl = getWebGLContext(canvas);
//不支持WebGL的浏览器将打印一个错误,并结束代码运行
if (!gl) {
console.log("浏览器不支持WebGL");
return;
}
//初始化着色器
if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
console.log("初始化着色器失败");
return;
}
//指定一个覆盖(清空)canvas的颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//执行清空
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制一个点
gl.drawArrays(gl.POINTS,0,1);
}
顶点着色器代码位于第2到6行, 片元着色器位于第10到13行,实际上,它们是以js字符串形式编写的着色器语言程序。
这样主程序就可以将它们传给WebGL系统。
在前面说到过,着色器是类似于c的OpenGL ES着色器语言(GLSL ES)来编写。着色器的语言很简单,稍微懂一点c或者js就可以理解。
初始化着色器
在研究着色器内部细节之前我们先看一下main函数的执行流程。
获取canvas元素 => 获取webGL绘图上下文 => 初始化着色器 => 设置canvas背景色 => 清楚canvas => 绘图
第三步初始化着色器, 调用了辅助函数initShaders()对字符串形式的着色器进行了初始化。该辅助函数定义在cuon.util.js中
/**
* Create a program object and make current
* @param gl GL context
* @param vshader a vertex shader program (string)
* @param fshader a fragment shader program (string)
* @return true, if the program object was created and successfully made current
*/
function initShaders(gl, vshader, fshader) {
var program = createProgram(gl, vshader, fshader);
if (!program) {
console.log('Failed to create program');
return false;
}
gl.useProgram(program);
gl.program = program;
return true;
}
/**
* Create the linked program object
* @param gl GL context
* @param vshader a vertex shader program (string)
* @param fshader a fragment shader program (string)
* @return created program object, or null if the creation has failed
*/
function createProgram(gl, vshader, fshader) {
// Create shader object
var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
if (!vertexShader || !fragmentShader) {
return null;
}
// Create a program object
var program = gl.createProgram();
if (!program) {
return null;
}
// Attach the shader objects
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// Link the program object
gl.linkProgram(program);
// Check the result of linking
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
var error = gl.getProgramInfoLog(program);
console.log('Failed to link program: ' + error);
gl.deleteProgram(program);
gl.deleteShader(fragmentShader);
gl.deleteShader(vertexShader);
return null;
}
return program;
}
/**
* Create a shader object
* @param gl GL context
* @param type the type of the shader object to be created
* @param source shader program (string)
* @return created shader object, or null if the creation has failed.
*/
function loadShader(gl, type, source) {
// Create shader object
var shader = gl.createShader(type);
if (shader == null) {
console.log('unable to create shader');
return null;
}
// Set the shader program
gl.shaderSource(shader, source);
// Compile the shader
gl.compileShader(shader);
// Check the result of compilation
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
var error = gl.getShaderInfoLog(shader);
console.log('Failed to compile shader: ' + error);
gl.deleteShader(shader);
return null;
}
return shader;
}
参数
gl: 指定渲染上线文
vshader: 指定顶点着色器程序代码
fshader: 指定片元着色器程序代码
返回值
true 初始化着色器成功
false 初始化着色器失败
后面我们会研究这个函数的内部细节, 现在只需要知道这个函数初始化了着色器。供我们使用即可。
WebGL系统由两部分组成, 顶点着色器和片元着色器。 这是简化之后的。初始化着色器之前, 顶点着色器和片元着色器都是空白的,我们需要将字符串形式的着色器代码从js传给WebGL系统, 并建立着色器, 这就是initShaders()所做的事情。 注意,着色器是运行在WebGL系统中,而不是js中。