WebGL 繪制Line的bug(三)

上一篇已經(jīng)講述了通過面模擬線條時(shí)候,每一個(gè)頂點(diǎn)的頂點(diǎn)數(shù)據(jù)包括:端點(diǎn)坐標(biāo)、偏移量、前一個(gè)端點(diǎn)坐標(biāo)、后一個(gè)端點(diǎn)坐標(biāo),當(dāng)然如果我們通過索引的方式來繪制的話,還包括索引數(shù)組,下面的代碼通過傳遞一組線條的端點(diǎn)數(shù)組來創(chuàng)建上述相關(guān)數(shù)據(jù):

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;
};

代碼首先定義了一個(gè)類,該類構(gòu)造函數(shù)可以傳入端點(diǎn)數(shù)組;在該類上定義了一個(gè)方法 computeData,用來計(jì)算頂點(diǎn)數(shù)組,每個(gè)頂點(diǎn)包括上文所述的4個(gè)信息,另外增加了一個(gè)顏色信息。
讀者,可以結(jié)合第二篇的思路和上面的代碼來來理解,此處不再詳述 代碼的細(xì)節(jié)。

另外一個(gè)比較重要的代碼是頂點(diǎn)著色器中,通過傳入的這些頂點(diǎn)信息來計(jì)算最終的頂點(diǎn)坐標(biāo),代碼如下:

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;
    }
`;

計(jì)算的原理,也可以參考第二篇的論述,此處需要注意的是,為了能夠計(jì)算頂點(diǎn)在屏幕上的最終位置,需要把canvans的尺寸大小傳遞給著色器(uniform 變量 uViewport),同樣為了計(jì)算裁剪,需要把鏡頭的near值傳遞給著色器(uniform 變量 uNear),而變量uWorldViewProjection表示模型視圖透視變換的矩陣,熟悉WebGL的同學(xué)一定清楚。

如果你對(duì)WebGL 感興趣,可以了解下我們用WebGL開發(fā)的3D機(jī)房項(xiàng)目:
HTML5,不只是看上去很美(第二彈:打造最美3D機(jī)房)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在OpenGL中,大量的數(shù)據(jù)在著色器中傳遞,數(shù)據(jù)通過Buffer和Texture兩種形式組織。 1 緩存(Buff...
    RichardJieChen閱讀 8,285評(píng)論 1 10
  • WebGL從2012年開始接觸,后面因?yàn)殚_始專注前端其他方面的事情,慢慢地就把它給遺忘。最近前端開始又流行起繪畫制...
    我不是傳哥閱讀 4,363評(píng)論 1 22
  • 第三章 管線一覽 本章我們會(huì)學(xué)到什么 OpenGL管線的每個(gè)階段做什么的 如果連接著色器和固定功能管線階段 如果創(chuàng)...
    葭五閱讀 6,499評(píng)論 2 18
  • 本文梳理了WebGL中從零到渲染出一個(gè)簡單幾何圖形的主要流程。幫助一些剛接觸WebGL的玩家簡單整理下在WebGL...
    肖怡君閱讀 7,761評(píng)論 2 19
  • 我發(fā)了《致即將上大學(xué)童鞋:如何在大學(xué)賺回學(xué)費(fèi)》這一文,就收到一些學(xué)弟學(xué)妹的后臺(tái)留言,要我告訴她們比賽獲獎(jiǎng)的方法。其...
    蘇碧玉閱讀 833評(píng)論 1 0

友情鏈接更多精彩內(nèi)容