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的冪次方問題相關配置,文中也已經給出