WebGL 繪制Line的bug(三)
?```
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
? ? ? 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);
? ? ? 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 + 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(三)