var vShader = ` attribute vec4 a_Position; attribute vec2 a_TexCoord; varying vec2 v_TexCoord; void main(){ gl_Position = a_Position; v_TexCoord = a_TexCoord; } `; var fShader = ` //设定默认精度 #ifdef GL_ES precision mediump float; #endif uniform sampler2D u_Sampler; varying vec2 v_TexCoord; void main(){ gl_FragColor = texture2D(u_Sampler,v_TexCoord); } `; function main(){ //获取canvas元素 var canvas = document.getElementById('webgl'); //获取webgl上下文 var gl = getWebGLContext(canvas); if(!gl){ console.log('Failed to get the rendering context for WebGL!'); return; } //初始化着色器 if(!initShaders(gl,vShader,fShader)){ console.log('Failed to initialize shaders.'); return; } var n = initVertexBuffers(gl); if(n < 0){ console.log('Failed to set the positions of the vertices!'); return; } if(!initTextures(gl,n)){ console.log('Failed to initialize textures.'); return; } //用指定颜色填充webgl容器,就是设置背景 gl.clearColor(0.4, 0.5, 0.0, 1.0); function initVertexBuffers(gl){ var verticesTex = new Float32Array([ -0.5, 0.5, 0.0, 1.0, -0.5,-0.5, 0.0, 0.0, 0.5, 0.5, 1.0, 1.0, 0.5,-0.5, 1.0, 0.0 ]); var n = 4;//点的个数 //创建缓冲区对象 var vertexTexBuffer = gl.createBuffer(); if(!vertexTexBuffer){ console.log('Failed to create the buffer object!'); return -1; } //将数据添加到缓冲区(绑定在缓冲区对象上) gl.bindBuffer(gl.ARRAY_BUFFER,vertexTexBuffer); gl.bufferData(gl.ARRAY_BUFFER,verticesTex,gl.STATIC_DRAW); var fsize = verticesTex.BYTES_PER_ELEMENT; //获取shaderProgram中attribute变量‘a_Position’的地址 var a_Position = gl.getAttribLocation(gl.program,'a_Position'); if (a_Position < 0) { console.log('Failed to get the storage location of a_Position'); return -1; } //将缓冲区对象分配给a_Position变量并开启访问 gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,fsize * 4,0); gl.enableVertexAttribArray(a_Position); var a_TexCoord = gl.getAttribLocation(gl.program,'a_TexCoord'); if (a_TexCoord < 0) { console.log('Failed to get the storage location of a_TexCoord'); return -1; } //将缓冲区对象分配给a_TexCoord变量并开启访问 gl.vertexAttribPointer(a_TexCoord,2,gl.FLOAT,false,fsize * 4,fsize * 2); gl.enableVertexAttribArray(a_TexCoord); return n; } //初始化纹理图片,通过image传入 function initTextures(){ //创建纹理对象 var texture = gl.createTexture(); //读取u_Sampler存储位置 var u_Sampler = gl.getUniformLocation(gl.program,'u_Sampler'); var image = new Image(); image.onload = function(){ loadTexture(gl,n,texture,u_Sampler,image); } image.src = '../image/demo.jpg'; return true; } //加载纹理 function loadTexture(gl,n,texture,u_Sampler,image){ //对问题图像进行y轴反转 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1); //开启0号纹理单元 gl.activeTexture(gl.TEXTURE0); //向target绑定纹理对象 gl.bindTexture(gl.TEXTURE_2D,texture); //配置纹理参数 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); //处理图片像素非2的幂次方的配置 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); //配置纹理图像 gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,image); //将0号纹理传递给着色器 gl.uniform1i(u_Sampler,0); gl.clear(gl.COLOR_BUFFER_BIT); // Clear <canvas> gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); } } main();
注意:
①每个顶点着色器数据(-0.5, 0.5, 0.0, 1.0)前两个表示webgl的坐标系,后两个表示纹理坐标系;
②顶点着色器需要传入两个参数数据源a_Position、a_TexCoord,分别代表webgl顶点坐标和纹理坐标;
③对于纹理坐标,无论是顶点坐标系输入输出(a_TexCoord,v_TexCoord)还是片元着色器用于输入的v_TexCoord类型都是vec2,是二维的,别搞错了
④对于片元着色器uniform sampler2D u_Sampler;该变量的数据传递和以往不同,将纹理全部处理完毕之后,通过如下方法传递该纹理到片元着色器
gl.uniform1i(u_Sampler,0);
⑤因为加载纹理可能是异步的,所以渲染方法必须在加载纹理结束(配置完纹理并数据传递完毕)之后
//将0号纹理传递给着色器 gl.uniform1i(u_Sampler,0); gl.clear(gl.COLOR_BUFFER_BIT); // Clear <canvas> gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
⑥图片尺寸非2的幂次方问题相关配置,文中也已经给出