HTML部分
<script type="text/javascript" src="gl-matrix.js"></script> <canvas id="myCanvas" width="400" height="400" style="border: 1px solid red"></canvas>
JavaScript部分

以下兩點若不注意texture2D有可能取不到值,一片黑色。
- 老的顯卡只支持圖片尺寸為2的n次冪的紋理圖片。
- TEXTURE_MAG_FILTER和TEXTURE_MIN_FILTER參數需要制定。
const vertex = `
attribute vec3 v3Position;
uniform mat4 u_matrix;
attribute vec2 inUv;
varying vec2 outUv;
void main() {
gl_Position = u_matrix * vec4(v3Position, 1.0);
outUv = inUv;
}
`;
// texture2D(u_texture, vec2(outUv.x, outUv.y));
// texture2D(u_texture, outUv;
// 從紋理texture中根據outUv坐標取色素rgba
const fragment = `
precision mediump float;
uniform sampler2D u_texture;
varying vec2 outUv;
void main() {
gl_FragColor = texture2D(u_texture, vec2(outUv.x, outUv.y));
}
`;
let canvas = document.getElementById('myCanvas');
let webgl = canvas.getContext('webgl');
const data_position = new Float32Array([
// x y z u v
30, 30, 0, 0.0, 0.0,
330, 30, 0, 2.0, 0.0,
330, 330, 0, 2.0, 2.0,
30, 30, 0, 0.0, 0.0,
330, 330, 0, 2.0, 2.0,
30, 330, 0, 0.0, 2.0
]);
const data_mat4 = glMatrix.mat4.ortho([], 0, canvas.clientWidth, canvas.clientHeight, 0, -10, 10);
// 第一步:編譯程序
let program = createProgram(webgl, vertex, fragment);
// 第二步:建立buffer
let buffer_position = bindBufferWidthData(webgl, webgl.ARRAY_BUFFER, data_position); // 創建數據緩沖區
// 第三步:變量綁定
let v3Position = bindVertexAttributePointer(webgl, program, "v3Position", 3, 20, 0); // 綁定頂點輸入變量v3Position的指針和取數方式
let inUv = bindVertexAttributePointer(webgl, program, "inUv", 2, 20, 12); // 綁定頂點輸入變量inUv坐標的指針和取數方式
let matrix = setUniformMatrix(webgl, program, 'u_matrix', data_mat4); // 設置全局變量u_matrix的值
let img = new Image();
img.onload = ImageLoaded;
img.src = '/static/imgs/sky.png';
function ImageLoaded() {
var texture = webgl.createTexture();
webgl.activeTexture(webgl.TEXTURE1); // webgl有32個問題里圖片,激活第二個紋理圖片,一般使用第一個webgl.TEXTURE0
webgl.bindTexture(webgl.TEXTURE_2D, texture); // 設置webgl的TEXTURE1為TEXTURE_2D,實例為創建的texture變量
// 設置紋理圖片的參數
webgl.texImage2D(webgl.TEXTURE_2D, 0, webgl.RGBA, webgl.RGBA, webgl.UNSIGNED_BYTE, img);
// 圖片的真實大小為256*256,實際繪制時的區域有可能大於圖片實際尺寸,也有可能小於圖片實際尺寸
// 用於定義大於或小於真實尺寸時的圖片算法,NEAREST效率高,LINEAR效率低但效果好,圖片較小時看不出差別
webgl.texParameteri(webgl.TEXTURE_2D,webgl.TEXTURE_MAG_FILTER,webgl.NEAREST);
webgl.texParameteri(webgl.TEXTURE_2D,webgl.TEXTURE_MIN_FILTER,webgl.NEAREST);
// 一般UV坐標或ST坐標處於0到1之間,有時也會超過1,超過1時的顯示方式
// gl.REPEAT 平鋪
// gl.MIRRORED_REPEAT 鏡像(倒影)平鋪
// gl.CLAMP_TO_EDGE 使用邊緣顏色填充
webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_S, webgl.REPEAT); // 橫向
webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_T, webgl.REPEAT); // 縱向
let u_texture = webgl.getUniformLocation(program, "u_texture"); // 獲取全局變量u_texture
webgl.uniform1i(u_texture, 1); // 將全局變量賦值為webgl的第二個紋理圖片
clearCanvas(webgl);
webgl.drawArrays(webgl.TRIANGLES, 0, 6);
};


函數
/**
* 編譯shader源碼並與webgl綁定,返回program對象
* @param {*} webgl
* @param {*} vertex
* @param {*} fragment
*/
function createProgram(webgl, vertex, fragment) {
// 創建程序
let shader_vertex = webgl.createShader(webgl.VERTEX_SHADER);
let shader_fragment = webgl.createShader(webgl.FRAGMENT_SHADER);
webgl.shaderSource(shader_vertex, vertex);
webgl.shaderSource(shader_fragment, fragment);
// 編譯源碼
webgl.compileShader(shader_vertex);
webgl.compileShader(shader_fragment);
if (webgl.getShaderParameter(shader_vertex, webgl.COMPILE_STATUS) === false) {
console.error('Compile Shader Error: shader_vertex,' + webgl.getShaderInfoLog(shader_vertex));
}
if (webgl.getShaderParameter(shader_fragment, webgl.COMPILE_STATUS) === false) {
console.error('Compile Shader Error: shader_fragment,' + webgl.getShaderInfoLog(shader_fragment));
}
// 創建執行程序
let program = webgl.createProgram();
webgl.attachShader(program, shader_vertex);
webgl.attachShader(program, shader_fragment);
// 連接context和program
webgl.linkProgram(program);
if(webgl.getProgramParameter(program, webgl.LINK_STATUS) === false) {
console.error(webgl.getProgramInfoLog(program));
}
webgl.useProgram(program);
return program;
}
/**
* 向webgl添加buffer並傳入data
* @param {*} webgl
* @param {*} target 數據類型,gl.ARRAY_BUFFER
* @param {*} data
*/
function bindBufferWidthData(webgl, target, data) {
let buffer = webgl.createBuffer();
webgl.bindBuffer(target, buffer);
webgl.bufferData(target, data, webgl.STATIC_DRAW); // 內存數據傳入顯存
}
/**
* 建立JS變量和頂點輸入變量的引用,返回JS變量
* @param {*} webgl
* @param {*} program
* @param {String} varName Shader中的變量名
* @param {Number} varSize 變量維度
* @param {Number} stride 每段數據長度
* @param {Number} offset 每段中的偏移量
*/
function bindVertexAttributePointer(webgl, program, varName, varSize, stride, offset) {
var pointer = webgl.getAttribLocation(program, varName);
webgl.vertexAttribPointer(pointer, varSize, webgl.FLOAT, false, stride, offset);
webgl.enableVertexAttribArray(pointer);
return pointer;
}
/**
* 向Shader傳入mat4類型的全局變量
* @param {*} webgl
* @param {*} program
* @param {String} varName 變量名稱
* @param {mat4} data 變量值
*/
function setUniformMatrix(webgl, program, varName, data) {
let matrix = webgl.getUniformLocation(program, 'u_matrix');
webgl.uniformMatrix4fv(matrix, false, data); // r g b a
return matrix;
}
function clearCanvas(webgl) {
webgl.clearColor(0.7, 0.7, 0.7, 1);
webgl.clear(webgl.COLOR_BUFFER_BIT);
}
