OSG环境实现Coons曲面的拼接绘制

最近在捣腾那个曲面的绘制,目的是想要绘制hermite曲面,经过查阅资料,发现coons曲面可以是hermite曲面的很好的实现途径。

coons曲面的简介:

由于是引用资料,在此贴图即可,观者有需要的可以自己搜索coos曲面相关的介绍。














以上便是coons曲面的简单介绍,下面给出例子实现的关键代码,例子代码部分引用网络的代码,有需要的观者可以到pudn网站下载。

关键代码:

(1)产生基函数

void Product(double V[], double p)//产生基函数,UV向均适用
{
double P[N + 1];
P[N] = 1;
for (int i = N - 1; i >= 0; i--)
P[i] = P[i + 1] * p;
V[0] = P[0] * 2 - P[1] * 3 + P[3];
V[1] = P[0] * (-2) + P[1] * 3;
V[2] = P[0] - P[1] * 2 + P[2];
V[3] = P[0] - P[1];
}

(2)产生coons算法的点,传进去的V顶点数组相当于是公式的中间矩阵:


osg::Vec3 coons(osg::ref_ptr<osg::Vec3Array> V, double u, double w)
{
osg::Vec3 pts[N + 1], pt;
double U[N + 1], W[N + 1];
int i, j;
Product(U, u);//产生u向的基函数,保存在U中
Product(W, w);//产生w向的基函数,保存在W中
pt = osg::Vec3(0, 0, 0);
for (i = 0; i <= N; i++)
{
pts[i] = osg::Vec3(0, 0, 0);
for (j = 0; j <= N; j++)
{
pts[i] += V->at(i*(N + 1) + j) * W[j];//V0,V1,V4,V5
}
pt += pts[i] * U[i];
}
return pt;
}

(3)产生曲面片段的顶点,保存在pts数组中:

void coons_to_points(osg::ref_ptr<osg::Vec3Array> CP, osg::ref_ptr<osg::Vec3Array> pts, int npoints)//参数:CP控制点,pts生成的点
{
double u, w, delt;
delt = 1 / (double)npoints;
u = w = 0;
for (int i = 0; i <= npoints; i++)
{
u = 0;
for (int j = 0; j <= npoints; j++)
{
pts->push_back(coons(CP, u, w));//产生一个coons曲面点
u += delt;
}
w += delt;
}
}

(4)产生整个曲面的顶点,并生成一个几何体Geometry:曲面插值点,UV向的切矢量,插值点的扭转矢量分别作为数组传进去,同时传进uv的细分值

osg::Geometry* GetRevitHermiteFacePoints(osg::ref_ptr<osg::Vec3Array> Totalpoints, osg::ref_ptr<osg::Vec3Array> TotalpointsUT, osg::ref_ptr<osg::Vec3Array> TotalpointsVT, osg::ref_ptr<osg::Vec3Array> TotalpointsUVT, int unums, int vnums)
{
osg::ref_ptr<osg::Vec3Array> GridPoints = new osg::Vec3Array;
osg::Geometry* geom = new osg::Geometry;
geom->setVertexArray(GridPoints);
int PSize = GridPoints->size();
auto Pnum = Totalpoints->size();
for (int i = 0; i <Pnum - 2; i += 2)//Pnum-2
{
osg::ref_ptr<osg::Vec3Array> points = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> pointsUT = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> pointsVT = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> pointsUVT = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> SubGridPoints = new osg::Vec3Array;


osg::ref_ptr<osg::Vec3Array> ConctrlP = new osg::Vec3Array;
for (int m = i; m < i+4; m += 2)
{
ConctrlP->push_back(Totalpoints->at(m));
ConctrlP->push_back(Totalpoints->at(m + 1));
ConctrlP->push_back(TotalpointsUT->at(m));
ConctrlP->push_back(TotalpointsUT->at(m + 1));
}
for (int m = i; m < i+4; m += 2)
{
ConctrlP->push_back(TotalpointsVT->at(m));
ConctrlP->push_back(TotalpointsVT->at(m + 1));
ConctrlP->push_back(TotalpointsUVT->at(m));
ConctrlP->push_back(TotalpointsUVT->at(m + 1));
}
//InitCP(ConctrlP);
coons_to_points(ConctrlP, SubGridPoints, unums);
int pNumm = SubGridPoints->size();//每一个子网格的顶点数
for (int k = 0; k < pNumm;k++)
{
GridPoints->push_back(SubGridPoints->at(k));
}
auto geomEle = new osg::DrawElementsUInt(osg::PrimitiveSet::LINES, 0);//DrawElements方式


int PNumU = unums + 1;//每个U向的顶点数
int PNumV = vnums + 1;//每个V向的顶点数
for (int k = 0; k < PNumV-1; k++)//PNumV
{
for (int i = 0; i < PNumU; i++)
{
if (i + 1 < PNumU)
{
//三角形
geomEle->push_back(PSize+k*PNumU + i);
geomEle->push_back(PSize+(k + 1)*PNumU + i);
geomEle->push_back(PSize+k*PNumU + (i + 1));


geomEle->push_back(PSize+k*PNumU + (i + 1));
geomEle->push_back(PSize+(k + 1)*PNumU + (i + 1));
geomEle->push_back(PSize+(k + 1)*PNumU + i);


}
}
}
geom->addPrimitiveSet(geomEle);
PSize += pNumm;
/*<绑定颜色>*/
osg::ref_ptr<osg::Vec4Array> V_C = new osg::Vec4Array;

V_C->push_back(osg::Vec4(0.0, 1.0, 1.0, 1.0));
geom->setColorArray(V_C);
geom->setColorBinding(osg::Geometry::BIND_OVERALL);
}
///*<绑定颜色>*/
//osg::ref_ptr<osg::Vec4Array> V_C = new osg::Vec4Array;
//V_C->push_back(osg::Vec4(0.0, 1.0, 1.0, 1.0));
//geom->setColorArray(V_C);
//geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
return geom;
}

测试使用的数据:

void InitialConctrlP1(osg::ref_ptr<osg::Vec3Array> Totalpoints1, osg::ref_ptr<osg::Vec3Array> TotalpointsUT1, osg::ref_ptr<osg::Vec3Array> TotalpointsVT1, osg::ref_ptr<osg::Vec3Array> TotalpointsUVT1)
{
Totalpoints1->push_back(osg::Vec3(0.0, 0.0, 2.0));//P0-[0][0]
Totalpoints1->push_back(osg::Vec3(10.0, 0.0, 2.0)); //P1-[1][0]
Totalpoints1->push_back(osg::Vec3(0.0, 10.0, 2.0));  //P2-[0][1]
Totalpoints1->push_back(osg::Vec3(10.0, 10.0, 2.0)); //P3-[1][1]


Totalpoints1->push_back(osg::Vec3(0, 15, 0));
Totalpoints1->push_back(osg::Vec3(10, 15, 0));


//Totalpoints1->push_back(osg::Vec3(0, 20, 0));
//Totalpoints1->push_back(osg::Vec3(10, 20, 0));


TotalpointsUT1->push_back(osg::Vec3(1.5, 1.5, 2.0));//P0u-[0][0]
TotalpointsUT1->push_back(osg::Vec3(3.0, 0.5, 2.5));//P1u-[1][0]
TotalpointsUT1->push_back(osg::Vec3(0.5, 3.0, 1.0));//P2u-[0][1]
TotalpointsUT1->push_back(osg::Vec3(1.5, 3.5, 1.5));//P3u-[1][1]


TotalpointsUT1->push_back(osg::Vec3(1, -1, 0));
TotalpointsUT1->push_back(osg::Vec3(1, -1, 0));


//TotalpointsUT1->push_back(osg::Vec3(1, -1, 0));
//TotalpointsUT1->push_back(osg::Vec3(1, -1, 0));


TotalpointsVT1->push_back(osg::Vec3(0.3, 1.5, 2.0));//P0v-[0][0]
TotalpointsVT1->push_back(osg::Vec3(1.0, 0.5, 2.5));//P1v-[1][0]
TotalpointsVT1->push_back(osg::Vec3(0.5, 1.0, 1.5));//P2v-[0][1]
TotalpointsVT1->push_back(osg::Vec3(1.5, 3.5, 1.5));//P3v-[1][1]


TotalpointsVT1->push_back(osg::Vec3(-1, 1, 1));
TotalpointsVT1->push_back(osg::Vec3(-1, 1, 1));


//TotalpointsVT1->push_back(osg::Vec3(-1, 1, 1));
//TotalpointsVT1->push_back(osg::Vec3(-1, 1, 1));


TotalpointsUVT1->push_back(osg::Vec3(1.3, 10.5, 12.3));//P0uv-[0][0]
TotalpointsUVT1->push_back(osg::Vec3(12.0, 11.5, 1.0));//P1uv-[1][0]
TotalpointsUVT1->push_back(osg::Vec3(1.5, 11.0, 11.1));//P2uv-[0][1]
TotalpointsUVT1->push_back(osg::Vec3(12.5, 11.5, 1.5));//P3uv-[1][1]


TotalpointsUVT1->push_back(osg::Vec3(1, 1, 1));
TotalpointsUVT1->push_back(osg::Vec3(-1, -1, -1));
//TotalpointsUVT1->push_back(osg::Vec3(1, 1, 1));
//TotalpointsUVT1->push_back(osg::Vec3(-1,-1, -1));


}


实现两个曲面片段拼接的效果图:






最后推荐一些阅读的网站:

http://netclass.csu.edu.cn/NCourse/hep089/Chapter3/CG_Txt_3_062.htm

https://en.wikipedia.org/wiki/Coons_patch

http://www.cgeo.ulg.ac.be/CAO/CAD_05.pdf

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值