功能:使用webgl繪制一個矩形,這裡通過繪制兩個三角形來實作一個矩形的繪制
步驟:
1 | 擷取webgl上下文 |
2 | 擷取着色器字元串 |
3 | 建立,加載,編譯着色器 |
4 | 給着色器的變量指派 |
5 | 繪制圖形 |
第一步:擷取webgl上下文
// 擷取WebGL上下文
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
if (!gl) {
return;
}
// 告訴WebGL怎樣把提供的gl_Position裁剪空間坐标對應到畫布像素坐标(螢幕空間)
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// 清空畫布
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
第二步:建立着色器字元串
這裡幾個注意事項:a_position.xy 其實是擷取一個vec2的向量
vec2 zeroToOne = a_position.xy / u_resolution; 這裡是vec2/vec2。我了解他的結果應該如下:
假設vec2 a1(x1,y1) a2(x2,y2) a3 = a1/a2 =(x1/x2,y1/y2)
其他的了解應該不難
<!-- vertex shader -->
<script id="2d-vertex-shader" type="notjs">
attribute vec4 a_position;
uniform vec2 u_resolution;
void main() {
// 從像素坐标轉換到 0.0 到 1.0
vec2 zeroToOne = a_position.xy / u_resolution;
// 再把 0->1 轉換 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// 把 0->2 轉換到 -1->+1 (裁剪空間)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace, 0, 1);
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="notjs">
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0.5, 1); // return redish-purple
}
</script>
var vertexShaderSource = document.getElementById("2d-vertex-shader").text;
var fragmentShaderSource = document.getElementById("2d-fragment-shader").text;
第三步:建立,加載,編譯着色器
// 建立着色器方法,輸入參數:渲染上下文,着色器類型,資料源
function createShader(gl, type, source) {
var shader = gl.createShader(type);// 建立着色器對象
gl.shaderSource(shader, source);// 提供資料源
gl.compileShader(shader);// 編譯 -> 生成着色器
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
}
// 然後我們将這兩個着色器 link(連結)到一個 program(着色程式)
function createProgram(gl, vertexShader, fragmentShader) {
var program = gl.createProgram();//建立着色程式
gl.attachShader(program, vertexShader);// 附加頂點着色器
gl.attachShader(program, fragmentShader);// 附加片元着色器
gl.linkProgram(program);//連結到着色程式
var success = gl.getProgramParameter(program, gl.LINK_STATUS);//判斷着色程式是否建立成功
if (success) {
gl.useProgram(program);
return program;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
}
建立定點着色器和片元着色器,再建立程式
var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
var program = createProgram(gl, vertexShader, fragmentShader);
第四步:給變量指派
// 建立存放三個2維裁剪空間點的緩存
var positionBuffer = gl.createBuffer();
// 綁定位置資訊緩沖(下面的綁定點就是ARRAY_BUFFER)
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
var positions = new Float32Array([
100, 200,
200, 200,
100, 30,
100, 30,
200, 200,
200, 30,
]);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
// 從着色程式中找到a_position屬性值所在的位置
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
// 從着色程式中找到u_resolution屬性值所在的位置
var resolutionUniformLocation = gl.getUniformLocation(program, "u_resolution");
// 啟用對應屬性
gl.enableVertexAttribArray(positionAttributeLocation);
// 告訴屬性怎麼從positionBuffer中讀取資料 (ARRAY_BUFFER)
var size = 2; // 每次疊代運作提取兩個機關資料
var type = gl.FLOAT; // 每個機關的資料類型是32位浮點型
var normalize = false; // 不需要歸一化資料
var stride = positions.BYTES_PER_ELEMENT * 2; // 0 = 移動機關數量 * 每個機關占用記憶體(sizeof(type))每次疊代運作運動多少記憶體到下一個資料開始點
var offset = 0; // 從緩沖起始位置開始讀取
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
// 設定全局變量 分辨率
gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
第五步:繪制圖像
// 繪制
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = 6;
gl.drawArrays(primitiveType, offset, count);
看一下效果:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CZyIGMiJjY0EWN2EjNzUzYjZ2NjdTZxYWY3IGOihDOk9CX0IzLcZDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL1M3Lc9CX6MHc0RHaiojIsJye.png)
我們可以調整一下坐标,就會發現是兩個三角形了。
把坐标調整一下:
var positions = new Float32Array([
100, 200,
200, 200,
100, 30,
100, 30,
200, 200,
200, 100,
]);