以前鋪墊了許多,今天能夠來分享點純乾貨了。html
上一篇已經講述了經過面模擬線條時候,每個頂點的頂點數據包括:端點座標、偏移量、前一個端點座標、後一個端點座標,固然若是咱們經過索引的方式來繪製的話,還包括索引數組,下面的代碼經過傳遞一組線條的端點數組來建立上述相關數據:數組
bk.Line3D = function (points,colors){ this.points = points; this.colors = colors; } bk.Line3D.prototype.computeData = function() { var len = this.points.length; var count = len * 3 * 2; var position = new Float32Array(count); var positionPrev = new Float32Array(count); var positionNext = new Float32Array(count); var color = new Float32Array(count); var offset = new Float32Array(len * 2); var indicesCount = 3 * 2 * (len - 1); var indices = new Uint16Array(indicesCount); var triangleOffset = 0,vertexOffset = 0; for(var i = 0; i < len; i ++){ var i3 = i * 3 * 2; var point = this.points[i]; position[i3 + 0] = point.x; position[i3 + 1] = point.y; position[i3 + 2] = point.z; position[i3 + 3] = point.x; position[i3 + 4] = point.y; position[i3 + 5] = point.z; var r = (i + 1) / len; var g = Math.random(); var b = Math.random(); g = r; b = 0; r = 1- r; color[i3 + 0] = r; color[i3 + 1] = g; color[i3 + 2] = b; color[i3 + 3] = r; color[i3 + 4] = g; color[i3 + 5] = b; if (i < count - 1) { var i3p = i3 + 6; positionNext[i3p + 0] = point.x; positionNext[i3p + 1] = point.y; positionNext[i3p + 2] = point.z; positionNext[i3p + 3] = point.x; positionNext[i3p + 4] = point.y; positionNext[i3p + 5] = point.z; } if (i > 0) { var i3n = i3 - 6; positionPrev[i3n + 0] = point.x; positionPrev[i3n + 1] = point.y; positionPrev[i3n + 2] = point.z; positionPrev[i3n + 3] = point.x; positionPrev[i3n + 4] = point.y; positionPrev[i3n + 5] = point.z; } var idx = 3 * i; var i2 = i * 2; offset[i2 + 0] = 5; offset[i2 + 1] = -5; } var end = count - 1; for(i = 0;i < 6 ;i ++){ positionNext[i] = positionNext[i + 6]; positionPrev[end - i] = positionPrev[end - i - 6]; } for(i = 0;i < indicesCount ;i ++){ if(i % 2 == 0){ indices[triangleOffset ++] = i; indices[triangleOffset ++] = i + 1; indices[triangleOffset ++] = i + 2; }else{ indices[triangleOffset ++] = i + 1; indices[triangleOffset ++] = i; indices[triangleOffset ++] = i + 2; } } this.position = position; this.positionNext = positionNext; this.positionPrev = positionPrev; this.color = color; this.offset = offset; this.indices = indices; };
代碼首先定義了一個類,該類構造函數能夠傳入端點數組;在該類上定義了一個方法 computeData,用來計算頂點數組,每一個頂點包括上文所述的4個信息,另外增長了一個顏色信息。
讀者,能夠結合第二篇的思路和上面的代碼來來理解,此處再也不詳述 代碼的細節。dom
另一個比較重要的代碼是頂點着色器中,經過傳入的這些頂點信息來計算最終的頂點座標,代碼以下:函數
var lineVS = ` attribute vec3 aPosition; attribute vec3 aPositionPre; attribute vec3 aPositionNext; attribute float aOffset; attribute vec3 aColor; varying vec3 vColor; uniform mat4 uWorldViewProjection; uniform vec4 uViewport; uniform float uNear; uniform mat4 uViewMatrix; uniform mat4 uProjectMatrix; vec4 clipNear(vec4 p1,vec4 p2){ float n = (p1.w - uNear) / (p1.w - p2.w); return vec4(mix(p1.xy,p2.xy,n),-uNear,uNear); } void main(){ vec4 prevProj = uWorldViewProjection * vec4(aPositionPre, 1.0); vec4 currProj = uWorldViewProjection * vec4(aPosition, 1.0); vec4 nextProj = uWorldViewProjection * vec4(aPositionNext, 1.0); if (currProj.w < 0.0) { if (prevProj.w < 0.0) { currProj = clipNear(currProj, nextProj); }else { currProj = clipNear(currProj, prevProj); } } vec2 prevScreen = (prevProj.xy / abs(prevProj.w) + 1.0) * 0.5 * uViewport.zw; vec2 currScreen = (currProj.xy / abs(currProj.w) + 1.0) * 0.5 * uViewport.zw; vec2 nextScreen = (nextProj.xy / abs(nextProj.w) + 1.0) * 0.5 * uViewport.zw; vec2 dir; float len = aOffset; if(aPosition == aPositionPre){ dir = normalize(nextScreen - currScreen); }else if(aPosition == aPositionNext){ dir = normalize(currScreen - prevScreen); }else { vec2 dirA = normalize(currScreen - prevScreen); vec2 dirB = normalize(nextScreen - currScreen); vec2 tanget = normalize(dirA + dirB); float miter = 1.0 / max(dot(tanget,dirA),0.5); len *= miter; dir = tanget; } dir = vec2(-dir.y,dir.x) * len; currScreen += dir; currProj.xy = (currScreen / uViewport.zw - 0.5) * 2.0 * abs(currProj.w); vec4 pos = uProjectMatrix * uViewMatrix * vec4(aPosition,1.0); vColor = aColor; gl_Position = currProj; } `;
計算的原理,也能夠參考第二篇的論述,此處須要注意的是,爲了可以計算頂點在屏幕上的最終位置,須要把canvans的尺寸大小傳遞給着色器(uniform 變量 uViewport),一樣爲了計算裁剪,須要把鏡頭的near值傳遞給着色器(uniform 變量 uNear),而變量uWorldViewProjection表示模型視圖透視變換的矩陣,熟悉WebGL的同窗必定清楚。post
若是你對WebGL 感興趣,能夠了解下咱們用WebGL開發的3D機房項目:this
關於這個話題就先分享到這裏了,若是你們對其它方面與興趣的,咱們也能夠一塊兒來探討。url