webgl入門

1-刷底色的基本步驟

1.在html中創建canvas 畫布css

<canvas id="canvas"></canvas>

2.在js中獲取canvas畫布html

const canvas=document.getElementById('canvas’);

3.使用canvas 獲取webgl 繪圖上下文node

const gl=canvas.getContext('webgl’);

4.指定將要用來清空繪圖區的顏色web

gl.clearColor(0,0,0,1);

5.使用以前指定的顏色,清空繪圖區算法

gl.clear(gl.COLOR_BUFFER_BIT);

總體代碼canvas

<canvas id="canvas"></canvas><script>
    const canvas=document.getElementById('canvas');
    canvas.width=window.innerWidth;
    canvas.height=window.innerHeight;    const gl=canvas.getContext('webgl');
    gl.clearColor(0,0,0,1);
    gl.clear(gl.COLOR_BUFFER_BIT);</script>

clearColor(r,g,b,a) 中的參數是紅、綠、藍、透明度,其定義域是[0,1]瀏覽器

2-靈活操做webgl中的顏色

css 中有一個「rgba(255,255,255,1)」 顏色,其中r、g、b的定義域是[0,255],這裏要和webgl裏的顏色區分一下。網絡

咱們能夠簡單瞭解一下將css顏色解析爲webgl 顏色的原理:app

const rgbaCSS = "rgba(255,0,0,1)";const reg = RegExp(/\((.*)\)/);const rgbaStr = reg.exec(rgbaCSS)[1];const rgb = rgbaStr.split(",").map((ele) => parseInt(ele));const r = rgb[0] / 255;const g = rgb[1] / 255;const b = rgb[2] / 255;const a = rgb[3];

gl.clearColor(r, g, b, a);
gl.clear(gl.COLOR_BUFFER_BIT);

在three.js 裏有一個很是完美的顏色對象-Color,咱們經過這個對象能夠輕鬆的控制顏色。ide

案例-多姿多彩的畫布

1.引入Color 對象

import { Color } from "https://unpkg.com/three/build/three.module.js";

我這是經過CDN 引入的,這種方法不適用於nodejs,由於nodejs 沒法直接經過網絡路徑請求資源。

2.實例化Color 對象

const color = new Color(1, 0, 0);

3.創建色相偏移動畫

!(function ani() {
    color.offsetHSL(0.005, 0, 0);
    gl.clearColor(color.r, color.g, color.b, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
    requestAnimationFrame(ani);
})();

關於顏色的操做咱們就說到這,Color 對象還有不少其它方法,能夠在threejs官網查看。

3-webgl 的繪圖步驟

1.在html中創建canvas 畫布

<canvas id="canvas"></canvas>

2.在js中獲取canvas畫布

const canvas=document.getElementById('canvas');

3.使用canvas 獲取webgl 繪圖上下文

const gl=canvas.getContext('webgl');

4.在script中創建頂點着色器和片元着色器,glsl es

//頂點着色器<script id="vertexShader" type="x-shader/x-vertex">
    void main() {
        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
        gl_PointSize = 100.0;
    }</script>//片元着色器<script id="fragmentShader" type="x-shader/x-fragment">
    void main() {
        gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
    }</script>

5.在js中獲取頂點着色器和片元着色器的文本

const vsSource = document.getElementById('vertexShader').innerText;const fsSource = document.getElementById('fragmentShader').innerText;

6.初始化着色器

initShaders(gl, vsSource, fsSource);

7.指定將要用來清空繪圖區的顏色

gl.clearColor(0,0,0,1);

8.使用以前指定的顏色,清空繪圖區

gl.clear(gl.COLOR_BUFFER_BIT);

9.繪製頂點

gl.drawArrays(gl.POINTS, 0, 1);

總體代碼

<canvas id="canvas"></canvas><!-- 頂點着色器 --><script id="vertexShader" type="x-shader/x-vertex">
    void main() {
        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
        gl_PointSize = 100.0;
    }</script><!-- 片元着色器 --><script id="fragmentShader" type="x-shader/x-fragment">
    void main() {
        gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
    }</script><script>
    // canvas 畫布
    const canvas = document.getElementById('canvas');
    canvas.width=window.innerWidth;
    canvas.height=window.innerHeight;    // webgl畫筆
    const gl = canvas.getContext('webgl');    // 頂點着色器
    const vsSource = document.getElementById('vertexShader').innerText;    // 片元着色器
    const fsSource = document.getElementById('fragmentShader').innerText;    // 初始化着色器
    initShaders(gl, vsSource, fsSource);    // 指定將要用來清理繪圖區的顏色
    gl.clearColor(0., 0.0, 0.0, 1.0);    // 清理繪圖區
    gl.clear(gl.COLOR_BUFFER_BIT);    // 繪製頂點
    gl.drawArrays(gl.POINTS, 0, 1);    function initShaders(gl,vsSource,fsSource){        //建立程序對象
        const program = gl.createProgram();        //創建着色對象
        const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);        const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);        //把頂點着色對象裝進程序對象中
        gl.attachShader(program, vertexShader);        //把片元着色對象裝進程序對象中
        gl.attachShader(program, fragmentShader);        //鏈接webgl上下文對象和程序對象
        gl.linkProgram(program);        //啓動程序對象
        gl.useProgram(program);        //將程序對象掛到上下文對象上
        gl.program = program;        return true;
    }    function loadShader(gl, type, source) {        //根據着色類型,創建着色器對象
        const shader = gl.createShader(type);        //將着色器源文件傳入着色器對象中
        gl.shaderSource(shader, source);        //編譯着色器對象
        gl.compileShader(shader);        //返回着色器對象
        return shader;
    }</script>

對於上面的步驟一、二、3,你們應該都比較好理解,接下來我們詳細說一下第4 步,在script 裏用GLSL ES語言寫着色器。

5-着色器

5-1-着色器的概念

webgl 繪圖須要兩種着色器:

  • 頂點着色器(Vertex shader):描述頂點的特徵,如位置、顏色等。
  • 片元着色器(Fragment shader):進行逐片元處理,如光照。

看了這兩個名詞的解釋,我想不少初學者會是懵的。

我給你們翻譯翻譯:

補間動畫你們知道不?頂點着色器裏的頂點就是補間動畫裏的關鍵幀,片元着色器裏的片元就是關鍵幀之間以某種算法算出的插值。固然,我們webgl裏的片元是像素的意思。

再給你們舉一個更簡單、更貼切的例子:

兩點決定一條直線你們知道不?頂點着色器裏的頂點就是決定這一條直線的兩個點,片元着色器裏的片元就是把直線畫到畫布上後,這兩個點之間構成直線的每一個像素。

關於概念我們就說到這,接下來我們說着色器語言。

5-2-着色器語言

webgl 的着色器語言是GLSL ES語言

  • 頂點着色程序,要寫在type=「x-shader/x-vertex」 的script中。
<script id="vertexShader" type="x-shader/x-vertex">    void main() {
        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
        gl_PointSize = 100.0;
    }
</script>
  • 片元着色程序,要寫在type=「x-shader/x-fragment」 的script中。
<script id="fragmentShader" type="x-shader/x-fragment">    void main() {
        gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
    }
</script>

void main() {…… } 是主體函數。

在頂點着色器中,gl_Position 是頂點的位置,gl_PointSize 是頂點的尺寸,這種名稱都是固定的,不能寫成別的。

在片元着色器中,gl_FragColor 是片元的顏色。

vec4() 是一個4維矢量對象。

將vec4() 賦值給頂點點位gl_Position 的時候,其中的前三個參數是x、y、z,第4個參數默認1.0,其含義咱們後面會詳解;

將vec4() 賦值給片元顏色gl_FragColor 的時候,其中的參數是r,g,b,a。

至於GLSL ES語言的其它知識,我們會在後面另開一篇詳解,這裏先以入門爲主。

在第6步中,咱們使用了一個自定義的方法initShaders() ,這是用於初始化着色器的,接下來我們詳細說一下。

6-着色器初始化

初始化着色器的步驟:

  1. 創建程序對象,目前這只是一個手繪板的外殼。

    const shaderProgram = gl.createProgram();
  2. 創建頂點着色器對象和片元着色器對象,這是手繪板裏用於接收觸控筆信號的零部件,兩者能夠分工合做,把觸控筆的壓感(js信號)解析爲計算機語言(GLSL ES),而後讓計算機(瀏覽器的webgl 渲染引擎)識別顯示。

    const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
  3. 將頂點着色器對象和片元着色器對象裝進程序對象中,這就完成的手繪板的拼裝。

    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
  4. 鏈接webgl 上下文對象和程序對象,就像鏈接觸控筆和手繪板同樣(觸控筆裏有傳感器,能夠向手繪板發送信號)。

    gl.linkProgram(shaderProgram);
  5. 啓動程序對象,就像按下了手繪板的啓動按鈕,使其開始工做。

    gl.useProgram(program);

上面第二步中的創建着色對象方法loadShader(),是一個自定義的方法,其參數是(webgl上下文對象,着色器類型,着色器源文件),gl.VERTEX_SHADER 是頂點着色器類型,gl.FRAGMENT_SHADER是片元着色器類型。

function loadShader(gl, type, source) {    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);    return shader;
}
  • gl.createShader(type) :根據着色器類型創建着色器對象的方法。

  • gl.shaderSource(shader, source):將着色器源文件傳入着色器對象中,這裏的着色器源文件就是咱們以前在script 裏用GLSL ES寫的着色程序。

  • gl.compileShader(shader):編譯着色器對象。

在之後的學習裏,initShaders 會常常用到,因此咱們能夠將其模塊化。

function initShaders(gl,vsSource,fsSource){    //建立程序對象
    const program = gl.createProgram();    //創建着色對象
    const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);    const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);    //把頂點着色對象裝進程序對象中
    gl.attachShader(program, vertexShader);    //把片元着色對象裝進程序對象中
    gl.attachShader(program, fragmentShader);    //鏈接webgl上下文對象和程序對象
    gl.linkProgram(program);    //啓動程序對象
    gl.useProgram(program);    //將程序對象掛到上下文對象上
    gl.program = program;    return true;
}function loadShader(gl, type, source) {    //根據着色類型,創建着色器對象
    const shader = gl.createShader(type);    //將着色器源文件傳入着色器對象中
    gl.shaderSource(shader, source);    //編譯着色器對象
    gl.compileShader(shader);    //返回着色器對象
    return shader;
}export {initShaders}

後面在須要的時候,import 引入便可。

import {initShaders} from '../jsm/Utils.js';
相關文章
相關標籤/搜索