<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      圖形學

      圖形學就是在一個二維的平面上展示三維模型.
      這里我們用H5的canvas來演示. 我們不會用canvas的任何畫圖的方法, 只是把他當作一個屏幕來使用.

      三維模型

      要將三維物體,表現在二維平面上, 首先我們要有一個三維的模型.我們要先知道,如何在一個三維坐標系中構造一個物體的模型.
      這個模型是怎么做的呢. 他一般包含一下幾點

      中心點和旋轉角度.

      中心點一般用來確定一個模型在三維坐標系中的具體位置. 一般用 x, y, z 表示.中心點移動, 模型上的所有坐標跟著移動. 模型旋轉時,繞中心點旋轉.

      三角形網絡 和 頂點.

      模型的具體形狀是由三角形拼成的. 如圖所示

      所有的模型都是有一個一個三角形拼成的. 三角形少, 精度就小.三角形多,精度就大. 也就越接近顯示中的物體. 以一個正方體為例, 6個面, 一個面需要兩個三角形拼成, 一共12個三角形.
      三角形的點就是頂點. 一般有很多三角形的頂點是重復的. 立方體一共八個頂點. 代碼實踐中我們是頂點做一個數組. 三角形做一個數組.

      	 let points = [
                  -1, 1,  -1,     // 0
                  1,  1,  -1,     // 1
                  -1, -1, -1,     // 2
                  1,  -1, -1,     // 3
                  -1, 1,  1,      // 4
                  1,  1,  1,      // 5
                  -1, -1, 1,      // 6
                  1,  -1, 1,      // 7
              ]
      
              let vertices = []
              for (let i = 0; i < points.length; i += 3) {
                  let v = GuaVector.new(points[i], points[i+1], points[i+2])
                  // let c = GuaColor.randomColor()
                  let c = GuaColor.red()
                  vertices.push(GuaVertex.new(v, c))
              }
      
              // 12 triangles * 3 vertices each = 36 vertex indices
              let indices = [
                  // 12
                  [0, 1, 2],
                  [1, 3, 2],
                  [1, 7, 3],
                  [1, 5, 7],
                  [5, 6, 7],
                  [5, 4, 6],
                  [4, 0, 6],
                  [0, 2, 6],
                  [0, 4, 5],
                  [5, 1, 0],
                  [2, 3, 7],
                  [2, 7, 6],
              ]
      

      在上述代碼中, points就是頂點的數組, 每三個元素是一組坐標,表示該頂點的x,y,z.
      indices是三角形的數組, 第一個元素[0, 1, 2] 表示第一個三角形. 這里的0表示 頂點數組里的第0個頂點.

      頂點的屬性.

      頂點的屬性包括,坐標(x, y, z), 顏色(rgba), 法向量(fx, fy, fz), 貼圖.

      • 坐標就是這個點在三維坐標系中的坐標.
      • 顏色就是rgba顏色.
      • 法向量就是這個點的垂直方向. 法向量屬性這里和我們的數學嘗試有些區別. 一個點為什么會有法向量呢?
        原因在于我們這里的頂點并不是數學意義上的點. 數學上的點是沒有大小,寬高,方向的. 但是我們這里的頂點有. 嚴格意義上來說 這里的頂點是一個長寬都是1像素的面,是面的最小組成單元 .他有坐標, 有寬高都是1,既然是面當然有法向量. 又因為他足夠小.能夠近似的看做點.
      • 貼圖. 貼圖指的是, 這個模型的顏色不是單一的顏色, 而是一張圖. 一般會有一個貼圖文件. 貼圖文件里保存的是每一個頂點上應該填充的顏色. 頂點的貼圖屬性里保存的就是這個顏色值在貼圖文件中的位置.

      視角

      視角就是三維空間中我們觀察模型時的視線. 視角有三個屬性.
      
      • position: 視角的坐標,就是眼睛的坐標
      • target: 我們的視角觀察的目標的坐標. position和target連起來就是視線
      • up: 是position到target的距離.
        這三個屬性確定一個視角. 視角移動的話, 三維模型的投影也會發生變化.

      光照陰影

      光照陰影(shading). 在二維坐標系中模擬顯示中的物體還要考慮光照問題. 我們看到的顏色是物體反射光的顏色. 光線照射到物體上的角度不同, 物體上光線的強度就不同.
      就是有一個光源, 他發射除了光線, 光線照射到 物體上, 由于角度不同導致了, 雖然物體上的顏色相同, 但是看起來顏色有區別, 有高光, 有陰影.比如物體模型是紅色, 光線與三角形是垂直關系90°展示正紅色, 不是垂直是60°, 是暗紅色, 隨著角度越來越小,顏色越來越暗. 也就是說點的顏色要根據法向量和光線的夾角來計算.
      根據計算方式不同, 會有不同效果.
      如下圖所示

      這是不同的光照模型和不同精度下模型的效果.  從上到下是精度越來越高, 從左到右是 光照的計算越來越精細.
      
      • 左1(a1), (flat shading)是一個三角形用一個法向量, 所以一個平面的光照是一樣的.
      • 左2(b1),(goraud shading) 是一個頂點一個法向量, 一個三角形就有三個法向量. 其他點用頂點的光照計算插值.
      • 左3(c1), (phong shading) 是先 一個頂點一個法向量, 然后,用這三個頂點的法向量 插值計算其他點的法向量, 然后再計算光照. 所以c1即便模型精度很低, 但是也依然有了一個精度相對高的光照.

      這是不同光照下的法向量方向.

      二維平面

      像素

      要在二維平面上展示圖像, 基礎是畫點. 一張圖片是由像素組成的. 比如 一張分辨率為50*100的png圖片. 那么這張圖長寬有50個像素, 高有100個像素.像素就是圖片最基礎的組成單元. 所有的圖片都是由像素組成. 
      像素的屬性包括: 坐標x, y表示像素的位置. rgba表示像素的顏色.比如紅色用rgba表示就是(255, 0, 0, 255). rgba的每一個值都是0-255. 用二進制表示剛好一個字節的數據量. 
      

      以H5中的canvas圖片的像素為例.

      	  var c=document.getElementById("myCanvas");
              var ctx=c.getContext("2d");
              ctx.fillStyle="red";
              ctx.fillRect(0, 0, 50, 50);
              
              // 獲取canvas上的像素數據. 參數(x, y, w, h)
              var imgData=ctx.getImageData(0, 0, 50, 50);
      
              imgData.data[1] =  255
              ctx.putImageData(imgData,10,10);
              // 使用putImageData之后, 會直接改變canvas上的像素顏色.
      

      這里的imgData就是canvas中的像素數據. 格式如下

      		{
      			height: 50,
      	        width: 50,
      	        data: [
      	            255, 0,0, 255,
      	            255, 0,0, 255,
      	            255, 0,0, 255,
      	            ......
      	            ]
      		}
      

      這里的imgData表示這張canvas圖片, 高50像素, 寬50像素. data里面的數據是從左上角開始,從左到右, 從上到下依次排列. 每4個元素表示該像素的顏色信息. 比如第一個像素的rgba是(255, 0, 0, 255).
      一共由 50 * 50 = 2500個像素, 每個像素用4個數據表示顏色. 所以在data里由10000個元素.

      所以只要我們有了一張圖的像素信息, 就能直接把這張圖展示出來.

      光柵化

      我們現在有了一個三維的立體模型, 屏幕是二維的, 要在一個二維屏幕上展示三維圖形, 就需要把三維圖形投影到二維平面上, 用像素展示出來, 稱為為光柵化.
      比如:

      上圖就是一個立方體在二維平面中的投影. 如果我們轉變觀察這個立方體的角度, 這個投影的形狀也會發生改變. 從三維立體圖形, 到二維平面的投影圖, 我們可以通過三角函數計算, 獲得最終的尺寸. 那么針對一個三維模型, 我們要考慮他的旋轉角度, 相對于遠點的位移, 觀察的視角, 以及投影面. 這些都考慮到后, 我們就能得到一個貼近于真是的投影圖.

      矩陣

      上面說了, 要從三維模型的坐標, 考慮很多條件, 用三角函數來計算出最終投影到平面上的二維坐標. 但是這樣一個個計算太過復雜, 一般都是通過矩陣來直接計算的. 矩陣能將三維模型的坐標點, 直接轉換成要投影的二維坐標, 常用的矩陣包括:

      • 計算旋轉角度的旋轉矩陣rotation
      • 計算模型位移的位移矩陣translation
      • 確認觀察視角的視角矩陣view
      • 把三維坐標轉換成二維坐標的投影矩陣projuction

      矩陣是跟著模型走的, 一個單獨的模型, 比如說房間里的一張床, 一個桌子, 當他移動的時候, 所有的點都跟著移動. 當他旋轉的時候, 所有的點都跟著旋轉.這個模型有一個中心點和旋轉角度來確定他在三維空間的位置, 比如水平旋轉了30°, 根據中心點, 和 旋轉角度, 一個桌子上的點就能算出旋轉后的位置, 旋轉矩陣就是做這個地, 位移矩陣就是計算當中心點移動了10個像素后, 其他點的位置. 旋轉矩陣和位移矩陣是計算模型在移動后的三維空間的坐標, 視角矩陣是當三維空間的視角變化后, 模型在三維空間的坐標變化. 投影矩陣是將三維坐標轉換成二維坐標.

      	    // 視角矩陣
      	    const view = Matrix.lookAtLH(position, target, up)
              // 投影矩陣
              const projection = Matrix.perspectiveFovLH(0.8, w / h, 0.1, 1)
      
              // 得到 mesh 中點在世界中的坐標
              const rotation = Matrix.rotation(mesh.rotation)	//旋轉矩陣
              const translation = Matrix.translation(mesh.position)	//位移矩陣
              const world = rotation.multiply(translation)	// 世界矩陣
      
              // transform就是最后的矩陣.
              const transform = world.multiply(view).multiply(projection)
      

      矩陣可以相乘, 相乘的效果與依次使用是一樣的.

      深度

      一個三維模型投影到二維平面, 因為我們看到是投影, 看到正面的話,就不能看到背面. 而且正面和背面雖然在二維平面的坐標是一樣的, 但是顏色是不一樣的. 那么我們怎么確定具體畫哪個點呢?
      就用深度.
      一個三維的頂點經過矩陣計算后得到的除了x,y二維坐標, 還有一個深度. 這個深度是和視角的距離. 如果和視角的距離近, 那么就展示,如果相對較遠, 就不畫. 一般來說是保存一個 二維平面上已經畫好的點的數組 .這個點的信息就包括他在二維平面上的坐標,顏色,深度. 再畫點時, 先判斷這個點的坐標是否已經畫過了, 如果沒有,就畫上. 如果畫過了, 對比深度.如果當前點的深度更近,就把原來的覆蓋掉, 否則不畫.

      插值

      我們的圖形是以三角形為基礎的, 圖像信息都是存儲在頂點上的, 頂點上的坐標, 顏色都有了, 但是我們不能只畫頂點, 那么兩個頂點之間的點的圖像信息是怎么得到的呢?
      就是用插值計算得到的.
      比如說有兩個點.

      • A點,坐標(10, 10).顏色紅色(255, 0, 0, 255)
      • B點, 坐標(50, 50). 顏色綠色(0, 255, 0, 255)

      現在要問處于這兩點之間的C點的顏色和坐標.
      首先計算factor, 過渡因子.
      首先計算AB的長度.

      var x1 = 10, y1 = 10, x2 = 50, y2 = 50 
      // 長度s
      var s = (  (x2 - x1) ** 2 + (y2 - y1) ** 2 ) ** 0.5
      
      // 假設我們要畫AB上距離A點10像素的點, 根據點距A的距離占總距離的比例,計算到他的坐標
      var factor = 10 / s
      
      var x = factor * (x2 - x1) + x1
      var y = factor * (y2 - y1) + y1
      
      

      顏色的插值計算與坐標一樣.
      C點是AB的中心點, 那么C的坐標就是(30, 30), 顏色(128, 128, 0, 255).所有的計算中有小數的四舍五入.
      畫線就是把AB兩點之間的所有的點, 根據這個點的所在位置,計算插值, 然后把所有的點都畫出來.

      畫三角形

      現在二維平面上的三角形點的信息有了, 根據插值我們能畫線了. 那么三角形這個面怎么畫呢?

      首先我們有三角形的三個頂點A B C按Y軸坐標排列, a.y > b.y > c.y.
      對AC邊求得M點(m.y == b.y). 三角形就被劃分成了AMB, MBC兩個三角形.
      然后先畫AMB.
      從上到下, 從A點開始畫平行線. 根據距離A點的高度, 算出factor,計算插值, 然后找出AM上的sx點和 AB上的ex點. sx-ex線與MB平行. 這算是在AMB三角形中填了一條線. 然后再用平行線一條一條把整個AMB填滿, 從上到下, 如果A距離MB的高度為10, 那就是10條線.
      AMB畫完了再畫MBC.
      一個三角形畫完了, 把所有的三角形都畫完.整個立體圖形就都出來了.

      posted on 2020-11-06 19:11  下輩子當座橋-李飛  閱讀(621)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 综合色一色综合久久网| 成人av午夜在线观看| 国产成人精品永久免费视频| 91青青草视频在线观看| 人妻无码∧V一区二区| 精品国产免费一区二区三区香蕉| 日韩有码中文字幕第一页| 国产精品中文字幕综合| 亚洲日韩久热中文字幕| 四虎精品国产精品亚洲精| 中文字幕无码免费久久9一区9| 婷婷丁香五月深爱憿情网| 野外做受又硬又粗又大视频√| 粉嫩蜜臀av一区二区绯色| 一区二区中文字幕久久| 中文字幕av无码免费一区| 风韵丰满妇啪啪区老老熟女杏吧| 加勒比无码av中文字幕 | 国产精品一区二区插插插| 大香伊蕉在人线国产最新2005| 奇米四色7777中文字幕| 亚洲精品尤物av在线网站| 香港日本三级亚洲三级| 久久精品国产亚洲AⅤ无码| 偷看少妇自慰xxxx| 日韩高清视频 一区二区| 国产精品无遮挡猛进猛出| 成人欧美一区二区三区在线观看 | 国产成人片无码视频在线观看| 国产精品免费看久久久| 激情综合网激情五月我去也| 小污女小欲女导航| 亚洲国内精品一区二区| 日韩一区二区三区在线视频| 欲乱人妻少妇邻居毛片| 女人腿张开让男人桶爽| 亚洲男人天堂一级黄色片| 暖暖影院日本高清...免费| 久久青草国产精品一区| 精品午夜福利无人区乱码| 视频二区国产精品职场同事|