天天看點

WebGL學習筆記 | 使用着色器繪制一個點

前一篇 《WebGL學習筆記 | 建立着色器程式》介紹了如何建立着色器程式,這次我們讓着色器程式運作起來,并在螢幕上繪制一個點。

1. 頂點着色器程式

完整的着色器程式分為頂點着色器程式和片元着色器程式,我們先看下頂點着色器的程式代碼,将它定義為一個JavaScript字元串:

  1. //頂點着色器程式
  2. var VSHADER_SOURCE = `
  3. void main() {
  4. //設定一個坐标點
  5. gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
  6. //設定點的大小
  7. gl_PointSize = 4.0;
  8. }
  9. `

頂點着色器是用來描述頂點特性比如:位置和大小,它是指二維或三維空間中的一個點,頂點着色器中有兩個内置變量:

  • gl_Position:表示頂點位置
  • gl_PointSize:表示點的尺寸(像素,預設為1.0)

上面代碼中 gl_Position 内置變量必須被指派,否則着色器就不能正常工作,gl_PointSize 則不是必須的,它的預設值為1.0 。

注意我們給 gl_Position 指派了一個矢量 vec4 它内部是由 4 個浮點數組成,但是這裡隻用了三個即:x、y、z,第四個分量設定為 1.0 在這裡被稱之為齊次坐标,因為它能夠提高處理三維資料的效率,是以被三維圖形系統大量使用。

當需要使用齊次坐标表示頂點坐标時,隻需要将最後一個分量置為 1.0 即可。

齊次坐标:齊次坐标使用(x, y, z, w)表示,等價于三維坐标(x/w, y/w, z/w),是以如果齊次坐标的第 4 個分量是 1,就可以将它當三維坐标使用。

2. 片元着色器程式

片元可以了解為逐像素處理過程,嚴格意義上說片元還包括:像素的位置、顔色和其它資訊。

  1. //片元着色器程式
  2. var FSHADER_SOURCE =`
  3. //設定點的顔色
  4. gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  5. `;

gl_FragColor 是片元着色器中的唯一内置變量,它控制像素在螢幕上的最終顔色,上面代碼中的 vec4 的 4個分量代表顔色的 RGBA 值。

3. 在 JavaScript 啟用繪制

在 JavaScript 中初始化好着色器程式,進行編譯、連結,最後一步就是進行繪制操作:

//看上一篇《WebGL學習筆記 | 建立着色器程式》中有講解

  1. ...
  2. gl.useProgram(program);
  3. gl.drawArrays(gl.POINTS, 0, 1);

gl.drawArrays 函數非常強大,它可以用來繪制各種圖形,該函數規範如下:

gl.drawArrays(mode, first, count)

參數  

mode:指定繪制方式,可接收以下常量:gl.POINTS、gl.LINES、gl.LINESTRIP、gl.LINELOOP、gl.TRIANGLES、gl.TRIANGLESTRIP、gl.TRIANGLEFAN

first:指定從那個頂點開始繪制(整型數)

count:指定繪制需要用到多少個頂點(整型數)

傳回值: 無

錯誤:

INVALID_ENUM 傳入的 mode 參數不是前述參數之一

INVALID_VALUE 參數 first 或 count 是負數

使用 gl.drawArrays() 時,頂點着色器将被執行 count 次,每次處理一個頂點,我們這裡隻繪制了一個點,是以count為1。

當頂點着色器執行完成後,片元着色器開始執行,将顔色值賦給 gl_FragColor,最後一個紅色的像素點被繪制到了螢幕的中心位置 (0.0, 0.0, 0.0) ,看下圖:

WebGL學習筆記 | 使用着色器繪制一個點

本篇教程完整源碼如下:

HelloPoint.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Draw a point (1)</title>
  6. </head>
  7. <body onload="main()">
  8. <canvas id="webgl" width="400" height="400">
  9. Please use a browser that supports "canvas"
  10. </canvas>
  11. <script src="HelloPoint1.js"></script>
  12. </body>
  13. </html>

HelloPoint.js

  1. //頂點着色器代碼
  2. gl_PointSize = 8.0;
  3. //片元着色器代碼
  4. //建立着色器程式并繪制
  5. function main() {
  6. // 擷取canvas标簽
  7. var canvas = document.getElementById('webgl');
  8. // 擷取webgl上下文對象
  9. var gl = canvas.getContext('webgl')//getWebGLContext(canvas);
  10. if (!gl) {
  11. console.log('Failed to get the rendering context for WebGL');
  12. return;
  13. //建立、編譯頂點Shader
  14. var vertexShader = gl.createShader(gl.VERTEX_SHADER);
  15. gl.shaderSource(vertexShader, VSHADER_SOURCE);
  16. gl.compileShader(vertexShader);
  17. if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
  18. var error = gl.getShaderInfoLog(vertexShader);
  19. console.log('Failed to compile shader: ' + error);
  20. gl.deleteShader(vertexShader);
  21. return null;
  22. //建立、編譯片元Shader
  23. var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  24. gl.shaderSource(fragmentShader, FSHADER_SOURCE);
  25. gl.compileShader(fragmentShader);
  26. if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
  27. var error = gl.getShaderInfoLog(fragmentShader);
  28. gl.deleteShader(fragmentShader);
  29. //建立program對象,關聯、連結頂點、片元着色器
  30. var program = gl.createProgram();
  31. gl.attachShader(program, vertexShader);
  32. gl.attachShader(program, fragmentShader);
  33. gl.linkProgram(program);
  34. if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
  35. var error = gl.getProgramInfoLog(program);
  36. console.log('Failed to link program: ' + error);
  37. gl.deleteProgram(program);
  38. //啟用有着色器程式
  39. //通知webgl繪編

繼續閱讀