今天需要用vtk實現貼圖功能,搜遍網上居然都沒有找到很好的學習資料,只是找到一篇寫於07年的“vtk中的紋理貼圖詳解”裏面有一個例子,是在一個平面上貼圖,但我要實現的是三維空間中的貼圖,類似於在一個立方體上面貼圖,有參考的例子了,開始實驗:
1、VTK紋理貼圖基礎:
見vtk中的紋理貼圖詳解(點擊進入)
2、實驗開始:
預定義
#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;
先是定義數據,先是生成一個vtkUnstructuredGrid的立方體數據
//首先定義立方體的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]); }
然後讀取紋理數據,紋理文件見附件
//讀取紋理圖像
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日 [email protected] //
////////////////////////////////////////////////////////////////////////////////////
#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;
}