使用Buffer
文章推薦指數: 80 %
在〈使用attribute 變數〉中,每次只傳遞一個向量或浮點數,如果有多個頂點要繪製呢?這時可以透過Buffer,使用JavaScript 將資料放入Buffer,然後著色器從Buffer...
回WebGL
在〈使用attribute變數〉中,每次只傳遞一個向量或浮點數,如果有多個頂點要繪製呢?這時可以透過Buffer,使用JavaScript將資料放入Buffer,然後著色器從Buffer取得資料。
來看看怎麼畫兩個點好了,這只需要用到簡單的著色器:
因為這邊不做動畫,指定了gl.STATIC_DRAW,這是個最佳化提示,表示會經常使用Buffer,然而不常去變動它,在MDN的bufferData文件中,可以查看到其他提示,像是gl.DYNAMIC_DRAW、gl.STREAM_DRAW等。
接下來可以指定position來取用這個Buffer:
constattr_position=gl.getAttribLocation(prog,'position');
gl.vertexAttribPointer(attr_position,3,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(attr_position);
vertexAttribPointer的參數中3與g.FLOAT表示,每次從Buffer中取用三個單位的資料,型態是浮點數;false是normalized指定,簡單來說,若設定為true,會把整數轉換為-1~1的值,因為這邊設定為g.FLOAT了,這個參數基本上就是false(這時設成true也沒作用);下一個0是stride,用來指定每單位資料是幾個位元組,被設成0的話,就表示使用指定的型態;最後一個0表示從Buffer哪裏開始讀取,這邊是從陣列開頭開始。
接下來就可以畫兩個點了:
letmode=gl.POINTS;
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(mode,0,2);
mode如果改成gl.LINES的話,就會每兩個點連接起來,繪製出一條線來,例如,希望按下滑鼠時可以切換點與線的繪製:
gl.canvas.addEventListener('mousedown',()=>{
mode=mode===gl.POINTS?gl.LINES:gl.POINTS;
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(mode,0,2);
});
可以點一下範例網頁看看效果,因為會有兩個頂點,頂點著色器會被呼叫兩次,然而卻畫出了一條線,這是片段著色器的功勞,它會自動根據兩個頂點座標處指定的varying變數值,計算出插值來執行演算內容,最後指定給gl_FragColor,這個過程叫柵格化(Rasterisation),就目前來說,並沒有用到varying變數,片段著色器的顏色是寫死的,因此兩個點間的像素顏色也就固定了,之後會看到,頂點著色器如何使用varying變數傳遞資訊給片段著色器。
除了gl.POINTS、g.LINES之外,還有gl.LINE_STRIP依序連接每個點,gl.LINE_LOOP依序連接每個點外,最後一個點還會連接第一個點,在上頭的範例因為只有兩個點,設成這兩個效果都一樣,來看看正三角形的繪製好了:
//正三角頂點
constverteices=[
0.25,0.0,0.0,
0.0,0.433,0.0,
-0.25,0.0,0.0
];
//建立、指定、綁定Buffer
constbuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(verteices),gl.STATIC_DRAW);
constattr_position=gl.getAttribLocation(prog,'position');
gl.vertexAttribPointer(attr_position,3,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(attr_position);
//繪製
leti=0;
letmodes=[gl.LINE_STRIP,gl.LINE_LOOP,gl.TRIANGLES];
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(modes[i],0,3);
gl.canvas.addEventListener('mousedown',()=>{
i=(i+1)%3;
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(modes[i],0,3);
});
按下滑鼠的話,會依序展示gl.LINE_STRIP、gl.LINE_LOOP與gl.TRIANGLES的效果,gl.TRIANGLES是每次取三個點,畫出一個三角形,你可以先點一下範例網頁看看效果,嗯?不是要畫正三角嗎?你看到的不是正三角?只是個等腰三角?頂點設錯了嗎?
如果單看verteices中的三個頂點值,確實是正三角沒錯,不過別忘了,在〈認識著色器〉談到:
如果要將Canvas的顯示空間對應至裁剪空間,那麼通常可以將Canvas顯示空間最左邊對應至裁剪空間的x的-1.0,最右邊對應至1.0,顯示空間最下方對應至裁剪空間y的-1.0,最上方對應至1.0。
這表示,如果你的Canvas寬高並不是一比一的話,畫出來的東西是會變形的,若不想如此,必須依Canvas寬高比例做出修正:
來順便看一下gl.TRIANGLE_STRIP與gl.TRIANGLE_FAN好了。
gl.TRIANGLE_STRIP可以共用頂點,從第三個頂點開始,每個頂點與前兩個頂點連成三角形,也就是後續的三角形,會使用前兩個頂點形成的邊作為共用邊。
例如:
constverteices=[
0.25,0.0,0.0,
0.0,0.433,0.0,
-0.25,0.0,0.0,
-0.5,0.433,0.0
];
...略
gl.drawArrays(gl.TRIANGLE_STRIP,0,4);
看一下範例網頁,你會看到兩個正三角形成的平行四邊形,下圖列出了頂點關係:
至於gl.TRIANGLE_FAN,正如其名稱所示,適合繪製扇形,因為它從第三個頂點開始,都會與第一個和上個頂點相連,例如:
//圓的頂點
constr=0.25;
constfn=24;
constverteices=[0.0,0.0,0.0];
for(leti=0,step=2*Math.PI/fn;i
延伸文章資訊
- 1[Day5] WebGL 修羅道(2) - 資料傳遞 - iT 邦幫忙
buffers 跟attributes: 我們可以將資料放進去buffer 當中,當GPU 需要使用時就從buffer 取用,通常會存放像是頂點位置、紋理、顏色等等的資料;attribute 則...
- 25.3 - A Primer on Buffer Objects — LearnWebGL
Buffer objects provide the data for attribute variables in vertex shader programs. Remember that ...
- 3WebGL/uniform-buffers.html at main - GitHub
Contribute to KhronosGroup/WebGL development by creating an account on GitHub. ... <title>WebGL U...
- 4增加一個2D 物件到WebGL 環境- Web APIs | MDN
當你建立了WebGL的context後,便可開始渲染。最簡單的例子就是加入一個 ... 每次迭代時,vertex shader 從buffer 得到下一個值並傳入到attribute。
- 5WebGL How It Works
Buffers are the way of getting vertex and other per vertex data onto the GPU. gl.createBuffer cre...