天天看點

OpenGL5-紋理貼圖

代碼下載下傳

OpenGL5-紋理貼圖

#include "CELLWinApp.hpp"

#include <gl/GLU.h>

#include <assert.h>

#include <math.h>

#pragma comment(lib,"opengl32.lib")

#pragma comment(lib,"glu32.lib")

#pragma comment(lib,"winmm.lib")

/**

* 經過上幾個例子的了解,這一例子介紹OpenGL坐标系

OpenGL使用右手坐标

坐标是OpenGL中用來描述場景的坐标,

Z+軸垂直螢幕向外

,X+從左到右,

Y+軸從下到上,

是右手笛卡爾坐标系統,

我們用這個坐标系來描述物體位置.

即:

從左到右,x遞增

從下到上,y遞增

從遠到近,z遞增

坐标系以螢幕中心為原點(0, 0, 0)。你面對螢幕,你的右邊是x正軸,上面是y正軸,螢幕指向你的為z正軸

*/

* 紋理坐标,也是這個例子的重點。

* 本節課介紹最常用的,也做好了解的2D紋理坐标

* 實際上就是給一個面貼上一個圖檔。

首先看下紋理坐标的定義

下面是一個圖檔,圖檔的左上角的坐标定義為 0 ,0,(三維中中術語 u(x),v(y)坐标)

u,v(0,0)                             u,v(1,0)

-----------------------------

|                                      |

u,v(0,1)                             u,v(1,1)

* 頂點結構聲明,u,v作弊啊飄

struct Vertex

{

/**

* u,v坐标

*/

float u,v;

* 頂點坐标

float x, y, z;

};

Vertex g_cubeVertices[] =

{ 0, 0, -1.0f,-1.0f, 1.0f },

{ 1, 0, 1.0f,-1.0f, 1.0f },

{ 1, 1, 1.0f, 1.0f, 1.0f },

{ 0, 1, -1.0f, 1.0f, 1.0f },

{ 0, 0, -1.0f,-1.0f,-1.0f },

{ 1, 0, -1.0f, 1.0f,-1.0f },

{ 1, 1, 1.0f, 1.0f,-1.0f },

{ 0, 1, 1.0f,-1.0f,-1.0f },

{ 0, 0, -1.0f, 1.0f,-1.0f },

{ 1, 0, -1.0f, 1.0f, 1.0f },

{ 1, 1, 1.0f, 1.0f, 1.0f },

{ 0, 1, 1.0f, 1.0f,-1.0f },

{ 1, 0, 1.0f,-1.0f,-1.0f },

{ 1, 1, 1.0f,-1.0f, 1.0f },

{ 0, 1, -1.0f,-1.0f, 1.0f },

{ 0, 0, 1.0f,-1.0f,-1.0f },

{ 1, 0, 1.0f, 1.0f,-1.0f },

{ 0, 1, 1.0f,-1.0f, 1.0f },

{ 1, 0, -1.0f,-1.0f, 1.0f },

{ 1, 1, -1.0f, 1.0f, 1.0f },

{ 0, 1, -1.0f, 1.0f,-1.0f }

class Tutorial5 :public CELL::Graphy::CELLWinApp

public:

Tutorial5(HINSTANCE hInstance)

:CELL::Graphy::CELLWinApp(hInstance)

,_primitiveType(GL_POINTS)

{

}

virtual void render()

do

{

glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

static float fXrot = 0.0f;

static float fYrot = 0.0f;

static float fZrot = 0.0f;

/**

* 擷取一幀繪制的時間

*/

static DWORD dwBegin = timeGetTime();

float fElpased = float(timeGetTime() - dwBegin) * 0.001f;

dwBegin = timeGetTime();

* 三個方向上,x軸,y軸,z軸,同時旋轉

float rotSpeed = 90;

fXrot += rotSpeed * fElpased;

fYrot += rotSpeed * fElpased;

fZrot += rotSpeed * fElpased;

* 指明,要操作的矩陣是模型矩陣

glMatrixMode( GL_MODELVIEW );

* 将模型矩陣清空為機關矩陣,對角線為1的矩陣為機關矩陣,其意義是

* 機關矩陣與定點作用,或者與其他的矩陣做乘法,結果不變

float modelView[4][4] =

{

1,0,0,0

0,1,0,0,

0,0,1,0,

0,0,0,1

};

glLoadIdentity();

* 移動模型矩陣 model view,

* glTranslatef( x, y, z );

* 做了改操作以後,矩陣變為

x,y,z,1

glTranslatef( 0.0f, 0.0f, -5.0f );

* 可以調用

* float mat[4][4];

* glGetFloatv(GL_PROJECTION_MATRIX,(float*)mat);

float mat[4][4];

glGetFloatv(GL_MODELVIEW_MATRIX,(float*)mat);

* 進行旋轉,将更改modelview 矩陣

glRotatef( fXrot, 1.0f, 0.0f, 0.0f );

glRotatef( fYrot, 0.0f, 1.0f, 0.0f );

glRotatef( fZrot, 0.0f, 0.0f, 1.0f );

* 矩陣将被應用到繪制的的定點上。

* 實際上進行的操作就是 g_cubeVertices 數組中每一個點與矩陣進行相乘,得到新的定點。

* 這個操作是在顯示卡中完成。是以速度很快。

* 當然,在顯示卡上,不止是與modelview矩陣相乘,還要和,投影矩陣和觀察矩陣進行相乘,

* 就是 MVP * vertex ;

* M = model matrix

* V = view matrix

* P = Project matrix

* 使用紋理

glBindTexture(GL_TEXTURE_2D,_textureId);

glInterleavedArrays( GL_T2F_V3F, 0, g_cubeVertices );

glDrawArrays( GL_QUADS, 0, 24 );

SwapBuffers( _hDC );

} while (false);

* 生成投影矩陣

* 後面為了重用性,我們會寫一個專門的matrix類,完成矩陣的一系列擦做

* 這個是很有必須要的,當你對Opengl了解的不斷深入,你會發現,很多都是和數學有關的

void perspective(float fovy,float aspect,float zNear,float zFar,float matrix[4][4])

assert(aspect != float(0));

assert(zFar != zNear);

#define PI 3.14159265358979323f

float rad = fovy * (PI / 180);

float halfFovy = tan(rad / float(2));

matrix[0][0] = float(1) / (aspect * halfFovy);

matrix[1][1] = float(1) / (halfFovy);

matrix[2][2] = -(zFar + zNear) / (zFar - zNear);

matrix[2][3] = -float(1);

matrix[3][2] = -(float(2) * zFar * zNear) / (zFar - zNear);

#undef PI

virtual void onInit()

/**

* 調用父類的函數。

*/

CELL::Graphy::CELLWinApp::onInit();

* 設定Opengl的投影方式,改例子裡面,我們使用正交投影

* OpenGL的投影方式有兩種(我知道的):正交,和透視,有興趣的可以google下

* 這裡采用的視窗坐标系,與Windows視窗坐标一直,左上角為 0,0,右下角為 _winWidth,_winHeight

* 這種投影下繪制出來的物體沒有三維感

//glOrtho(0,_winWidth,_winHeight,0,1,-1);

//! 修改投影方式-透視投影,

//! 指定我們要進行操作的矩陣,OpenGL是一個狀态機,是以要操作那一個狀态的時候,需要進行切換

//! 下面的這句話就是切換到投影矩陣上

//! gluPerspective細節實作,參照下面的網址:http://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml

glMatrixMode( GL_PROJECTION );

#if 0

glLoadIdentity();

gluPerspective( 45.0, (GLdouble)_winWidth / (GLdouble)_winHeight, 0.1, 100.0);

float mat[4][4];

glGetFloatv(GL_PROJECTION_MATRIX,(float*)mat);

#else

//! 這裡我們也可以自己按照Opengl的投影方式生成一個投影矩陣,

//! 然後将投影矩陣給OpenGL

GLfloat matrix[4][4] =

0,0,0,0,

0,0,0,0

};

perspective(45.0f, (GLfloat)_winWidth / (GLfloat)_winHeight, 0.1f, 100.0f,matrix);

glLoadMatrixf((float*)matrix);

#endif

glClearColor(0,0,0,1);

* 增加如下兩句話

* glEnable(GL_DEPTH_TEST); 啟動深度測試,這樣,有遮擋計算,被遮蓋的将覆寫

* glEnable(GL_TEXTURE_2D); 啟動紋理,支援紋理貼圖,這樣才可以繪制紋理出來

glEnable(GL_DEPTH_TEST);

glEnable(GL_TEXTURE_2D);

* 讀一個bmp圖檔

HBITMAP hBmp = (HBITMAP)LoadImageA(0,"1.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);

* 擷取圖檔的大小

BITMAP bmpInf = {0};

GetObject(hBmp,sizeof(bmpInf),&bmpInf);

* 擷取圖檔的顔色資料(r,g,b)

int size = bmpInf.bmHeight * bmpInf.bmWidth * 3;

char* data = new char[size];

BITMAPINFO bi;

bi.bmiHeader.biSize = sizeof(bi.bmiHeader);

bi.bmiHeader.biWidth = bmpInf.bmWidth;

bi.bmiHeader.biHeight = bmpInf.bmHeight;

bi.bmiHeader.biPlanes = 1;

bi.bmiHeader.biBitCount = 24;

bi.bmiHeader.biCompression = BI_RGB;

bi.bmiHeader.biSizeImage = size;

bi.bmiHeader.biClrUsed = 0;

bi.bmiHeader.biClrImportant = 0;

* 擷取rgb資料

int idata = GetDIBits(_hDC,hBmp,0,bi.bmiHeader.biHeight,data,&bi,DIB_RGB_COLORS);

* 産生一個紋理Id,可以認為是紋理句柄,後面的操作将書用這個紋理id

glGenTextures( 1, &_textureId );

* 使用這個紋理id,或者叫綁定(關聯)

glBindTexture( GL_TEXTURE_2D, _textureId );

* 指定紋理的放大,縮小濾波,使用線性方式,即當圖檔放大的時候插值方式

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

* 将圖檔的rgb資料上傳給opengl.

glTexImage2D(

GL_TEXTURE_2D, //! 指定是二維圖檔

0, //! 指定為第一級别,紋理可以做mipmap,即lod,離近的就采用級别大的,遠則使用較小的紋理

GL_RGB, //! 紋理的使用的存儲格式

bmpInf.bmWidth, //! 寬度,老一點的顯示卡,不支援不規則的紋理,即寬度和高度不是2^n。

bmpInf.bmHeight, //! 寬度,老一點的顯示卡,不支援不規則的紋理,即寬度和高度不是2^n。

0, //! 是否的邊

GL_BGR_EXT, //! 資料的格式,bmp中,windows,作業系統中存儲的資料是bgr格式

GL_UNSIGNED_BYTE, //! 資料是8bit資料

data

);

delete []data;

* 删除圖檔

DeleteObject(hBmp);

virtual int events(unsigned msg, unsigned wParam, unsigned lParam)

switch(msg)

case WM_KEYDOWN:

{

if (wParam == 'S' ||wParam == 'S')

_primitiveType += 1;

if (_primitiveType >=GL_POLYGON )

{

_primitiveType = 0;

}

}

}

break;

}

return __super::events(msg,wParam,lParam);

protected:

unsigned _primitiveType;

* 儲存紋理Id

unsigned _textureId;

int CALLBACK _tWinMain(

HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPTSTR lpCmdLine,

int nShowCmd

)

(void*)hInstance;

(void*)hPrevInstance;

(void*)lpCmdLine;

(void*)nShowCmd;

Tutorial5 winApp(hInstance);

winApp.start(640,480);

return 0;

}

我的QQ13697826

繼續閱讀