\color{blue}{ch2}
坐標圖

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

webgl的右手坐標

對應坐標
繪圖簡單步驟

- 獲取canvas:
var canvas = doucment.getElementById('webgl') - 獲取上下文:
var gl = getWebGLContext(canvas) - 初始化著色器
initShader(gl, VSHADER_SOURCE, FSHADER_SOURCE) - 設置背景色:
gl.clearColor(0.0, 0.0, 0.0, 1.0) - 清空canvas:
gl.clear(gl.COLOR_BUFFER_BIT) - 繪圖:
gl.drawArrays(gl.POINTS, 0, 1)
使用變量
- 聲明:
attribute vec4 a_Position;\n - 將變量賦值給gl_Position:
gl_Position = a_Position;\n - 向變量傳輸數據:
var a_Position = gl.getAttribLocation(gl.program, 'a_Position')
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0)
要點
- WebGL程序包括運行在瀏覽器中的Javascript和運行在WebGL系統的著色器程序倆個部分
- vec4 四個浮點數 組成的矢量(也稱為齊次坐標是四維的,通常把最后一個變量設置為1.0代表三維)
- 頂點著色器兩個內置變量:
gl_Position, gl_PointSize - 片元著色器內置變量:
gl_FragColor - attribute變量: 傳輸與頂點相關的數據, unifrom變量傳輸對所有頂點相同的數據(或與頂點無關)
\color{blue}{ch3}
繪制多點(使用緩沖區(qū))
- 創(chuàng)建緩沖區(qū)對象:
var vertexBuffer = gl.creteBuffer() - 綁定緩沖區(qū)對象:
gl.bindBuffer(gl.ARRAY_BUFFER, vextexBuffer) - 將數據寫入緩沖區(qū):
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW) - 將緩沖區(qū)對象分配給一個attribute變量(多點一次性分配)):
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0) - 開啟attribute變量(為了使頂點著色器能夠訪問緩沖區(qū)數據):
gl.enableVertexAttribArray(a_Position)
要點
-
new Float32Array([])類型化數組:BYTES_PER_ELEMENT數組中每個元素所占的字節(jié)數
WebGl繪制基本圖形
gl.drawArrays(gl.TRIANGLES, 0, n)

\color{blue}{ch4}
變換矩陣步驟
- 為旋轉矩陣創(chuàng)建Matrix對象:
var xformMatrix = new Matrix4() - 將xformMatrix設置為旋轉矩陣:
xformMatrix.setRotate(ANGLE, 0, 0, 1) - 將旋轉矩陣傳輸給頂點著色器:
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix.elements) - varying變量的作用是從頂點著色器向片元著色器傳輸數據
要點
-
gl.uniformMatrix4fv()的最后一個參數一定要是類型化數組 - 將變換全部復合在一起的矩陣稱為模型矩陣
- 當有多種數據傳輸時,可以使用多個緩沖區(qū)存不同數據或者使用一個緩沖區(qū)進行數據的交錯組織
一個緩沖區(qū)處理多種數據

傳輸顏色
varying vec4 v_Color;\n+
.......
v_Color = a_Color;\n+
.......
gl_FragColor = v_Color;\n+
調用片元著色器
片元著色器計算出該片元的顏色,并寫入顏色緩沖區(qū),直到第15部最后一個片元被處理完成,瀏覽器就會顯示處最終的結果

\color{blue}{ch6}
要點
-
vec4 v4 = vec4(1.0, 2.0, 3.0, 0.0)可以通過v4.x, v4.y, v4.z訪問 - 存儲限定字
Attribute變量: 只能出現在頂點著色器中,“逐頂點” -
uniform變量: 逐片元或頂點共用 -
varying: 從頂點著色器向片元著色器傳輸數據, 但變量一定是同名和同類型的varying變量
\color{blue}{ch7}
視圖矩陣
視圖矩陣表示觀察者的狀態(tài):
觀察者的視點,觀察點,上方向

視圖矩陣步驟
uniform mat4 u_ViewMatrix;\n用來接收視圖矩陣
.......gl_Position = u_ViewMatrix * a_Position;\n視圖矩陣與頂點坐標相乘
.......var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix)獲取存儲位置var viewMatrix = new Matrix4()viewMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0)設置視點,視線和上方向gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements)傳輸
要點
- 將平移,縮放等基本變換矩陣或它們的組合稱為模型矩陣
<視圖矩陣> x <模型矩陣> x <原始頂點坐標>- 也可以將視圖矩陣和模型矩陣相乘的結果成為
模型視圖矩陣:var modelViewMatrix = viewMatrix.multiply(modelMatrix) -
<投影矩陣> x <視圖矩陣> x <模型矩陣>稱為模型視圖投影矩陣
鼠標或鍵盤控制思路
- 在main()里注冊事件, 參數有:事件, gl, 頂點數, 視圖矩陣儲存位置, 視圖矩陣
document.onkeydown = function(ev){keydown(ev, gl, n, u_ViewMatrix)} - 在main()里畫初始的(還沒調用keydown函數):
draw(gl, n, u_ViewMatrix, viewMatrix) - 在keydown改變
viewMatrix.setLookAt()參數, 最后調用draw畫圖 - 執(zhí)行draw:傳遞viewMatrix,
gl.drawArrays(gl.TRIANGLES, 0, n)
可視空間
- 盒子空間, 由
正射投影產生: 大小與其所在的位置沒有關系(不能產生深度感), 用到的矩陣是 正射投影矩陣(OrthoView)



- 金字塔可視空間, 由
透視投影產生: 一般真實的世界用的都是透視投影, 用到矩陣是 透視投影矩陣(projMatrix)



處理對象的前后關系
- WebGL會按照緩沖區(qū)的順序繪制圖形,而且后繪制的圖形覆蓋先繪制圖形
- 可以利用WebGL提供的
隱藏面消除功能消除 - 步驟:
開啟隱藏面消除功能
gl.enable(gl.DEPTH_TEST)
在繪制之前,清除深度緩沖區(qū)gl.clear(gl.DEPTH_BUFFER_BIT)
- 深度緩沖區(qū)就是用來存儲深度信息的,所以在繪制一幀之前,都必須清除緩沖區(qū)(包括顏色和深度):
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
畫3D圖使用索引
- 使用
gl.drawElements()代替gl.drawArrays() - 上面兩種方法的區(qū)別在于
gl.ELEMENT_ARRSY_BUFFERT它管理著具有索引結構的三維模型數據
canvas15.png -
索引值是整型數,使用Uint8Array
canvas16.png - 當多次調用緩沖區(qū)時,可以把緩沖區(qū)封裝成一個函數,
initArrayBuffer(gl, data, num, type, attribute)
其中
data為頂點或者顏色坐標,type表示坐標的類型,attribute代表變量名,num代表每個頂點的占位數
\color{blue}{ch8}
反射類型
- 漫反射(diffuse)
<漫反射光顏色> = <入射光顏色> x <表面基底色> x cosa
- 環(huán)境反射(ambient)
<環(huán)境反射光顏色> = <入射光顏色> x <表面基底色>
物體最終顏色
<表面的反射光顏色> = <漫反射光顏色> + <環(huán)境反射光顏色>
平行光下的漫反射
- 入射角cosa =
<光線方向> · <法線方向>,兩者的點積,兩個向量進行歸一化 - 平面上任意一點都具有相同的法向量, 所以
頂點坐標個數與頂點顏色個數與法線量個數要保持一致 - 歸一化(
normalize)光線以Float32Array類型的形式儲存在lightDirection對象的elements屬性中
運動物體光照
- 對頂點坐標進行變換的模型矩陣
變換后的法向量: 用
法向量乘以模型矩陣的逆轉矩陣\color{green}{modelMatrix}
求逆轉置步驟:
- 求原矩陣的逆矩陣
normalMatrix.setInverseOf(modelMatrix)- 將上一步的求得的逆矩陣進行轉置
normalMatrix.transpose()
這里的用normalMatrix來存儲
點光源的漫反射
- 在物體不同位置(不同頂點)的入射光的方向不同
- 計算頂點的入射光的方向步驟:
- 計算模型變換后的頂點坐標(
世界坐標)var vertexPosition = u_ModelMatrix * a_Position- 光線方向是由點光源坐標減去頂點坐標,在進行歸一化
vec3 lightDirecti on = normalize(u_LightPosition - vec3(vertexPosition))
要點
- 為了更逼真:逐片元光照
\color{blue}{ch9}
要點
- 模型矩陣(\color{red}{modelMatrix}): 變換原始頂點坐標(旋轉,平移,縮放)
- 視圖矩陣(\color{red}{viewMatrix}): 觀察者狀態(tài)
lookAt - 投影矩陣(\color{red}{projMatrix}): 可視空間包括
setPerspective, setOrtho - 一組頂點多次復用時,平移和旋轉都有類似的光標概念
層次結構模型
- 例:單關節(jié)模型
- 初始化頂點坐標和顏色緩沖區(qū)
n = initVertexBuffer(gl)- 注冊鍵盤事件,參數:
ev, gl, n(頂點索引數組個數), viewProjMatrix(投影矩陣) , u_MvpMatrix(投影視圖模型矩陣), uNormalMatrix- 觸發(fā)鍵盤事件, 改變全局變量
g_arm1Angle和g_joint1Angle, 從而改變全局模型矩陣g_modelMatrix, 多次調用- 重新計算視圖投影模型矩陣
viewProjMatrix
- 例: 多關節(jié)模型
- 初始化頂點坐標和顏色緩沖區(qū)
n = initVertexBuffer(gl)- 注冊鍵盤事件,參數:
ev, gl, n(頂點索引數組個數), viewProjMatrix(投影矩陣) , u_MvpMatrix(投影視圖模型矩陣), uNormalMatrix- 觸發(fā)鍵盤事件, 改變全局變量
g_arm1Angle和g_joint1Angle,g_joint2Angle,g_joint3Angle, 從而改變全局模型矩陣g_modelMatrix- 多次調用draw畫組件,在畫手指之前緩存
g_modelMatrix,pushMatrix存儲矩陣的棧,將矩陣推入棧
\color{blue}{ch10}
紋理圖像步驟
- 頂點著色器中接收頂點的紋理坐標, 光柵化后傳遞給片元著色器
var verticesTexCoords = new Float32Array([...])創(chuàng)建頂點坐標和紋理坐標
var a_TexCoord = gl.getAttribLocation()分配并開啟
- 片元著色器根據片元的紋理坐標,從紋理圖像中抽取紋素顏色,賦給當前片元
initTextures()函數負責配置和加載紋理:
var texture = gl.createTexture()創(chuàng)建紋理對象來管理紋理
var u_Sampler = gl.getUni...變量用來接收紋理圖像
image.onload = function () { loadTexture(gl, n, texture, u_Sampler, image)}來等圖片加載完成執(zhí)行
loadTexture()用來配置紋理:
gl.pixelStorei()反轉轉y坐標gl.activeTexture()激活紋理單元, --管理gl.bindTexture()綁定紋理對象, --操作gl.texParameteri()配置紋理對象的參數gl.texImage2D()將紋理圖像分配給紋理對象gl.uniform1i()將紋理單元傳遞給片元著色器

