WebGL - 着色器初始化流程

本文详细介绍了WebGL中着色器的初始化过程,包括创建着色器对象、指定着色器代码、编译着色器、创建程序对象、分配着色器对象、连接程序对象以及使用程序对象的七个步骤。同时,解释了着色器对象和程序对象的作用,以及在编译和链接过程中可能出现的问题和解决方法。
摘要由CSDN通过智能技术生成

之前对着色器的初始化都是使用的initShaders()这个方法,部分代码在文章最后,其内部分执行细节没有去清晰的了解过,下面做进一步的了解和分析,才能更深入的了解webgl的原理

initShaders()方法的主要作用是编译GLSL ES代码,创建和初始化着色器,以便供WebgGL使用,具体初始化分为以下七步;

  • 1、创建着色器对象gl.createShader()
  • 2、向着色器对象中填充着色器程序的源代码gl.shaderSource()
  • 3、编译着色器gl.compileShader()
  • 4、创建程序对象gl.createProgram()
  • 5、为程序对象分配着色器gl.attachShader()
  • 6、连接程序对象gl.linkProgram()
  • 7、使用程序对象gl.useProgram()

1、两个对象

着色器对象:着色器对象管理一个顶点着色器或者一个片元着色器

程序对象:程序对象是管理着着色器对象的容器

2、具体方法介绍

1、创建着色器对象 gl.createShader()

​ 通过gl.createShader()来创建着色器对象,gl.VERTEX_SHADER或者gl.FRAGMENT

gl.createShader(type)WebGL提供的一个方法,MDN文档这样解释

WebGLRenderingContext.createShader() 用于创建一个 WebGLShader 着色器对象,该对象可以使用 WebGLRenderingContext.shaderSource()WebGLRenderingContext.compileShader() 方法配置着色器代码.

该方法接收一个参数type

type

​ 参数为gl.VERTEX_SHADERgl.FRAGMENT_SHADER两者中的一个

如果不再需要这个着色器可以使用gl.deleteShader()将其删除,但是如果着色器对象还在使用,那么gl.deleteShader()并不会立刻将其删除,而是要等到程序对象不再使用该着色器后,才将其删除

2、指定着色器对象的代码gl.shaderSource()

gl.shaderSource(shader, source)方法,向着色器指定GLSL ES源代码,在js中源代码以字符串的形式存在;

3、编译着色器gl.compileshader()

使用WebGLRenderingContext.compileShader()用于编译一个GLSL着色器,使其成为二进制数据,然后就可以被WebGLProgram对象所使用
语法

void gl.compileShader(shader)

var shader = gl.createShader(gl.VERTEX_SHADER);// 创建着色器对象
gl.shaderSource(shader, shaderSource);// 指定着色器对象的代码
gl.compileShader(shader);// 编译着色器

当使用gl.compileShader()方法时,如果着色器源代码中存在错误,那么就会出现编译错误,可以使用gl.getShaderParameter()来检查着色器的状态

有以下参数

  • gl.DELETE_STATUS:标示着色器是否被删除,删除(GL_TRUE)未删除(GL_FALSE).
  • gl.COMPILE_STATUS: 标示着色器是否编译成功,是(GL_TRUE)不是(GL_FALSE
  • gl.SHADER_TYPE: 标示着色器类型,是顶点着色器(gl.VERTEX_SHADER)还是片段着色器(gl.FRAGMENT_SHADER)

返回true或者false

如果编译失败,返回false,此时webgl系统会把编译错误的具体内容写入着色器的 信息日志,可以通过 gl.getShaderInfoLog()来获取报错信息

4、创建程序对象gl.createProgram()

程序对象包含顶点着色器和片元着色器,可以调用gl.createProfram()来创建程序对象,

该方法没有参数,返回一个WebGLProgram对象

一个WebGLProgram对象,由两个编译过后的WebGLShader组成,顶点着色器和片元着色器,这些组合成一个可用的webgl着色器程序

示例:

var program = gl.createProgram();

// 添加预先定义好的顶点着色器和片段着色器
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);

gl.linkProgram(program);

if ( !gl.getProgramParameter( program, gl.LINK_STATUS) ) {
  var info = gl.getProgramInfoLog(program);
  throw "Could not compile WebGL program. \n\n" + info;
}

类似的可以使用gl.deleteProgram()方法来删除程序对象

一旦程序对象被创建之后,需要向程序附上两个着色器

5、为程序对象分配着色器对象gl.attachShader()

webgl要运行起来必须要有两个着色器,顶点着色器和片元着色器,使用gl.attachShader()方法,为程序对象分配这两个着色器

如刚才上面的那段代码,就是在程序对象被创建之后开始分配着色器对象

着色器在附给程序对象前,并不一定要为其指定代码或进行编译,也就是说把空的着色器附给程序对象也是可以的,也可以使用gl.detachShader()来解除分配给程序对象的着色器

6、连接程序对象gl.linkProgram()

在为程序对象分配了两个着色器对象后,还需要将着色器连接起来,使用gl.linkProgram()方法来执行

程序对象连接操作目的时保证以下几点:

  • 顶点着色器和片元着色器的varying变量同名同类型,且一一对应
  • 顶点着色器对每个varying变量赋了值
  • 顶点着色器和片元着色器中的同名uniform变量也是同类型的
  • 着色器中的attributeuniform、和varying变量的个数没有超过着色器的上限

如果程序已经连接成功了,那么就会得到一个二进制的可执行模块,供webgl系统使用

需要注意的是,程序对象即使连接成功了,也有可能运行失败,比如没有为取样器分配纹理单元,这些错误是在运行阶段而不是连接阶段产生的,在运行阶段错误检查的开销很大,所以通常只在调式程序时这样做;

7、使用程序对象gl.useProgram()

最后通过gl.useProgram()告知webgl系统使用哪个对象

WebGLRenderingContext.useProgram() 方法将定义好的WebGLProgram 对象添加到当前的渲染状态中

这个方法使得webgl具有了一个强大的特性,那就是在绘制前准备多个程序对象,然后在绘制的时候根据需要切换程序对象

工具方法代码

// cuon-utils.js (c) 2012 kanda and matsuda
/**
 * 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);
    // 将此时的程序对象夫hi给
    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) {
    // 创建着色器对象
    var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
    var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
    if (!vertexShader || !fragmentShader) {
        return null;
    }

    // 创建程序对象
    var program = gl.createProgram();
    if (!program) {
        return null;
    }

    // 为程序对象分配着色器对象
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);

    // 连接程序对象
    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) {
    // 创建着色器对象
    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;
}

/**
 * Initialize and get the rendering for WebGL
 * @param canvas <cavnas> element
 * @param opt_debug flag to initialize the context for debugging
 * @return the rendering context for WebGL
 */
function getWebGLContext(canvas, opt_debug) {
    // Get the rendering context for WebGL
    var gl = WebGLUtils.setupWebGL(canvas);
    if (!gl) return null;

    // if opt_debug is explicitly false, create the context for debugging
    if (arguments.length < 2 || opt_debug) {
        gl = WebGLDebugUtils.makeDebugContext(gl);
    }

    return gl;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值