webgl初章:進入3D世界

終于要進入到webgl的世界了。還真是有點小激動。在之前的文章里,跟大家詳細分享了下 canvas 的相關(guān)內(nèi)容。下面會有這幾篇文章的鏈接,有興趣的小伙伴可以自行查閱。

canvas入門篇 一

canvas入門篇 二

canvas實戰(zhàn)篇

準備好了嗎?接下來讓我們開啟奇幻旅程,進入 3D 的世界。

1. 認識3D

首先我們要介紹的是幾個概念,這是我們要進入到 3D 不可或缺的內(nèi)容。認識一下它們吧。

1.1 視點,視線,目標點,上方向

這幾個概念在webgl中屬于最常見的內(nèi)容。

  • 視點:可以簡易的理解為眼睛,也叫觀察點
  • 目標點:可以理解為我們要看的物體(任何物體)
  • 上方向:頭頂?shù)姆较颉?/strong>

實際生活中,我們的目光總是以我們的眼睛為起始點,到達我們想要看到的物體,同時,我們觀察的角度不同,物體也會呈現(xiàn)不一樣的形態(tài)。以一張圖說明吧。

視點視線上方向.png

如此幾個內(nèi)容,創(chuàng)建出了3D世界的基本顯示模型,由此可見其重要程度。后面我們也會說到如何在 webgl 中設(shè)定這幾個內(nèi)容。也會有的小伙伴把視點稱為相機,目標點稱為畫布。其實是一樣的道理。按照自己的理解記憶就好。

1.2 可視范圍

可視范圍指的是我們所能看到的最大范圍。如:一般情況下我們看不到自己身后的事物。

眾所周知,三維物體具有深度的概念。在我們的理解中,深度就是 z 軸。

雖然我們可以將物體放置在三維空間中的任何位置,但是在webgl中,可視范圍之外的物體是不被繪制的,這也是為了節(jié)省開銷。

1.3 可視空間

水平視角、垂直視角、可視深度 定義了可視空間的概念。

可視空間分為兩種。

  • 正射投影:與物體的遠近無關(guān),通常用在建筑設(shè)計和建模上。
正射投影.png
  • 透視投影:我們平時觀察的真實世界都是透視投影。更有深度的感覺。
透視投影.png

1.3 著色器

如果想渲染 3d 圖形,就需要經(jīng)過一系列的步驟,這些步驟稱為渲染管線。在開發(fā) webgl 程序時,我們就需要通過著色器語言跟GPU進行溝通,用來設(shè)定我們需要渲染和顯示的圖形。

由此可見:著色器是編寫webgl時最重要的一點(沒有之一)。我們之所以能生成并操作3d圖像,都是因為著色器在起作用。webgl中著色器分為兩種。頂點著色器和片元著色器

1.3.1 頂點著色器

這里的頂點代表的是組成物體的每一個點。

頂點著色器的功能主要是將位置數(shù)據(jù)經(jīng)過矩陣變換、計算光照之后生成頂點顏色、變換紋理坐標。并將生成的數(shù)據(jù)輸出到片元著色器。

1.3.2 片元著色器

片元著色器的作用是將光柵化階段生成的每個片元,計算出每個片元的最終元素。

注:

由于著色器內(nèi)容比較重要,這里我們先引入這兩個概念,先簡單理解就可以,后面專門對著色器進行分享。

2. 繪制圖形

2.1 獲取繪圖上下文

了解了第一小節(jié)的內(nèi)容之后,我們開始進入到webgl開發(fā)實戰(zhàn)中。

還記得canvas中第一步需要干什么嗎?

沒錯,需要獲取 canvas 元素和繪圖上下文。webgl 開發(fā)也不例外,也需要首先獲取元素和繪圖上下文。形如下方代碼所示:

// <canvas id="canvas"></canvas>  canvas的dom結(jié)構(gòu)

// 獲取canvas元素
const ctx = document.getElementById('canvas') 

// 獲取繪圖上下文
const gl = ctx.getContext('webgl')

2.2 初始化著色器

1. 編寫著色器代碼

獲取到繪圖上下文之后,我們需要初始化webgl 的著色器了,著色器代碼是以字符串的形式嵌入到渲染程序中,所以我們需要編寫兩個著色器的字符串。

// 頂點著色器
const VERTEX_SHADER = '' +
      'void main(){' +
      ' gl_Position = vec4(0.0,0.0,0.0,1.0);' +
      ' gl_PointSize = 15.0;' +
      '}' +
      ''
// 片元著色器
const FRAGMENT_SHADER = '' +
      'void main() {' +
      ' gl_FragColor = vec4(1.0,0.0,0.0,1.0);' +
      '}' +
      ''

兩個著色器代碼都是以字符串的形式存在,并在執(zhí)行渲染時嵌入到渲染流程內(nèi)。

說明:

  • void main() {}: 創(chuàng)建一個主函數(shù)。
  • gl_Position: 指定繪制的坐標,接收一個擁有4個浮點分量的vec4數(shù)據(jù)。分別代表 x,y,z,w數(shù)據(jù)
  • gl_PointSize: 表示要繪制圖形的尺寸大小。
  • gl_FragColor: 定義圖形顏色,1.0 0.0 0.0 1.0 分別代表r g b a
2. 創(chuàng)建著色器

當然,只是編寫完著色器代碼依然不能完成渲染工作,接下來我們就需要將著色器添加到渲染流程內(nèi)

// 首先創(chuàng)建頂點和片元著色器

// 創(chuàng)建頂點著色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);

// 創(chuàng)建片元著色器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
3. 著色器編譯

完成上述兩步之后,我們就需要將著色器代碼添加到著色器中。看下例子。

// 將頂點著色器代碼添加到頂點著色器中
gl.shaderSource(vertexShader, VERTEX_SHADER);

// 將片元著色器代碼添加到片元著色器中
gl.shaderSource(fragmentShader, FRAGMENT_SHADER);

// 添加完成后,需要編譯著色器
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
4. 創(chuàng)建 program

完成編譯之后,我們需要將著色器添加到渲染程序中。

const program = gl.createProgram();

// 將著色器添加到程序中
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);

// 關(guān)聯(lián)program
gl.linkProgram(program);

// 使用program
gl.useProgram(program);
5. 繪制圖形

完成上述步驟之后,就可以繪制我們的圖形了。這里我們以一個點為例。在畫布上繪制一個點出來。

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

此時就可以打開頁面,看到我們繪制的這個點了。

總結(jié)代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>webgl初章:進入3D世界</title>
</head>
<body>

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

<script>
  const ctx = document.getElementById('canvas');

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

  // 頂點著色器
  const VERTEX_SHADER = '' +
    'void main(){' +
    ' gl_Position = vec4(0.0,0.0,0.0,1.0);' +
    ' gl_PointSize = 15.0;' +
    '}' +
    ''

  // 頂點著色器
  const FRAGMENT_SHADER = '' +
    'void main() {' +
    ' gl_FragColor = vec4(1.0,0.0,0.0,1.0);' +
    '}' +
    ''

  // 創(chuàng)建頂點和片元著色器
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

  // 將頂點著色器代碼添加到頂點著色器中
  gl.shaderSource(vertexShader, VERTEX_SHADER);

  // 將片元著色器代碼添加到片元著色器中
  gl.shaderSource(fragmentShader, FRAGMENT_SHADER);

  // 添加完成后,需要編譯著色器
  gl.compileShader(vertexShader);
  gl.compileShader(fragmentShader);

  const program = gl.createProgram();

  // 將著色器添加到程序中
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);

  // 關(guān)聯(lián)program
  gl.linkProgram(program);
  // 使用program
  gl.useProgram(program);

  // 繪制一個點
  gl.drawArrays(gl.POINTS, 0, 1);

</script>
</body>
</html>

由于是初章,內(nèi)容會比較少。今天的內(nèi)容就先分享到這里,Bye~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文地址:WebGL學(xué)習(xí)(2) - 3D場景[https://jeff_zhong.gitee.io/blog/2...
    jeffzhong閱讀 899評論 0 1
  • 對于大多數(shù)做動效的人來說,canvas實際應(yīng)用一般都是2D平面視覺動效,而3D,一般會出動webgl(或者thre...
    羽晞yose閱讀 6,911評論 3 11
  • 一、WebGL 基本認識 WebGL(Web Graphics Library)是一個光柵化引擎,它可以根據(jù)你的代...
    一個笑點低的妹紙閱讀 10,058評論 2 7
  • 久違的晴天,家長會。 家長大會開好到教室時,離放學(xué)已經(jīng)沒多少時間了。班主任說已經(jīng)安排了三個家長分享經(jīng)驗。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,815評論 16 22
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會,身份的轉(zhuǎn)變要...
    余生動聽閱讀 10,834評論 0 11

友情鏈接更多精彩內(nèi)容