WebGL - 示例 从文件中加载并使用不同着色器

因为对不同的场景以及不同的材质需要使用不同的着色器,因此需要使用多个着色器,而不是单个,单个着色器是无法绘制出很复杂的场景,因为有的物体没有纹理而有的有纹理以及别的效果

1、外部文件加载着色器

着色器语言就是 GLSL格式的代码,我们可以先把顶点和片元着色器分别写在.glsl后缀名的文件中,如果你的编译器支持这种语法检测,那么代码就会有颜色,而不仅仅是字符串样式显示,尽管着色器代码本身就是字符串

下面是将要绘制的单色立方体的着色器文件

single_vertex_shader.glsl

// 顶点着色器
attribute vec4 a_Position;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_NormalMatrix;
varying vec4 v_Color;

void main(){

    vec3 lightDirection = vec3(0.0, 0.0, 1.0); // 灯光的位置 在世界坐标系中
    vec4 color = vec4(0.5, 0.5, 0.8, 1.0);// 表面颜色
    gl_Position = u_MvpMatrix * a_Position; // 计算后的顶点坐标
    vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));//标准化法向量
    float nDot = max(dot(normal, lightDirection), 0.0);
    v_Color = vec4(color.rgb * nDot, color.a);
    
}

single_fragment_shader.glsl

precision mediump float;
varying vec4 v_Color;
void main(){
    gl_FragColor = v_Color
}

从外部文件加载着色器,其实就是加载.glsl文件,读取里面的数据,然后通过顶点着色器和片元着色器创建程序对象

关于如何加载外部文件的方法,在上一篇文章中有介绍,你也可以直接去我的gitee上仓库的lib目录直接下载加载器

2、创建程序对象

加载完.glsl文件之后,就可以使用这两个着色器程序了,创建program对象,下面是两个程序对象,通过四个着色器代码创建得到的

var singleProgram = createProgram(gl, single_vertex_shader, single_fragment_shader);
var textureProgram = createProgram(gl, texture_vertex_shader,texture_fragment_shader);

3、获取变量存储地址

采用javascript对象属性的方式,把每个变量的存储地址挂载到程序对象上,便于使用

// 获取 singleProgram 中的 attribute 和 uniform 变量存储位置
singleProgram.a_Position = gl.getAttribLocation(singleProgram, 'a_Position');
singleProgram.a_Normal = gl.getAttribLocation(singleProgram, 'a_Normal');
singleProgram.u_MvpMatrix = gl.getUniformLocation(singleProgram, 'u_MvpMatrix');
singleProgram.u_NormalMatrix = gl.getUniformLocation(singleProgram, 'u_NormalMatrix');

// 获取 textureProgram 中的 attribute 和 uniform 变量存储位置
textureProgram.a_Position = gl.getAttribLocation(textureProgram, 'a_Position');
textureProgram.a_Normal = gl.getAttribLocation(textureProgram, 'a_Normal');
textureProgram.a_TexCoord = gl.getAttribLocation(textureProgram, 'a_TexCoord');
textureProgram.u_MvpMatrix = gl.getUniformLocation(textureProgram, 'u_MvpMatrix');
textureProgram.u_NormalMatrix = gl.getUniformLocation(textureProgram, 'u_NormalMatrix');
textureProgram.u_Sampler = gl.getUniformLocation(textureProgram, 'u_Sampler');

4、设置顶点颜色以及法线信息

因为创建的是两个立方体,所以它们的顶点数据和顶点索引以及法线数据都是可以共用的

var cube = initVertexBuffers(gl);
if (!cube) {
    console.log('failed to set the vertex information');
    return false;
}

上面通过initVertexBuffers()方法来设置顶点信息

设置完公用的顶点信息后,一个立方体是需要加载贴图的,因此需要把贴图的数据给加载到贴图立方体的片元着色器上,此处是通过initTexture(gl, program)方法来进行设置

var texture = initTextures(gl, textureProgram);
if (!texture) {
    console.log('failed to intialize the texture.');
    return false;
}

设置完以上数据之后,就可以开始绘制

因为是三维物体,有z轴深度,需要开启深度

gl.enable(gl.DEPTH_TEST)
// 设置canvas清空后的颜色
gl.clearColor(0.0, 0.5, 0.5, 1.0)

5、设置视图矩阵参数

var viewProjMatrix = new Matrix4();
viewProjMatrix.setPerspective(30.0, canvas.width / canvas.height, 1.0, 100.0)
viewProjMatrix.lookAt(0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

下面就可以在循环渲染方法中,进行帧刷新渲染

实际上在真正的项目开发过程中,重复这些步骤是很繁琐的,对一些反复的操作封装比较好的引擎例如three.js它隐藏了webgl的内部执行流程,同时也内置了很多的着色器,每一种材质以及灯光的添加都对应了一种着色器,这些着色器是可以进行修改的,并且three.js也支持自己去写着色器以及原生webgl代码

https://ithanmang.gitee.io/webgl-notes/home/07-高级技术示例/08-使用不同着色器.html

你可能感兴趣的:(webgl)