初次接觸WebGL,如有錯誤之處歡迎留言,共同學習進步. v
WebGL的自畫像
我,WebGL,全名Web Graphics Library
,是為了讓死宅程式猿們(攤手)能在瀏覽器上為所欲為的畫女朋友,並還能動手動腳,而屈尊降臨於猿類的世界內。哇哈哈哈哈,快來臣服於我吧,哇嘎嘎嘎嗝~
WebGL啟動說明書
WebGL小姐姐神通廣大,法力無邊。那我們怎麼用她來創造一個猿猿幸(有)福(女)美(朋)滿(友)的世界呢?
首先,我們需要一個名為canvas
的祭壇,舉行一個召喚WebGL
小姐姐的小儀式。
const canvas = document.createElement(`canvas`);
const gl = canvas.getContext(`webgl`);
複製程式碼
那麼,WebGL
小姐姐Get到手了,接下來我們需要先將兩樣`祭品`交給她的兩名侍女。
- 準備用於建立軀體的原材料和賦予靈魂的色彩兩樣祭品
gl_Position
是每次繪製的點,是vec4型別,分別空間點(x, y, z)
和最後一個w
。對於w
可以參考文章Explaining Homogeneous Coordinates & Projective Geometry,可以理解為投影儀與空間點的距離,距離不同會導致縮放效應,距離遠則投放的物體越大。我們這裡使用沒有縮放效果的值1.0
,並使用了position
這個定義的變數值。每次繪製gpu buffer
會更新position
的值.
const vertexShaderSource = `
precision mediump float;
attribute vec2 position;
void main(void) {
gl_Position = vec4(position.x, position.y, 0.0, 1.0);
}
`;
複製程式碼
- 每次繪製都會使用
glFragColor
定義的顏色值,同樣是vec4型別,分別代表(r, g, b, a)
const fragmentShaderSource = `
precision mediump float;
void main(void) {
gl_FragColor = vec4(0.7, 0.5, 0.38, 0.0);
}
`
複製程式碼
關於
precision
:由於openGL
沒有宣告float
型別的預設精度,所以其姐妹WebGL
也就需要為shader
宣告精度。又由於高精度openGL
沒有支援,低精度在手機上可以有相容問題,所以預設推薦mediump
。參考stackoverflow.com/a/28540641/… 和 Use mediump precision in WebGL when possible
- 喚醒侍女並讓她們把祭品處理好
const vertexShader = gl.createShader(gl.VERTEX_SHADER); // 喚醒
gl.shaderSource(vertexShader, vertexShaderSource); // 上交祭品
gl.compileShader(vertexShader); // 處理祭品
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
// 由於祭品偶爾不新鮮或者侍女偷懶,我們要好好確認祭品是否處理完畢
throw new Error(`Error in compileing vertexShader: ${gl.getShaderInfoLog(vertexShader)}`);
}
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
throw new Error(`Error in compileing vertexShader: ${gl.getShaderInfoLog(vertexShader)}`);
}
複製程式碼
祭品已準備妥當,接下來就是要請出WebGL
小姐姐御用創世神器program
並使用祭品開光,然後交與小姐姐手中。
const program = gl.createProgram(); // 神器現世
gl.attachShader(program, vertexShader); // 開第一封印:原料
gl.attachShader(program, fragmentShader); // 開第二封印:色開
gl.linkProgram(program); // 交與小姐姐
if(!gl.getProgramParameter(program, gl.LINK_STATUS)) {
// 咳咳,由於神器與祭品偶爾無法契合,導致神器失效,需要檢查一下 ~_~
throw new Error(`invalid program: ${gl.getProgramInfoLog(program)}`);
}
複製程式碼
注意了注意了,WebGL
小姐姐起手式完畢,開天闢地,萬物復甦。我們現在可以向她許願,描述我們心中的猩福世界
了~v;v~
WebGL的許願池上的許願樹
WebGL
小姐姐有多個許願池,我們這裡使用gl.ARRAY_BUFFER
。然後告訴神器program
怎麼收取願望。
const buffer = gl.createBuffer(); // 建立許願樹
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); // 將許願樹種到`ARRAY_BUFFER`這個許願池內
// 獲取神器`program`的`position`之力
const position = gl.getAttribLocation(program, `position`);
// position之力為2個float型別的數一組,不轉化`buffer`型別,
// 從頭開始,不跳過任何一個願望
gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(position);
複製程式碼
WebGl的創世之作
小姐姐迎著絲毫都沒有的狂風,望著漫無編輯器的虛無黑暗,眼角迸發出一絲絲精光,大筆一揮, 左一劃右一揮。
gl.viewport(0, 0, 400, 400);
gl.useProgram(program);
gl.clearColor(255 / 255, 192 / 255, 203 / 255, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.lineWidth(1.5);
const points = new Float32Array([
-0.9, 0.9,
0.0, 0.0,
0.9, -0.9,
]);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.drawArrays(gl.LINE_LOOP, 0, points.length / 2);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-0.9, -0.9,
0.0, 0.0,
0.9, 0.9
]), gl.STATIC_DRAW);
gl.drawArrays(gl.LINE_LOOP, 0, 3);
複製程式碼
創世之作在漫天閃電,山崩海嘯之下莊嚴出世!! 登登登,piapia(背景樂)
最後來一張WebGL
繪製整個過程的流程圖:
未完待續
本文章首發於本人公眾號:楓之葉
若您能喜歡本文,並欲轉發本文請保留公眾號宣告與公眾號二維碼。謝謝 ^v^