Learning the WebGL

\color{blue}{ch2}

坐標圖

canvas1.png

canvas的坐標橫軸為x軸(正方向朝右),縱軸為y軸(正方向朝下)

canvas3.png

webgl的右手坐標

canvas4.png

對應坐標

繪圖簡單步驟

canvas2.png
  1. 獲取canvas: var canvas = doucment.getElementById('webgl')
  2. 獲取上下文: var gl = getWebGLContext(canvas)
  3. 初始化著色器 initShader(gl, VSHADER_SOURCE, FSHADER_SOURCE)
  4. 設置背景色: gl.clearColor(0.0, 0.0, 0.0, 1.0)
  5. 清空canvas: gl.clear(gl.COLOR_BUFFER_BIT)
  6. 繪圖: gl.drawArrays(gl.POINTS, 0, 1)

使用變量

  1. 聲明: attribute vec4 a_Position;\n
  2. 將變量賦值給gl_Position: gl_Position = a_Position;\n
  3. 向變量傳輸數據:

var a_Position = gl.getAttribLocation(gl.program, 'a_Position')
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0)

要點

  1. WebGL程序包括運行在瀏覽器中的Javascript和運行在WebGL系統的著色器程序倆個部分
  2. vec4 四個浮點數 組成的矢量(也稱為齊次坐標是四維的,通常把最后一個變量設置為1.0代表三維)
  3. 頂點著色器兩個內置變量: gl_Position, gl_PointSize
  4. 片元著色器內置變量: gl_FragColor
  5. attribute變量: 傳輸與頂點相關的數據, unifrom變量傳輸對所有頂點相同的數據(或與頂點無關)

\color{blue}{ch3}

繪制多點(使用緩沖區(qū))

  1. 創(chuàng)建緩沖區(qū)對象: var vertexBuffer = gl.creteBuffer()
  2. 綁定緩沖區(qū)對象: gl.bindBuffer(gl.ARRAY_BUFFER, vextexBuffer)
  3. 將數據寫入緩沖區(qū): gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
  4. 將緩沖區(qū)對象分配給一個attribute變量(多點一次性分配)): gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)
  5. 開啟attribute變量(為了使頂點著色器能夠訪問緩沖區(qū)數據): gl.enableVertexAttribArray(a_Position)

要點

  1. new Float32Array([])類型化數組: BYTES_PER_ELEMENT 數組中每個元素所占的字節(jié)數

WebGl繪制基本圖形

gl.drawArrays(gl.TRIANGLES, 0, n)

canvas5.png

\color{blue}{ch4}

變換矩陣步驟

  1. 為旋轉矩陣創(chuàng)建Matrix對象: var xformMatrix = new Matrix4()
  2. 將xformMatrix設置為旋轉矩陣: xformMatrix.setRotate(ANGLE, 0, 0, 1)
  3. 將旋轉矩陣傳輸給頂點著色器: gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix.elements)
  4. varying變量的作用是從頂點著色器向片元著色器傳輸數據

要點

  1. gl.uniformMatrix4fv()的最后一個參數一定要是類型化數組
  2. 將變換全部復合在一起的矩陣稱為模型矩陣
  3. 當有多種數據傳輸時,可以使用多個緩沖區(qū)存不同數據或者使用一個緩沖區(qū)進行數據的交錯組織

一個緩沖區(qū)處理多種數據

canvas6.png

傳輸顏色

varying vec4 v_Color;\n +
.......
v_Color = a_Color;\n+
.......
gl_FragColor = v_Color;\n+

調用片元著色器

片元著色器計算出該片元的顏色,并寫入顏色緩沖區(qū),直到第15部最后一個片元被處理完成,瀏覽器就會顯示處最終的結果

canvas7.png

\color{blue}{ch6}

要點

  1. vec4 v4 = vec4(1.0, 2.0, 3.0, 0.0) 可以通過v4.x, v4.y, v4.z訪問
  2. 存儲限定字Attribute變量: 只能出現在頂點著色器中,“逐頂點”
  3. uniform變量: 逐片元或頂點共用
  4. varying: 從頂點著色器向片元著色器傳輸數據, 但變量一定是同名和同類型的varying變量

\color{blue}{ch7}

視圖矩陣

視圖矩陣表示觀察者的狀態(tài):觀察者的視點,觀察點,上方向

canvas8.png

視圖矩陣步驟

  1. uniform mat4 u_ViewMatrix;\n 用來接收視圖矩陣
    .......
  2. gl_Position = u_ViewMatrix * a_Position;\n 視圖矩陣與頂點坐標相乘
    .......
  3. var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix) 獲取存儲位置
  4. var viewMatrix = new Matrix4()
  5. viewMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0) 設置視點,視線和上方向
  6. gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements) 傳輸

要點

  1. 將平移,縮放等基本變換矩陣或它們的組合稱為模型矩陣
  2. <視圖矩陣> x <模型矩陣> x <原始頂點坐標>
  3. 也可以將視圖矩陣和模型矩陣相乘的結果成為模型視圖矩陣: var modelViewMatrix = viewMatrix.multiply(modelMatrix)
  4. <投影矩陣> x <視圖矩陣> x <模型矩陣>稱為模型視圖投影矩陣

鼠標或鍵盤控制思路

  1. 在main()里注冊事件, 參數有:事件, gl, 頂點數, 視圖矩陣儲存位置, 視圖矩陣document.onkeydown = function(ev){keydown(ev, gl, n, u_ViewMatrix)}
  2. 在main()里畫初始的(還沒調用keydown函數): draw(gl, n, u_ViewMatrix, viewMatrix)
  3. 在keydown改變viewMatrix.setLookAt()參數, 最后調用draw畫圖
  4. 執(zhí)行draw:傳遞viewMatrix, gl.drawArrays(gl.TRIANGLES, 0, n)

可視空間

  1. 盒子空間, 由正射投影產生: 大小與其所在的位置沒有關系(不能產生深度感), 用到的矩陣是 正射投影矩陣(OrthoView)
canvas9.png
canvas10.png
canvas11.png
  1. 金字塔可視空間, 由透視投影產生: 一般真實的世界用的都是透視投影, 用到矩陣是 透視投影矩陣(projMatrix)
canvas12.png
canvas13.png
canvas14.png

處理對象的前后關系

  1. WebGL會按照緩沖區(qū)的順序繪制圖形,而且后繪制的圖形覆蓋先繪制圖形
  2. 可以利用WebGL提供的隱藏面消除功能消除
  3. 步驟:

開啟隱藏面消除功能 gl.enable(gl.DEPTH_TEST)
在繪制之前,清除深度緩沖區(qū) gl.clear(gl.DEPTH_BUFFER_BIT)

  1. 深度緩沖區(qū)就是用來存儲深度信息的,所以在繪制一幀之前,都必須清除緩沖區(qū)(包括顏色和深度): gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

畫3D圖使用索引

  1. 使用gl.drawElements()代替gl.drawArrays()
  2. 上面兩種方法的區(qū)別在于gl.ELEMENT_ARRSY_BUFFERT它管理著具有索引結構的三維模型數據
    canvas15.png
  3. 索引值是整型數,使用Uint8Array


    canvas16.png
  4. 當多次調用緩沖區(qū)時,可以把緩沖區(qū)封裝成一個函數,initArrayBuffer(gl, data, num, type, attribute)

其中data為頂點或者顏色坐標,type表示坐標的類型, attribute代表變量名, num代表每個頂點的占位數

\color{blue}{ch8}

反射類型

  1. 漫反射(diffuse)

<漫反射光顏色> = <入射光顏色> x <表面基底色> x cosa

  1. 環(huán)境反射(ambient)

<環(huán)境反射光顏色> = <入射光顏色> x <表面基底色>

物體最終顏色

<表面的反射光顏色> = <漫反射光顏色> + <環(huán)境反射光顏色>

平行光下的漫反射

  1. 入射角cosa = <光線方向> · <法線方向>,兩者的點積,兩個向量進行歸一化
  2. 平面上任意一點都具有相同的法向量, 所以頂點坐標個數頂點顏色個數法線量個數要保持一致
  3. 歸一化(normalize)光線以Float32Array類型的形式儲存在lightDirection對象的elements屬性中

運動物體光照

  1. 對頂點坐標進行變換的模型矩陣

變換后的法向量: 用法向量乘以模型矩陣的逆轉矩陣\color{green}{modelMatrix}

求逆轉置步驟:

  1. 求原矩陣的逆矩陣 normalMatrix.setInverseOf(modelMatrix)
  2. 將上一步的求得的逆矩陣進行轉置normalMatrix.transpose()
    這里的用normalMatrix來存儲

點光源的漫反射

  1. 在物體不同位置(不同頂點)的入射光的方向不同
  2. 計算頂點的入射光的方向步驟:
  1. 計算模型變換后的頂點坐標(世界坐標)var vertexPosition = u_ModelMatrix * a_Position
  2. 光線方向是由點光源坐標減去頂點坐標,在進行歸一化 vec3 lightDirecti on = normalize(u_LightPosition - vec3(vertexPosition))

要點

  1. 為了更逼真:逐片元光照

\color{blue}{ch9}

要點

  1. 模型矩陣(\color{red}{modelMatrix}): 變換原始頂點坐標(旋轉,平移,縮放)
  2. 視圖矩陣(\color{red}{viewMatrix}): 觀察者狀態(tài)lookAt
  3. 投影矩陣(\color{red}{projMatrix}): 可視空間包括setPerspective, setOrtho
  4. 一組頂點多次復用時,平移和旋轉都有類似的光標概念

層次結構模型

  1. 例:單關節(jié)模型
  1. 初始化頂點坐標和顏色緩沖區(qū)n = initVertexBuffer(gl)
  2. 注冊鍵盤事件,參數:ev, gl, n(頂點索引數組個數), viewProjMatrix(投影矩陣) , u_MvpMatrix(投影視圖模型矩陣), uNormalMatrix
  3. 觸發(fā)鍵盤事件, 改變全局變量g_arm1Angleg_joint1Angle, 從而改變全局模型矩陣g_modelMatrix, 多次調用
  4. 重新計算視圖投影模型矩陣 viewProjMatrix
  1. 例: 多關節(jié)模型
  1. 初始化頂點坐標和顏色緩沖區(qū)n = initVertexBuffer(gl)
  2. 注冊鍵盤事件,參數:ev, gl, n(頂點索引數組個數), viewProjMatrix(投影矩陣) , u_MvpMatrix(投影視圖模型矩陣), uNormalMatrix
  3. 觸發(fā)鍵盤事件, 改變全局變量g_arm1Angleg_joint1Angle, g_joint2Angle, g_joint3Angle, 從而改變全局模型矩陣g_modelMatrix
  4. 多次調用draw畫組件,在畫手指之前緩存g_modelMatrix, pushMatrix存儲矩陣的棧,將矩陣推入棧

\color{blue}{ch10}

紋理圖像步驟

  1. 頂點著色器中接收頂點的紋理坐標, 光柵化后傳遞給片元著色器

var verticesTexCoords = new Float32Array([...])創(chuàng)建頂點坐標和紋理坐標
var a_TexCoord = gl.getAttribLocation()分配并開啟

  1. 片元著色器根據片元的紋理坐標,從紋理圖像中抽取紋素顏色,賦給當前片元

initTextures()函數負責配置和加載紋理:

var texture = gl.createTexture()創(chuàng)建紋理對象來管理紋理
var u_Sampler = gl.getUni...變量用來接收紋理圖像
image.onload = function () { loadTexture(gl, n, texture, u_Sampler, image)}來等圖片加載完成執(zhí)行
loadTexture()用來配置紋理:

  1. gl.pixelStorei()反轉轉y坐標
  2. gl.activeTexture() 激活紋理單元, --管理
  3. gl.bindTexture()綁定紋理對象, --操作
  4. gl.texParameteri() 配置紋理對象的參數
  5. gl.texImage2D()將紋理圖像分配給紋理對象
  6. gl.uniform1i()將紋理單元傳遞給片元著色器
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容