[實驗]用VTK給立方體貼紋理

      今天需要用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;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章