1. 程式人生 > >WebGL 繪制Line的bug(三)

WebGL 繪制Line的bug(三)

端點 man new 偏移 dice position 視圖 1.0 裁剪

上一篇已經講述了通過面模擬線條時候,每一個頂點的頂點數據包括:端點坐標、偏移量、前一個端點坐標、後一個端點坐標,當然如果我們通過索引的方式來繪制的話,還包括索引數組,下面的代碼通過傳遞一組線條的端點數組來創建上述相關數據:
?```
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彪叔公眾號

WebGL 繪制Line的bug(三)