標籤:

WebGL 繪製Line的bug(三)

WebGL 繪製Line的bug(三)

來自專欄計算機圖形學 前端可視化 WebGL

上一篇已經講述了通過面模擬線條時候,每一個頂點的頂點數據包括:端點坐標、偏移量、前一個端點坐標、後一個端點坐標,當然如果我們通過索引的方式來繪製的話,還包括索引數組,下面的代碼通過傳遞一組線條的端點數組來創建上述相關數據:

```

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個信息,另外增加了一個顏色信息。

讀者,可以結合第二篇的思路和上面的代碼來來理解,此處不再詳述 代碼的細節。

另外一個比較重要的代碼是頂點著色器中,通過傳入的這些頂點信息來計算最終的頂點坐標,代碼如下:

```

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的同學一定清楚。

請關注公眾號ITman彪叔。

ITman彪叔公眾號


推薦閱讀:

Mantis 搭建及自定義心得
解Bug之路-Druid的Bug
《羅伯特議事規則》也有bug?
Bug追蹤管理簡史
Weekly Beta Apps 第5期

TAG:Bug | OpenGL | WebGL |