WebGL小姐姐教我學畫畫之起手式

楓~風發表於2019-02-12

初次接觸WebGL,如有錯誤之處歡迎留言,共同學習進步. v

WebGL的自畫像

我,WebGL,全名Web Graphics Library,是為了讓死宅程式猿們(攤手)能在瀏覽器上為所欲為的畫女朋友,並還能動手動腳,而屈尊降臨於猿類的世界內。哇哈哈哈哈,快來臣服於我吧,哇嘎嘎嘎嗝~

WebGL啟動說明書

WebGL小姐姐神通廣大,法力無邊。那我們怎麼用她來創造一個猿猿幸(有)福(女)美(朋)滿(友)的世界呢?

首先,我們需要一個名為canvas的祭壇,舉行一個召喚WebGL小姐姐的小儀式。

const canvas = document.createElement(`canvas`);
const gl = canvas.getContext(`webgl`);
複製程式碼

那麼,WebGL小姐姐Get到手了,接下來我們需要先將兩樣`祭品`交給她的兩名侍女。

  1. 準備用於建立軀體的原材料和賦予靈魂的色彩兩樣祭品
  • 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

  1. 喚醒侍女並讓她們把祭品處理好
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小姐姐教我學畫畫之起手式

最後來一張WebGL繪製整個過程的流程圖:

WebGL小姐姐教我學畫畫之起手式

未完待續


本文章首發於本人公眾號:楓之葉

WebGL小姐姐教我學畫畫之起手式

若您能喜歡本文,並欲轉發本文請保留公眾號宣告與公眾號二維碼。謝謝 ^v^

相關文章