一.简介
纹理映射是一种为三角形赋予图像数据的技术
在 Direct3D 中一个纹理是通过 IDirect3DTexture9 接口来表示,一个纹理是一个像素矩阵的表面被映射到三角形上
二.纹理坐标
Direct3D 使用一个纹理坐标系统,它是由水平方向的 u 轴(向右为正)和竖直方向 v 轴(向下为正)构成
// 纹理坐标系统表示
struct Vertex
{
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;
三.创建纹理
1.D3DXCreateTextureFromFile()
纹理数据可以从存储在磁盘中的图片文件中读取,放入 IDirect3DTexture9 抽象纹理类型
支持的图片格式有: BMP DDS DIB JPG PNG TGA
HRESULT D3DXCreateTextureFromFile(
LPDIRECT3DDEVICE9 pDevice,
LPCSTR pSrcFile,
LPDIRECT3DTEXTURE9* ppTexture
);
HRESULT IDirect3DDevice9::SetTexture(
DWORD Stage,
IDirect3DBaseTexture9* pTexture
);
// 创建纹理
IDirect3Dtexture9* _stonewall;
D3DXCreateTextureFromFile(_device, "stonewall.bmp", &_stonewall);
// 设置纹理
Device->SetTexture(0, _stonewall);
四.过滤器
纹理被映射到屏幕中的三角形上,有可能纹理和三角形不一样大,当出现需要对纹理进行变形的时候,就要用过滤(Filtering)来让变形平滑的技术
Direct3D提供了三种不同的过滤器,每种的品质级别和速度各不相同
1.Nearest point sampling
默认的过滤方法,品质最差,速度最快
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
2.Linear filtering
推荐使用,过滤产生的效果好
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
3.Anisotropic filtering
过滤产生的品质最好,处理时间最长
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
4.Mipmaps过滤器
如果显卡支持Mipmaps,Direct3D会自动选择与三角形最匹配的Mipmap
Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); // 不使用 mipmap
Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
五.寻址模式
纹理坐标必须指定在[0, 1]之间
Direct3D的寻址模式有四种: 环绕纹理寻址模式 边框颜色纹理寻址模式 截取纹理寻址模式 镜像纹理寻址模式
1.环绕纹理寻址模式(wrap address mode)
if (::GetAsyncKeyState('W') & 0x8000f)
{
Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
}
2.边框颜色纹理寻址模式(border color address mode)
if (::GetAsyncKeyState('B') & 0x8000f)
{
Device>SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
Device->SetSamplerState(0, D3DSAMP_BORDERCOLOR, 0x000000ff);
}
3.截取纹理寻址模式(clamp address mode)
if (::GetAsyncKeyState('C') & 0x8000f)
{
Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
}
4.镜像纹理寻址模式(mirror address mode)
if (::GetAsyncKeyState('M') & 0x8000f)
{
Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR);
}
六.例子
1.不过滤纹理
#include "d3dUtility.h"
IDirect3DDevice9* Device = 0;
const int Width = 640;
const int Height = 480;
IDirect3DVertexBuffer9* Quad = 0;
IDirect3DTexture9* Tex = 0;
struct Vertex
{
Vertex(){}
float _x, _y, _z;
float _nx, _ny, _nz;
float _u, _v;
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;
}
static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
bool Setup()
{
Device->CreateVertexBuffer(
6 * sizeof(Vertex),
D3DUSAGE_WRITEONLY,
Vertex::FVF,
D3DPOOL_MANAGED,
&Quad,
0);
Vertex* v;
Quad->Lock(0, 0, (void**)&v, 0);
v[0] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[1] = Vertex(-1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[2] = Vertex(1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[3] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[4] = Vertex(1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[5] = Vertex(1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
Quad->Unlock();
// 加载纹理文件
D3DXCreateTextureFromFile(Device, "a.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,
(float)Width / (float)Height,
1.0f,
1000.0f);
Device->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
void Cleanup()
{
d3d::Release<IDirect3DVertexBuffer9*>(Quad);
d3d::Release<IDirect3DTexture9*>(Tex);
}
bool Display(float timeDelta)
{
if (Device)
{
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
Device->BeginScene();
Device->SetStreamSource(0, Quad, 0, sizeof(Vertex));
Device->SetFVF(Vertex::FVF);
Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
Device->EndScene();
Device->Present(0, 0, 0, 0);
}
return true;
}
2.过滤处理纹理
#include "d3dUtility.h"
//
// Globals
//
IDirect3DDevice9* Device = 0;
const int Width = 640;
const int Height = 480;
IDirect3DVertexBuffer9* Quad = 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(
6 * sizeof(Vertex),
D3DUSAGE_WRITEONLY,
Vertex::FVF,
D3DPOOL_MANAGED,
&Quad,
0);
Vertex* v;
Quad->Lock(0, 0, (void**)&v, 0);
v[0] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 3.0f);
v[1] = Vertex(-1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[2] = Vertex( 1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 3.0f, 0.0f);
v[3] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 3.0f);
v[4] = Vertex( 1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 3.0f, 0.0f);
v[5] = Vertex( 1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 3.0f, 3.0f);
Quad->Unlock();
//
// Create the texture and set texture
//
D3DXCreateTextureFromFile(
Device,
"a.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);
//
// Don't use lighting for this sample
//
Device->SetRenderState(D3DRS_LIGHTING, false);
//
// Set the projection matrix
//
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI * 0.5f,
(float)Width / (float)Height,
1.0f,
1000.0f);
Device->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
void Cleanup()
{
d3d::Release<IDirect3DVertexBuffer9*>(Quad);
d3d::Release<IDirect3DTexture9*>(Tex);
}
bool Display(float timeDelta)
{
if (Device)
{
//
// Update the scene
//
// set wrap address mode
if (::GetAsyncKeyState('W') & 0x8000f)
{
Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
}
// set border color address mode
if (::GetAsyncKeyState('B') & 0x8000f)
{
Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
Device->SetSamplerState(0, D3DSAMP_BORDERCOLOR, 0x000000ff);
}
// set clamp address mode
if (::GetAsyncKeyState('C') & 0x8000f)
{
Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
}
// set mirror address mode
if (::GetAsyncKeyState('M') & 0x8000f)
{
Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR);
}
//
// Draw the scene
//
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
Device->BeginScene();
Device->SetStreamSource(0, Quad, 0, sizeof(Vertex));
Device->SetFVF(Vertex::FVF);
Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
Device->EndScene();
Device->Present(0, 0, 0, 0);
}
return true;
}