1. 程式人生 > >計算機圖形學-紋理對映

計算機圖形學-紋理對映

先放個圖

利用MFC框架實現紋理對映

紋理對映主要包括紋理定義、紋理控制、紋理對映方式、紋理座標和紋理物件等

1 首先建立點陣圖類

class CBMPLoader
{
public:
	CBMPLoader();
	~CBMPLoader();

	bool LoadBitmap(char *filename); //裝載一個bmp檔案
	void FreeImage(); //釋放影象資料

	unsigned int ID; //生成紋理的ID號
	int imageWidth; //影象寬度
	int imageHeight; //影象高度
	unsigned char *image; //指向影象資料的指標
};


2 點陣圖類的實現
CBMPLoader::CBMPLoader()
{
	/** 初始化成員值為0 */
	image = 0;
	imageWidth = 0;
	imageHeight = 0;
}


CBMPLoader::~CBMPLoader()
{
	FreeImage(); /**< 釋放影象資料佔據的記憶體 */
}

/** 裝載一個位圖檔案 */
bool CBMPLoader::LoadBitmap(char *file)
{
	FILE *pFile = 0; //檔案指標;
	/*建立點陣圖檔案資訊和點陣圖檔案頭結構*/
	BITMAPINFOHEADER bitmapInfoHeader;
	BITMAPFILEHEADER header;

	unsigned char textureColors = 0;/**< 用於將影象顏色從BGR變換到RGB */


	/** 開啟檔案,並檢查錯誤 */
	pFile = fopen(file, "rb");
	if (pFile == 0) return false;

	/** 讀入點陣圖檔案頭資訊 */
	fread(&header, sizeof(BITMAPFILEHEADER), 1, pFile);

	/** 檢查該檔案是否為點陣圖檔案 */
	if (header.bfType != BITMAP_ID)
	{
		fclose(pFile);             /**< 若不是點陣圖檔案,則關閉檔案並返回 */
		return false;
	}

	/** 讀入點陣圖檔案資訊 */
	fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, pFile);

	/** 儲存影象的寬度和高度 */
	imageWidth = bitmapInfoHeader.biWidth;
	imageHeight = bitmapInfoHeader.biHeight;


	/** 確保讀取資料的大小 */
	if (bitmapInfoHeader.biSizeImage == 0)
		bitmapInfoHeader.biSizeImage = bitmapInfoHeader.biWidth *
		bitmapInfoHeader.biHeight * 3;

	/** 將指標移到資料開始位置 */
	fseek(pFile, header.bfOffBits, SEEK_SET);

	/** 分配記憶體 */
	image = new unsigned char[bitmapInfoHeader.biSizeImage];

	/** 檢查記憶體分配是否成功 */
	if (!image)                        /**< 若分配記憶體失敗則返回 */
	{
		delete[] image;
		fclose(pFile);
		return false;
	}

	/** 讀取影象資料 */
	fread(image, 1, bitmapInfoHeader.biSizeImage, pFile);


	/** 將影象顏色資料格式進行交換,由BGR轉換為RGB */
	for (int index = 0; index < (int)bitmapInfoHeader.biSizeImage; index += 3)
	{
		textureColors = image[index];
		image[index] = image[index + 2];
		image[index + 2] = textureColors;
	}

	fclose(pFile);       /**< 關閉檔案 */
	return true;         /**< 成功返回 */


}
/** 釋放記憶體 */
void CBMPLoader::FreeImage()
{
	/** 釋放分配的記憶體 */
	if (image)
	{
		delete[] image;
		image = 0;
	}
}

3 編寫測試類
extern GLfloat LightAmbient[];
extern GLfloat LightDiffuse[];
extern GLfloat LightSpecular[];	/**< 鏡面光引數 */
extern GLfloat LightPosition[];	/**< 光源位置 */
class Example{

public:
	
	bool Init(int cx ,int cy){
		/** 使用者自定義的初始化過程 */
		glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
		glClearDepth(1.0f);
		glDepthFunc(GL_LEQUAL);
		glEnable(GL_DEPTH_TEST);
		glShadeModel(GL_SMOOTH);
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
		//ResizeDraw(true);											/**< 改變OpenGL視窗大小,直接呼叫子類的函式 */
		glViewport(0, 0, cx, cy);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(45.0f, (GLfloat)cx / (GLfloat)cy, 0.1f, 100.0f);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glEnable(GL_TEXTURE_2D);                          /**< 啟用紋理對映 */
		if (!Texture.LoadBitmap("image.bmp"))              /**< 載入點陣圖檔案 */
		{
			MessageBox(NULL, TEXT("裝載點陣圖檔案失敗!"), TEXT("錯誤"), MB_OK);  /**< 如果載入失敗則彈出對話方塊 */
			return false;
		}
		glGenTextures(1, &Texture.ID);        /**< 生成一個紋理物件名稱 */

		glBindTexture(GL_TEXTURE_2D, Texture.ID); /**< 建立紋理物件 */
		/** 控制濾波 */
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		/** 建立紋理 */
		gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, Texture.imageWidth,
			Texture.imageHeight, GL_RGB, GL_UNSIGNED_BYTE,
			Texture.image);
		/** 設定光源的屬性值 */
		glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);				/**< 設定環境光 */
		glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);				/**< 設定漫射光 */
		glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpecular);			/**< 設定漫射光 */
		glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);			/**< 設定光源位置 */
		/** 啟用光照和光源 */
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT1);

		return true;           /**< 成功返回 */
	}
		/**< 執行所有的初始化工作,如果成功函式返回true */
	void Uninit(){
		Texture.FreeImage();              /** 釋放紋理影象佔用的記憶體 */
		glDeleteTextures(1, &Texture.ID); /**< 刪除紋理物件 */
	}
		/**< 執行所有的解除安裝工作 */
	void Draw(){


		/** 使用者自定義的繪製過程 */
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	 /**< 清楚快取 */
		glLoadIdentity();
		/** 繪製過程 */
		glTranslatef(0.0f, 0.0f, -7.0f);
		glRotatef(rot, 1.0f, 1.0f, 0.0f);
		/** 選擇紋理 */
		glBindTexture(GL_TEXTURE_2D, Texture.ID);
		/** 開始繪製四邊形 */
		glBegin(GL_QUADS);
		/// 前側面
		glNormal3f(0.0f, 0.0f, 1.0f);								/**< 指定法線指向觀察者 */
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
		/// 後側面
		glNormal3f(0.0f, 0.0f, -1.0f);								/**< 指定法線背向觀察者 */
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f);
		/// 頂面
		glNormal3f(0.0f, 1.0f, 0.0f);								/**< 指定法線向上 */
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, 1.0f, 1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f);
		/// 底面
		glNormal3f(0.0f, -1.0f, 0.0f);								/**< 指定法線朝下 */
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
		/// 右側面
		glNormal3f(1.0f, 0.0f, 0.0f);								/**< 指定法線朝右 */
		glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f);
		/// 左側面
		glNormal3f(-1.0f, 0.0f, 0.0f);								/**< 指定法線朝左 */
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
		glEnd();														/**< 四邊形繪製結束 */

		glFlush();				           /**< 強制執行所有的OpenGL命令 */
	}
	
	/** 使用者自定義的程式變數 */
	CBMPLoader  Texture;          /**< 點陣圖載入類的物件 */
	float  rot = 1;					  /**< 用於旋轉物體 */
};



4.

實現繪圖

Example test;
GLfloat LightAmbient[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; 	/**< 環境光引數 */
GLfloat LightDiffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };		/**< 漫射光引數 */
GLfloat LightSpecular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };	/**< 鏡面光引數 */
GLfloat LightPosition[4] = { 0.0f, 0.0f, 0.0f, 1.0f };	/**< 光源位置 */
void CTextureView::OnDraw(CDC* /*pDC*/)
{
	CTextureDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此處為本機資料新增繪製程式碼
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// 繪製場景  
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	DrawPicture();
	glPopMatrix();
	// 交換緩衝區  
	SwapBuffers(wglGetCurrentDC());
}

void CTextureView::DrawPicture()
{
	CRect rc; GetWindowRect(&rc);
	int cx = rc.Width(); int cy = rc.Height();
	test.Init(cx,cy);
	test.Draw();
	SetTimer(1, 1, NULL);
}


void CTextureView::OnTimer(UINT_PTR nIDEvent)
{
	// TODO:  在此新增訊息處理程式程式碼和/或呼叫預設值
	if (nIDEvent == 1){
		test.rot += 1;
		InvalidateRect(NULL, FALSE);
        SetTimer(1, 1, NULL);
	}
	
	CView::OnTimer(nIDEvent);
}