纹理
借助纹理映射技术,我们可以将图像数据映射到三角形图元中。在Direct3D中,纹理用接口IDirect3DTexture9来表示。
1.纹理坐标
Direct3D使用的纹理坐标,由沿水平方向的u轴和沿垂直方向的v轴构成。用坐标对(u,v)标示的纹理元素称为纹理元。为了能处理不同尺寸的纹理,Direct3D将纹理坐标做了规范处理,使之限定在区间[0,1]内。纹理的FVF标记:D3DFVF_TEX1.
2.创建并启用纹理
纹理数据通常从磁盘的图像文件读入,然后再加载到IDirect3DTexture9对象中。使用的函数如下:
HRESULT D3DXCreateTextureFromFile(
LPDIRECT3DDEVICE9 pDevice, //创建纹理的设备
LPCTSTR pSrcFile, //要加载的文件
LPDIRECT3DTEXTURE9 * ppTexture //要创建的纹理
);
设置为当前纹理,用如下函数:
HRESULT IDirect3DDevice9::SetTexture(
DWORD Sampler, //第几层纹理,最多8层,(0-7).
IDirect3DBaseTexture9 * pTexture //要设置的纹理
);
若禁用某一层纹理,将pTexture置为0。Device->SetTexture(0,0);
3.纹理过滤器
有时纹理三角形为了适应屏幕三角形,会进行相应的放大或缩小。这样会产生纹理畸变,为了克服这种畸变,Direct3D采用了纹理过滤技术。
Direct3D提供了3种类型的纹理过滤器,纹理过滤方式可用Device->SetSamplerState方法。
3.1最近点采样
3.2线性纹理过滤
3.3各向异性纹理过滤
4.多级渐进纹理
由某一纹理创建一系列分辨率逐渐减小的纹理图像,并对每种分辨率下的纹理所采用的过滤方式进行定制,保留那些重要的细节。这一系列的纹理图像称为多级渐进纹理链。
4.1多级渐进纹理过滤器
Device->SetSamplerState(0,D3DSAMP_MIPFILTER,Fliter)
Fliter取值:
D3DTEXF_NONE,禁用多级渐进纹理过滤器
D3DTEXF_POINT,Direct3D将选择尺寸与屏幕三角形最接近的那一级纹理。一旦选择了某一级纹理,Direct3D就会用指定的放大过滤器和缩小过滤器对该级纹理进行过滤。
D3DTEXF_LINEAR, Direct3D将选择尺寸与屏幕三角形最接近的两个纹理。用指定的过滤器对每级纹理进行过滤。然后将这两级纹理进行线性组合,形成最终的颜色。
4.2使用多级渐进纹理
如果硬件支持多级渐进纹理,D3DXCreateTextureFromFile函数将创建一个多级渐进纹理链。Direct3D还将自动选择与屏幕三角形最接近的那一级纹理。
5.寻址模式
纹理坐标必须限制在[0,1]。从技术上讲是有问题的,因为坐标有可能超出这个范围。Direct3D定义了4种用来处理纹理坐标超出[0,1]范围的纹理映射模式。分别是:重复寻址模式,边界颜色寻址模式,箝位寻址模式,镜像寻址模式。
同样用SetSamplerState设定。
#include "d3dUtility.h" IDirect3DDevice9* Device = 0; //设备 const int Width = 640; const int Height = 480; IDirect3DVertexBuffer9* vb = 0; IDirect3DTexture9 * tex=0; //纹理 struct Vertex //顶点结构:位置、顶点法线和纹理 { Vertex(){} Vertex(float x, float y, float z,float nx,float ny,float nz,float u,float v) { _x = x; _y = y; _z = z; _nx=nx;_ny=ny;_nz=nz; _u=u;_v=v; } float _x, _y, _z; float _nx,_ny,_nz; float _u,_v; static const DWORD FVF; }; const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; // // Framework Functions // bool Setup() { Device->CreateVertexBuffer( //创建顶点缓存 12 * sizeof(Vertex), // size in bytes D3DUSAGE_WRITEONLY, // flags Vertex::FVF, // vertex format D3DPOOL_MANAGED, // managed memory pool &vb, // return create vertex buffer 0); // not used - set to 0 Vertex* vertices; vb->Lock(0, 0, (void**)&vertices, 0); //获取指向顶点缓存内容的指针 vertices[0] = Vertex(-1.0f, -1.0f,1.25f,0.0f,0.0f,-1.0f,0.0f,5.0f); vertices[1] = Vertex( -1.0f, 1.0f,1.25f,0.0f,0.0f,-1.0f,0.0f,0.0f); vertices[2] = Vertex( 1.0f, 1.0f, 1.25f,0.0f,0.0f,-1.0f,5.0f,0.0f); vertices[3] = Vertex(-1.0f, -1.0f, 1.25f,0.0f,0.0f,-1.0f,0.0f,5.0f); vertices[4] = Vertex( 1.0f, 1.0f, 1.25f,0.0f,0.0f,-1.0f,5.0f,0.0f); vertices[5] = Vertex( 1.0f, -1.0f, 1.25f,0.0f,0.0f,-1.0f,5.0f,5.0f); vb->Unlock(); D3DXCreateTextureFromFile(Device,"dx5_logo.bmp",&tex); //加载纹理图像, Device->SetTexture(0,tex); //设置当前纹理 Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR); //线性纹理过滤器设置为放大过滤器 Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR); //线性纹理过滤器设置为缩小过滤器 Device->SetSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_POINT); //多级渐进纹理过滤器,选择与屏幕尺寸最接近的那一级纹理 Device->SetRenderState(D3DRS_LIGHTING, false); //设置光照不可用 D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( //投影矩阵 &proj, D3DX_PI * 0.5f, // 90 - degree (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); //投影 return true; } void Cleanup() { d3d::Release<IDirect3DVertexBuffer9*>(vb); } bool Display(float timeDelta) { if( Device ) { Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); Device->SetStreamSource(0, vb, 0, sizeof(Vertex)); Device->SetFVF(Vertex::FVF); Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); //画出顶点缓存中的三角形图元 Device->SetFVF(Vertex::FVF); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; } // // WndProc // LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); } // // WinMain // int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) { ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; }