今天需要用vtk实现贴图功能,搜遍网上居然都没有找到很好的学习资料,只是找到一篇写于07年的“vtk中的纹理贴图详解”里面有一个例子,是在一个平面上贴图,但我要实现的是三维空间中的贴图,类似于在一个立方体上面贴图,有参考的例子了,开始实验:
1、VTK纹理贴图基础:
见vtk中的纹理贴图详解(点击进入)
2、实验开始:
预定义
- <p>#define NFACE 6
- #define NLINE 4
- #define M_GET_LENGTH3D(x, y, z) sqrt((double)((x)*(x) + (y)*(y) + (z)*(z)))</p><p>//---------------------------------------------------------
- typedef struct _T_PT3D_T_
- {
- double x, y, z;
- }
- PT3D;</p>
先是定义数据,先是生成一个vtkUnstructuredGrid的立方体数据
- <p> //首先定义立方体的8个点
- // a-----------b //顶
- // / /
- // / /
- // c-----------d</p><p> // aa-----------bb //底
- // / /
- // / /
- // cc-----------dd
- PT3D pa,pb,pc,pd,paa,pbb,pcc,pdd;
- paa.x = paa.y = paa.z = 0;
- pbb.x = pbb.z = 0; pbb.y = 1;
- pcc.y = pcc.z = 0; pcc.x = 1;
- pdd.x = pdd.y = 1; pdd.z = 0;
- pa.x = pa.y = 0; pa.z = 1;
- pb.y = pb.z = 1; pb.x = 0;
- pc.x = pc.z = 1; pc.y = 0;
- pd.x = pd.y = pd.z = 1;</p><p> vtkUnstructuredGrid *mycube = vtkUnstructuredGrid::New();
- vtkPoints *points = vtkPoints::New();
- points->InsertPoint(0, paa.x, paa.y, paa.z);//0->aa
- points->InsertPoint(1, pbb.x, pbb.y, pbb.z);//1->bb
- points->InsertPoint(2, pcc.x, pcc.y, pcc.z);//2->cc
- points->InsertPoint(3, pdd.x, pdd.y, pdd.z);//3->dd
- points->InsertPoint(4, pa.x, pa.y, pa.z);//4->a
- points->InsertPoint(5, pb.x, pb.y, pb.z);//5->b
- points->InsertPoint(6, pc.x, pc.y, pc.z);//6->c
- points->InsertPoint(7, pd.x, pd.y, pd.z);//7->d
- mycube->SetPoints(points);
- //int facesIndex[6][4] = {{ 下 },{ 上 },{ 左 },{ 右 },{ 前 },{ 后 }};
- //int facesIndex[6][4] = {{aa-bb-dd-cc},{a-b-d-c},{aa-a-c-cc},{bb-b-d-dd},{cc-c-d-dd},{aa-a-b-bb}};
- int facesIndex[NFACE][NLINE] = {{0,1,3,2},{4,5,7,6},{0,4,6,2},{1,5,7,3},{2,6,7,3},{0,4,5,1}};
- //int facesIndex[NFACE][NLINE] = {{6,0,2},{6,0,1},{6,2,3},{6,1,3}};
- for (int iFace = 0; iFace < NFACE; iFace++)
- {
- mycube->InsertNextCell(VTK_POLYGON,NLINE,facesIndex[iFace]);
- }</p>
然后读取纹理数据,纹理文件见附件
- //读取纹理图像
- vtkBMPReader *bmpReader = vtkBMPReader::New();
- bmpReader->SetFileName("D:\\CPlusPlusOpenSource\\MyTest\\01VTKtest\\test_project\\masonry.bmp");
- vtkTexture *atext = vtkTexture::New();
- atext->SetInputConnection(bmpReader->GetOutputPort());
- atext->InterpolateOn();
生成polydata
- //将点和多边形加入polydata
- vtkCellArray *faces = mycube->GetCells();
- vtkPolyData *profile = vtkPolyData::New();
- profile->SetPoints(points);
- profile->SetPolys(faces);
纹理配制,这里面主要试验的就是tmapper三个参数的设置
- //计算多边形的发向量。
- vtkPolyDataNormals *normal = vtkPolyDataNormals::New();
- normal->SetInput(profile);
- //设置多边形的纹理映射模式
- //设置为plane模式
- vtkTextureMapToPlane *tmapper = vtkTextureMapToPlane::New();
- tmapper->SetInputConnection(normal->GetOutputPort());
- //设置纹理st坐标系的顶点坐标 和两点坐标,定义了st坐标系
- //下面这一部分就是下面要试验的!
- tmapper->SetOrigin(paa.x, paa.y, paa.z);
- tmapper->SetPoint1(pa.x, pa.y, pa.z);
- tmapper->SetPoint2(pbb.x, pbb.y, pbb.z);
- //对纹理映射进行计算
- vtkTransformTextureCoords *xform = vtkTransformTextureCoords::New();
- xform->SetInputConnection(tmapper->GetOutputPort());
- //设置贴图重复比例 第一项是指s 第二项是指t 第三项是指r 一般是1
- //14:1是根据上面点坐标的数据估算出来的。如果将t坐标定义为1,那么就将纹理向s方向贴14格,也就是说,纹理在这个面片上横着14张,这里因为是正方形直接用1,1
- xform->SetScale(10, 1, 1);
最后是数据的显示
- //将数据放入polydata
- vtkPolyDataMapper *weightedTransMapper = vtkPolyDataMapper::New();
- weightedTransMapper->SetInputConnection(xform->GetOutputPort());
- //将数据放入actor
- vtkActor *weightedTransActor = vtkActor::New();
- weightedTransActor->SetMapper(weightedTransMapper);
- weightedTransActor->SetTexture(atext);
- //进行显示
- vtkRenderer *ren1 = vtkRenderer::New();
- vtkRenderWindow *renWin = vtkRenderWindow::New();
- renWin->AddRenderer(ren1);
- vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
- vtkInteractorStyleTrackballCamera *style = vtkInteractorStyleTrackballCamera::New();
- iren->SetInteractorStyle(style);
- iren->SetRenderWindow(renWin); ren1->AddActor(weightedTransActor);
- //ren1->SetBackground(0.1, 0.2, 0.5);
- ren1->SetBackground(0.3, 0.3, 0.3);
- renWin->SetSize(788, 588);
- ren1->GetActiveCamera()->Azimuth(90);
- ren1->GetActiveCamera()->Dolly(0);
- ren1->ResetCamera();
- ren1->GetActiveCamera()->Zoom(1);
- iren->Initialize();
- iren->Start();
3 实验结果
下面两个是实验不规则六面体和三角面贴图的效果
4 结果分析
基于上面的例子发现最后还是只能一片片贴,效率还是很低的,感觉这里面是要把不同的面片按照法线的方向来分类,一类用一个vtkTransformTextureCoords(vtkTextureMapToPlane),但不知道具体怎么操作~
5 源码
源码见附件,另外附件里的源码做了一个小小的优化,里面使用了vtkAppendPolyData把vtkTransformTextureCoords的结果append到一起,然后render,这样生成的速度还是很慢,但是至少交互的速度还行
啊,没找到传附件的地方。。。先插入纹理原件吧:(本来是bmp插进来变成jif自己转一下吧)
源码直接贴到下面吧,其实跟上面的步骤也差不多:
CubeTexture.cpp
- // vtk中的纹理贴图要用 vtkTextureMapToPlane vtkTextureMapToSphere //
- // vtkTextureMapToCylinder与 vtkTransformTextureCoords //
- // 配合使用才能达到最好的效果。 //
- // //
- // 目前vtk只支持2维纹理,3维纹理似乎并不支持。 //
- // //
- // 那么vtk的纹理是如何工作的呢?? //
- // //
- // 那么我们通过自己的一段代码来解释一下: //
- // //
- // http://blog.csdn.net/yqxx/article/details/1671900 //
- // //
- // 在原代码的基础上修改成立方体贴纹理 //
- // 2011年8月27日 wylb520@126.com //
- #include "vtkActor.h"
- #include "vtkCamera.h"
- #include "vtkBMPReader.h"
- #include "vtkCellArray.h"
- #include "vtkPoints.h"
- #include "vtkPolyData.h"
- #include "vtkPolyDataMapper.h"
- #include "vtkPolyDataNormals.h"
- #include "vtkRenderWindow.h"
- #include "vtkRenderWindowInteractor.h"
- #include "vtkRenderer.h"
- #include "vtkTexture.h"
- #include "vtkTextureMapToPlane.h"
- #include "vtkTextureMapToSphere.h"
- #include "vtkTransformTextureCoords.h"
- #include "vtkTextureMapToCylinder.h"
- #include "vtkProperty.h"
- #include <VTK\include\vtk-5.2\vtkInteractorStyleTrackballCamera.h>
- #include <VTK\include\vtk-5.2\vtkPNGReader.h>
- #include <VTK\include\vtk-5.2\vtkUnstructuredGrid.h>
- #include <VTK\include\vtk-5.2\vtkAssembly.h>
- #include <VTK\include\vtk-5.2\vtkAppendPolyData.h>
- // #define NFACE 4
- // #define NLINE 3
- #define NFACE 6
- #define NLINE 4
- #define M_GET_LENGTH3D(x, y, z) sqrt((double)((x)*(x) + (y)*(y) + (z)*(z)))
- //---------------------------------------------------------
- typedef struct _T_PT3D_T_
- {
- double x, y, z;
- }
- PT3D;
- int main()
- {
- //首先定义立方体的8个点
- // a-----------b //顶
- // / /
- // / /
- // c-----------d
- // aa-----------bb //底
- // / /
- // / /
- // cc-----------dd
- PT3D pa,pb,pc,pd,paa,pbb,pcc,pdd;
- paa.x = paa.y = paa.z = 0;
- pbb.x = pbb.z = 0; pbb.y = 1;
- pcc.y = pcc.z = 0; pcc.x = 1;
- pdd.x = pdd.y = 1; pdd.z = 0;
- pa.x = pa.y = 0; pa.z = 1;
- pb.y = pb.z = 1; pb.x = 0;
- pc.x = pc.z = 1; pc.y = 0;
- pd.x = pd.y = pd.z = 1;
- vtkUnstructuredGrid *mycube = vtkUnstructuredGrid::New();
- vtkPoints *points = vtkPoints::New();
- points->InsertPoint(0, paa.x, paa.y, paa.z);//0->aa
- points->InsertPoint(1, pbb.x, pbb.y, pbb.z);//1->bb
- points->InsertPoint(2, pcc.x, pcc.y, pcc.z);//2->cc
- points->InsertPoint(3, pdd.x, pdd.y, pdd.z);//3->dd
- points->InsertPoint(4, pa.x, pa.y, pa.z);//4->a
- points->InsertPoint(5, pb.x, pb.y, pb.z);//5->b
- points->InsertPoint(6, pc.x, pc.y, pc.z);//6->c
- points->InsertPoint(7, pd.x, pd.y, pd.z);//7->d
- mycube->SetPoints(points);
- //int facesIndex[6][4] = {{ 下 },{ 上 },{ 左 },{ 右 },{ 前 },{ 后 }};
- //int facesIndex[6][4] = {{aa-bb-dd-cc},{a-b-d-c},{aa-a-c-cc},{bb-b-d-dd},{cc-c-d-dd},{aa-a-b-bb}};
- int facesIndex[NFACE][NLINE] = {{0,1,3,2},{4,5,7,6},{0,4,6,2},{1,5,7,3},{2,6,7,3},{0,4,5,1}};
- //int facesIndex[NFACE][NLINE] = {{6,0,2},{6,0,1},{6,2,3},{6,1,3}};
- for (int iFace = 0; iFace < NFACE; iFace++)
- {
- mycube->InsertNextCell(VTK_POLYGON,NLINE,facesIndex[iFace]);
- }
- //使用vtkUnstructuredGrid是为了跟我后面要写的程序对接,实际上可以直接通过下面的方式定义顶点索引
- //vtkCellArray *faces = vtkCellArray::New();
- //faces->InsertNextCell(4);//face aa-bb-cc-dd(下)
- //faces->InsertCellPoint(0);
- //faces->InsertCellPoint(1);
- //faces->InsertCellPoint(2);
- //faces->InsertCellPoint(3);
- //faces->InsertNextCell(4);//face a-b-c-d(上)
- //faces->InsertCellPoint(4);
- //faces->InsertCellPoint(5);
- //faces->InsertCellPoint(6);
- //faces->InsertCellPoint(7);
- //faces->InsertNextCell(4);//face aa-a-c-cc(左)
- //faces->InsertCellPoint(0);
- //faces->InsertCellPoint(4);
- //faces->InsertCellPoint(6);
- //faces->InsertCellPoint(2);
- //faces->InsertNextCell(4);//face bb-b-d-dd(右)
- //faces->InsertCellPoint(1);
- //faces->InsertCellPoint(5);
- //faces->InsertCellPoint(7);
- //faces->InsertCellPoint(3);
- //faces->InsertNextCell(4);//face cc-c-d-dd(前)
- //faces->InsertCellPoint(2);
- //faces->InsertCellPoint(6);
- //faces->InsertCellPoint(7);
- //faces->InsertCellPoint(3);
- //faces->InsertNextCell(4);//face aa-a-b-bb(后)
- //faces->InsertCellPoint(0);
- //faces->InsertCellPoint(4);
- //faces->InsertCellPoint(5);
- //faces->InsertCellPoint(1);
- //读取纹理图像
- vtkBMPReader *bmpReader = vtkBMPReader::New();
- bmpReader->SetFileName("D:\\CPlusPlusOpenSource\\MyTest\\01VTKtest\\test_project\\masonry.bmp");
- vtkTexture *atext = vtkTexture::New();
- atext->SetInputConnection(bmpReader->GetOutputPort());
- atext->InterpolateOn();
- //将点和多边形加入polydata
- vtkCellArray *faces = mycube->GetCells();
- //vtkPolyData *profile = vtkPolyData::New();
- vtkIdType *indices;
- vtkIdType numberOfPoints;
- PT3D pt0,pt1,pt2;
- //vtkAssembly * CubeAssembly = vtkAssembly::New();
- vtkAppendPolyData * CaVectorAppendPoly = vtkAppendPolyData::New();
- for (faces->InitTraversal();faces->GetNextCell(numberOfPoints, indices);)
- {
- vtkPolyData *profile = vtkPolyData::New();
- vtkCellArray *lines = vtkCellArray::New();
- lines->InsertNextCell(numberOfPoints);//#number of points
- for (vtkIdType i = 0; i < numberOfPoints; i++)
- {
- lines->InsertCellPoint(indices[i]);
- //lines->InsertCellPoint(i);
- double point[3];
- points->GetPoint(indices[i], point);
- if (numberOfPoints < 4)
- {
- if (i == 1)
- {
- pt0.x = point[0];pt0.y = point[1];pt0.z = point[2];
- }
- if (i == 2)
- {
- pt1.x = point[0];pt1.y = point[1];pt1.z = point[2];
- }
- if (i == 0)
- {
- pt2.x = point[0];pt2.y = point[1];pt2.z = point[2];
- }
- }
- else //提供对三角面片的支持
- {
- if (i == 0)
- {
- pt0.x = point[0];pt0.y = point[1];pt0.z = point[2];
- }
- if (i == 1)
- {
- pt1.x = point[0];pt1.y = point[1];pt1.z = point[2];
- }
- if (i == 3)
- {
- pt2.x = point[0];pt2.y = point[1];pt2.z = point[2];
- }
- }
- }
- profile->SetPoints(points);
- profile->SetPolys(lines);
- //计算多边形的法向量。
- vtkPolyDataNormals *normal = vtkPolyDataNormals::New();
- normal->SetInput(profile);
- //设置多边形的纹理映射模式
- //设置为plane模式
- vtkTextureMapToPlane *tmapper = vtkTextureMapToPlane::New();
- tmapper->SetInputConnection(normal->GetOutputPort());
- //设置纹理st坐标系的顶点坐标 和两点坐标,定义了st坐标系
- tmapper->SetOrigin(pt0.x, pt0.y, pt0.z);
- tmapper->SetPoint1(pt1.x, pt1.y, pt1.z);
- tmapper->SetPoint2(pt2.x, pt2.y, pt2.z);
- //对纹理映射进行计算
- vtkTransformTextureCoords *xform = vtkTransformTextureCoords::New();
- xform->SetInputConnection(tmapper->GetOutputPort());
- //设置贴图重复比例 第一项是指s 第二项是指t 第三项是指r 一般是1
- //14:1是根据上面点坐标的数据估算出来的。如果将t坐标定义为1,那么就将纹理向s方向贴14格,也就是说,纹理在这个面片上横着14张
- xform->SetScale(1, 1, 1);
- //append,这样只需要一个actor
- CaVectorAppendPoly->AddInput((vtkPolyData*)xform->GetOutput());
- }
- //将数据放入polydata
- vtkPolyDataMapper *weightedTransMapper = vtkPolyDataMapper::New();
- weightedTransMapper->SetInputConnection(CaVectorAppendPoly->GetOutputPort());
- //将数据放入actor
- vtkActor *weightedTransActor = vtkActor::New();
- weightedTransActor->SetMapper(weightedTransMapper);
- weightedTransActor->SetTexture(atext);
- atext->Delete();
- points->Delete();
- //进行显示
- vtkRenderer *ren1 = vtkRenderer::New();
- vtkRenderWindow *renWin = vtkRenderWindow::New();
- renWin->AddRenderer(ren1);
- vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
- vtkInteractorStyleTrackballCamera *style = vtkInteractorStyleTrackballCamera::New();
- iren->SetInteractorStyle(style);
- iren->SetRenderWindow(renWin);
- //ren1->AddActor(weightedTransActor);
- ren1->AddActor(weightedTransActor);
- //ren1->SetBackground(0.1, 0.2, 0.5);
- ren1->SetBackground(0.3, 0.3, 0.3);
- renWin->SetSize(788, 588);
- ren1->GetActiveCamera()->Azimuth(90);
- ren1->GetActiveCamera()->Dolly(0);
- ren1->ResetCamera();
- ren1->GetActiveCamera()->Zoom(1);
- iren->Initialize();
- iren->Start();
- return 0;
- }