Opengl ES 线的三角化

 本文主要讨论将线扩展成2d线面的算法

 

如上图所示将p0p1这条直线  扩展成面 很简单     

Vec2f line = p1 - p0

Vec2f normal = Vec2f( -line.y, line.x).normalized().

 

Vec2f a = p0 - thickness * normal;
Vec2f b = p0 + thickness * normal;
Vec2f c = p1 - thickness * normal;
Vec2f d = p1 + thickness * normal;

如果是直线这么处理就可以了,但是如果有多段线,我们还需要计算交点的地方

首先我们先求出 t
Vec2f t = ( (p2-p1).normalized() + (p1-p0).normalized() ).normalized()
其次 在求出m
Vec2f m = Vec2f( -t.y,t.x )
最后再求出d的长度
float d = thickness / miter.dot( normal )

根据上述获得内容就能得到想要的所有顶点,然后根据这些顶点构建三角面片即可

代码大致如下:
 
 void trianglePolyLine( const Vec2f &p0, const Vec2f &p1, const Vec2f &p2, const Vec2f &p3 , PosArray &vtx, IndexArray &indices,double radius)
    {
        if(p1 == p2) return;
        
        Vec2f line = (p2 - p1).normalize();
        
        Vec2f normal = Vec2f(-line.Y, line.X).normalize();
        
        Vec2f tangent1 = (p0 == p1) ? line : ((p1-p0).normalize() + line).normalize();
        Vec2f tangent2 = (p2 == p3) ? line : ((p3-p2).normalize() + line).normalize();
        
        Vec2f miter1 = Vec2f(-tangent1.Y, tangent1.X);
        Vec2f miter2 = Vec2f(-tangent2.Y, tangent2.X);
        
        
        float length1 = radius / normal.dotProduct(miter1);
        float length2 = radius / normal.dotProduct(miter2);
        
        if(true) {
            Vec2f bg1(p1 - length1 * miter1);
            Vec2f ed1(p2 - length2 * miter2);
            Vec2f bg2(p1 + length1 * miter1);
            Vec2f ed2(p2 + length2 * miter2);
            
            int len = vtx.size();
            
            vtx.push_back(Vector3df(bg1.X, bg1.Y,0));
            vtx.push_back(Vector3df(ed1.X, ed1.Y,0));
            vtx.push_back(Vector3df(bg2.X, bg2.Y,0));
            vtx.push_back(Vector3df(ed2.X, ed2.Y,0));
         
            
            indices.push_back( len + 0 );
            indices.push_back( len + 1 );
            indices.push_back( len + 2 );
            indices.push_back( len + 1 );
            indices.push_back( len + 2 );
            indices.push_back( len + 3 );
        }
    }
调用代码如下
 
  for(int i = 0;i<vertexes.size();++i) {
                int a = ((i-1) < 0) ? 0 : (i-1);
                int b = i;
                int c = ((i+1) >= vertexes.size()) ? vertexes.size()-1 : (i+1);
                int d = ((i+2) >= vertexes.size()) ? vertexes.size()-1 : (i+2);
                
                trianglePolyLine( vertexes[a], vertexes[b], vertexes[c], vertexis[d],pts,indices,raidus );
            }
vertexes表示多段线,mesh表示构建的顶点数组 讲次数组直接以GL_Lines绘制
效果大致如下


请注意 以上过程在两段线夹角比较小的时候会出问题,所以请慎用..


geos库中 也有方法提供
测试代码如下
 
 static void createPolyline(PosArray &arr)
    {
        const float len = 100.0;
        geos::geom::GeometryFactory factroy;
        CoordinateArraySequenceFactory csf;
        
        CoordinateSequence *cs1 = (csf.create(3,2));
        cs1->setAt(Coordinate(-len,0,0),0);
        cs1->setAt(Coordinate(-len,len,0),1);
        cs1->setAt(Coordinate(len,len,0),2);
        std::auto_ptr<LineString> ring1(factroy.createLineString(cs1)) ;
        std::auto_ptr<Geometry>  p(ring1->buffer(10));

        std::auto_ptr<CoordinateSequence> pcs(p->getCoordinates());
        
        for(int i = 0; i < pcs->getSize(); ++i)
        {
            Coordinate co = pcs->getAt(i);
            arr.push_back(Vector3df(co.x,co.y,0));
        }
    }

注意 以上生成的顶点数组 还要进行三角剖分(推荐使用gpc),然后再以trianglelist的绘制,或者用以下的算法构建顶点数组
 
struct SDrawVertexColor
{
     Vector3df  pos;
     SColor4f   color;
};
 
typedef std::vector<SDrawVertexColor> PosClrArray;
tpyedef std::vector<int>              IndexArray;

void PolyLine( const Vector3df *pPoints, int nPoints, PosClrArray *outarray,
                              u32 color,  IndexArray *idx, float lineWidth,int zidx /*=0*/)
        {
            if(NULL == pPoints || nPoints<2 || NULL == outarray || lineWidth < 1e-6)
                return;
            
            u32 i_idx = outarray->size();
            Vector2df a,b,aR,aL,bR,bL;
            Vector2df abP,abV,tmp;
            
            Vector3df LindS1[10];
            Vector3df LindE1[10];
            SDrawVertexColor vertexAcc;
            vertexAcc.color =SColor4f(color);
            for ( u32 i=1; i < nPoints; ++i )
            {
                b = ToVector2d(pPoints[i-1]);
                a = ToVector2d(pPoints[i]);
                abP = a-b;
                abP.normalize();
                abV = rotateBy90(abP);
                aR = a + abV * lineWidth;
                aL = a - abV * lineWidth;
                
                bR = b + abV * lineWidth;
                bL = b - abV * lineWidth;
                // 添加第一个点的左右点
                
                LindS1[0] = ToVector3d(b,zidx);
                LindS1[1] = ToVector3d(bR,zidx);
                LindS1[2] = ToVector3d(bL,zidx);
                LindS1[3] = ToVector3d(b - abP * lineWidth,zidx);
                LindS1[4] = ToVector3d(b + (-abP+abV)*0.707f * lineWidth,zidx);
                LindS1[5] = ToVector3d(b + (-abP-abV)*0.707f * lineWidth,zidx);
                LindS1[6] = ToVector3d(b + ((-abP+abV)*0.707f+abV)*0.541f *lineWidth,zidx);
                LindS1[7] = ToVector3d(b + ((-abP+abV)*0.707f-abP)*0.541f *lineWidth,zidx);
                LindS1[8] = ToVector3d(b + ((-abP-abV)*0.707f-abP)*0.541f *lineWidth,zidx);
                LindS1[9] = ToVector3d(b + ((-abP-abV)*0.707f-abV)*0.541f *lineWidth,zidx);
                
                // 添加最后一个点的左右点
                LindE1[0] = ToVector3d(a,zidx);
                LindE1[1] = ToVector3d(aR,zidx);
                LindE1[2] = ToVector3d(aL,zidx);
                LindE1[3] = ToVector3d(a + abP * lineWidth,zidx);
                LindE1[4] = ToVector3d(a + (abP-abV)*0.707f * lineWidth,zidx);
                LindE1[5] = ToVector3d(a + (abP+abV)*0.707f * lineWidth,zidx);
                LindE1[6] = ToVector3d(a + ((abP-abV)*0.707f-abV)*0.541f *lineWidth,zidx);
                LindE1[7] = ToVector3d(a + ((abP-abV)*0.707f+abP)*0.541f *lineWidth,zidx);
                LindE1[8] = ToVector3d(a + ((abP+abV)*0.707f+abP)*0.541f *lineWidth,zidx);
                LindE1[9] = ToVector3d(a + ((abP+abV)*0.707f+abV)*0.541f *lineWidth,zidx);
                
                for (int j=0;j<10;++j)
                {
                    vertexAcc.pos =  LindS1[j];outarray->push_back(vertexAcc);
                }
                idx->push_back(u32(i_idx + 1));
                idx->push_back(u32(i_idx + 0));
                idx->push_back(u32(i_idx + 6));
                idx->push_back(u32(i_idx + 6));
                idx->push_back(u32(i_idx + 0));
                idx->push_back(u32(i_idx + 4));
                idx->push_back(u32(i_idx + 4));
                idx->push_back(u32(i_idx + 0));
                idx->push_back(u32(i_idx + 7));
                idx->push_back(u32(i_idx + 7));
                idx->push_back(u32(i_idx + 0));
                idx->push_back(u32(i_idx + 3));
                idx->push_back(u32(i_idx + 3));
                idx->push_back(u32(i_idx + 0));
                idx->push_back(u32(i_idx + 8));
                idx->push_back(u32(i_idx + 8));
                idx->push_back(u32(i_idx + 0));
                idx->push_back(u32(i_idx + 5));
                idx->push_back(u32(i_idx + 5));
                idx->push_back(u32(i_idx + 0));
                idx->push_back(u32(i_idx + 9));
                idx->push_back(u32(i_idx + 9));
                idx->push_back(u32(i_idx + 0));
                idx->push_back(u32(i_idx + 2));
                
                u32 m_idx = i_idx+10;
                for (int j=0;j<10;++j)
                {
                    vertexAcc.pos =  LindE1[j];outarray->push_back(vertexAcc);
                    
                }
                idx->push_back(u32(m_idx + 1));
                idx->push_back(u32(m_idx + 0));
                idx->push_back(u32(m_idx + 9));
                idx->push_back(u32(m_idx + 9));
                idx->push_back(u32(m_idx + 0));
                idx->push_back(u32(m_idx + 5));
                idx->push_back(u32(m_idx + 5));
                idx->push_back(u32(m_idx + 0));
                idx->push_back(u32(m_idx + 8));
                idx->push_back(u32(m_idx + 8));
                idx->push_back(u32(m_idx + 0));
                idx->push_back(u32(m_idx + 3));
                idx->push_back(u32(m_idx + 3));
                idx->push_back(u32(m_idx + 0));
                idx->push_back(u32(m_idx + 7));
                idx->push_back(u32(m_idx + 7));
                idx->push_back(u32(m_idx + 0));
                idx->push_back(u32(m_idx + 4));
                idx->push_back(u32(m_idx + 4));
                idx->push_back(u32(m_idx + 0));
                idx->push_back(u32(m_idx + 6));
                idx->push_back(u32(m_idx + 6));
                idx->push_back(u32(m_idx + 0));
                idx->push_back(u32(m_idx + 2));
                
                idx->push_back(u32(i_idx + 1));
                idx->push_back(u32(i_idx + 12));
                idx->push_back(u32(i_idx + 11));
                idx->push_back(u32(i_idx + 1));
                idx->push_back(u32(i_idx + 2));
                idx->push_back(u32(i_idx + 12));
                i_idx += 20;
                
            }
        }



 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值