纹理映射是一种将图形施加到表面的技术。以简单的一堵墙为例,这种技术可以只需要两个绘制有砖纹理的三角形即可。这样就可以为表面增加大量的细节,而不必使用大量的多边形。
纹理映射使用了图像数据并将图像数据绘制(映射)到表面上。该表面看上去就像有一幅图在它上面。所以,如果有一堵墙,并将砖块的纹理施加到这堵墙上面,那么即便只是这个表面使用了两个三角形,它看上去也像场景中的一堵墙。
Direct3D中的纹理就是一幅映射到表面上的图像,这样可以让表面显示比实际上更多的细节。在3D场景中实现纹理映射,最常见的方法是从外部文件加载图像数据。该文件可以存在于硬盘、软盘或光盘等载体上,同样该文件可以在场景中的多个表面上共享使用。
在Direct3D中实现纹理映射的最小工作量就是为Direct3D纹理对象加载一幅图像,为顶点结构和FVF的每个顶点指定纹理坐标,并在渲染几何图形之前添加纹理。Direct3D支持的图像文件格式有:
■
联合图像专家组(.jpg)
■ Windows位图(.bmp)
■ 光栅图像文件存储格式(.tga)
■
可移植的网络图像文件格式(.png)
■ 直接绘图表面格式(.dds)
■ 可移植的像素映射格式(.ppm)
■
Windows设备无关位图格式(.dib)
■ 高动态范围格式(.hdr)
■ 可移植的浮点映射格式(.pfm)
在Direct3D中加载图像时要用到一个名为LPDIRECT3DTEXTURE9的结构。LPDIRECT3DTEXTURE9结构是Direct3D中的纹理对象,在加载1D或2D纹理图像时要用到该结构。无论何时创建LPDIRECT3DTEXTURE9纹理对象,都要调用对象的Release()函数对其进行释放。创建纹理时,可以选择手动将图像数据加载到对象上,或使用Direct3D的函数将文件中的图像数据加载到对象上。本书将从文件加载图像数据入手,虽然读者可以从Direct3D支持的任何图像文件格式加载图像文件,但这里主要涉及他图像文件格式是.bmp和.tga这两种图像文件格式。
为了创建空的纹理图像,读者可以使用D3DXCreateTexture()函数手动将数据添加到纹理中。一旦成功创建纹理对象,D3DXCreateTexture()函数就返回一个D3D_OK值(如果出现错误就会返回其他值)。如果函数返回且纹理对象为NULL(空),那么纹理创建就存在问题。
HRESULT WINAPI D3DXCreateTexture(
LPDIRECT3DDEVICE9 pDevice, // Direct3D9的设备对象
UINT Width, // 图像宽度
UINT Height, // 图像高度
UINT MipLevels, // 图片的图层,一般用D3DX_DEFAULT,与图像质量有关
DWORD Usage, //设定这个纹理的使用方法
D3DFORMAT Format, // 每个颜色成分使用的位数
D3DPOOL Pool, // 纹理对象驻留的内存类别
LPDIRECT3DTEXTURE9 * ppTexture // 指向新创建的纹理对象
);
高度和宽度是图像的分辨率,设备对象是渲染要用的Direct3D9设备对象。为了创建无错的纹理对象就要成功地创建设备对象。为了使用该函数,同样要了解正在创建的纹理的宽度和高度。
图像的参数MipLevels中Mipmap的总数与图像质量有关。默认情况下,该标识符为0,如果正在创建一个要渲染的纹理,那么该标识符为D3DUSAGE_RENDERTARGET,如果该纹理是动态纹理,则该标识符为D3DUSAGE_DYNAMIC。本书出于开发目的,多数情况下将该标识符设为0,除了在本章后面的后台渲染演示程序时该标识符的设置为非0。
Format参数将确定每个颜色成分使用的位数,同样,颜色成分的数量确定了整幅图像的大小。从文件加载图像时,可以将该参数设为0,这样Direct3D可以根据文件自身的内容选择正确的图像格式。从文件加载图像时,也不可能总知道图像的格式。
Pool参数确定了纹理对象驻留的内存类别。该参数可以取值为D3DPOOL_DEFAULT,这样可以将内存放置到视频内存中(这是默认的);取值为D3DPOOL_MANAGED时,则是将纹理对象保存在系统内存中;当Pool取值为D3DPOOL_SYSTEMMEN时,则是将纹理对象保存在计算机的RAM内存中。如果Direct3D设备丢失,则不必重新创建资源。使用经过管理的资源可以避免在设备丢失的情况下恢复纹理对象。
D3DXCreateTexture()函数原型中的最后一个参数通过函数调用正在创建的纹理对象。如果调用该函数后,该参数不为NULL(空),并且如果函数的返回值为D3D_OK,则函数调用成功。
创建Direct3D纹理要用到另一个函数是D3DXCreateTextureFromFile()。该函数会通知Direct3D从指定的文件加载纹理并将其加载到内存中,该函数的原型如:
HRESULT WINAPI D3DXCreateTextureFromFile(
LPDIRECT3DDEVICE9 pDevice, // 设备对象
LPCTSTR pSrcFile, // 图像文件名
LPDIRECT3DTEXTURE9 * ppTexture // 用来储存载入图片的纹理对象实例
);
为了使从文件加载图像的方法发挥更多的控制作用,可以使用D3DXCreateTextureFromFileEx()函数:
HRESULT WINAPI D3DXCreateTextureFromFileEx(
LPDIRECT3DDEVICE9 pDevice, // D3D设备对象
LPCTSTR pSrcFile, // 指明加载图像位置的字符串
UINT Width, // 图像宽度
UINT Height, // 图像高度
UINT MipLevels, // 图片的图层,一般用D3DX_DEFAULT,与图像质量有关
DWORD Usage, //设定这个纹理的使用方法
D3DFORMAT Format, // 每个颜色成分使用的位数
D3DPOOL Pool, // 纹理对象驻留的内存类别
DWORD Filter, // 处理图像质量,并控制D3D填充图像数据的方法
DWORD MipFilter, // 像素过滤方式
D3DCOLOR ColorKey, // 透明色,设定这个颜色,在显示时,这图像中的这个颜色将忽略
D3DXIMAGE_INFO * pSrcInfo, // 记录载入图片信息
PALETTEENTRY * pPalette, // 记录调色板信息
LPDIRECT3DTEXTURE9 * ppTexture // 用来储存载入图片的纹理对象实例
);
该函数的参数包括pDevice、Width、Height、MipLevels、Usage、Format、Pool、和ppTexture等,最后一个参数和D3DXCreateTexture()函数中的该参数的定义相同。参数pSrcFile是指明加载图像位置的字符串,它和D3DXCreateTextureFromFile()函数中的该参数的功能相同。
Filter参数处理图像质量,并控制Direct3D填充图像数据的方法。在指明纹理图像为原始图像宽度和高度一半,或是比原始图像小时,这个参数非常有用。例如,如果使用该函数创建的图像只有原始图像尺寸的一半,那么可以使用D3DX_FILTER_BOX标识符。这样就会用2×2的盒子将图像的像素平均处理。查看DirectX文档的D3DX_FILTER一节内容,可以看到该参数可以使用的多个标识值。
MipFilter参数除了用于纹理图像的mipmap之外,和Filter参数完全相同。滤镜的目的是为了控制要加载到图形应用程序中的纹理图像质量。有时候,最终可以在不放弃全部图像质量的情况下,使用低质量的滤波,获取应用的纹理图像质量。
ColorKey参数是用于指定图像中像素透明或不可见时的颜色值。可以将与发送给该参数的颜色相配的每个像素设为透明,并且可以用纯黑色替代。这对那些有一部分内容不可见的图像,例如菜单按钮和句色的二维图像,非常有用。
pSrcInfo参数返回一个包含原始图像所有信息的结构。该信息存储在D3DIMAGE_INFO结构中,包含了图像的原始宽度和高度、格式、深度、Mip级别、资源类型和文件格式类型。
最后一个新出现的参数pPalette用于返回用该函数加载的所有经过调色处理的纹理图像的调色板。典型情况下,这些图像是8位图像(即所有的颜色成分都是8位的),如今很少使用。过去该函数被限制了在纹理中可以使用的位数。调色板可以采用8位数据。并以足够好的级别将纹理显示在屏幕上。如今使用的是32位的图像,比以前要高很多,所以要更好地在屏幕上显示纹理,没必要使用调色板。将纹理对象加载到内存后,接下来可以将它显示在3D场景中的某个表面上。使用Direct3D设备对象的SetTexture()函数可以完成这项工作。要在渲染所有假设要在表面上显示该纹理的几何图形前调用该函数。SetTexture()函数只有两个参数,函数原型:
HRESULT SetTexture(
DWORD Sampler, // 纹理要施加的采样器阶段
IDirect3DBaseTexture9 * pTexture // Direct3D9纹理对象
);
SetTexture()函数中的第一个参数是纹理要施加的采样器阶段。该参数值位于0~1之间。支持纹理的最大数量取决于硬件。调用Direct3D对象的GetDeviceCaps()函数,并使用该函数填充D3DCAP9对象就可以了解计算机的硬件性能。D3DCAP9对象成员存储了采样器阶段总数,该对象的值要么是MaxSimultaneousTexture,要么是MaxTextureBlendStages。
SetTexture()函数中的最后一个参数是Direct3D9纹理对象。如果函数中该参数的值为NULL,就会清空限定在采样器阶段的所有纹理。
纹理坐标
最后要做的事情是为顶点指定纹理坐标。纹理坐标是一对浮点值,用于访问纹理图像中的信息。在处理二维图像时,纹理坐标范围从0.0~1.0,分别称为“tu”和“tv”。tu和tv分别用于设置顶点纹理信息起始位置的宽度比和高度比。可以在多边形表面上的不同点之间对纹理图像做内插处理。重要的是在定义纹理坐标时要保持一致,这样才能按照预期的方式映射图像。
为了指明顶点的纹理坐标,必须在顶点纹理结构中指定两个以上的浮点值,并且要为顶点FVF添加一个新的标识符。具体示例如程序清单4.5所示。
更新后用于2D纹理映射的顶点结构和FVF标识符
struct stD3DVertex
{
float x, y, z;
unsigned long color;
float tu, tv;
};
#define D3DFVF_VERTEX(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
因为顶点结构中有两个新的浮点参数,所以要确保图元定义了所有必要的信息。
使用纹理坐标定义图元的示例
{-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 0, 1},
{ 0.3f, -0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 1, 1},
{ 0.3f, 0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 1, 0},
{ 0.3f, 0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 1, 0},
{-0.3f, 0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 0, 0},
{-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 0, 1}
};
纹理坐标的开始位置在图像的左上角(tu=0, tv=0),结束位置在图像的右下角。左上角的位置设定在纹理坐标的(0, 0)处,左下角的位置在(0, 1)处,右上角的位置在(1, 0)处,右下角的位置在(1, 1)处。这之间可以是0~1之间的任何数值(如0.2和0.5等)。
借助纹理坐标可以使用纹理图像的任意部分内容。如果只想使用一半的纹理,那么只要将纹理坐标的水平方向和垂直方向各设为0.5即可。
Mipmap
Mipmap是一系列纹理,它包含了低分辨率的原始纹理图像。每个Mipmap级别有一个宽度和高度,它们分别是该Mipmap之前的那个Mipmap级别的一半。例如,第一个mip级别是原始纹理宽度和高度的一半,而第二个mip级别则是第一个mip级别纹理宽度和高度的一半。使用Mipmap的目的是在观察者靠近或远离某个表面时为纹理图像保留幅度比,这也可称为缩小率和放大率。同样借助Mipmap可以减小需要将纹理发送给渲染管道的带宽。如果物体远离观察视角,那么只要使用较低的分辨率替代原始分辨率即可。这样做的好处就是还可以提高性能。只要在程序中设置了Mipmap级别,Direct3D就负责为程序调用正确的Mipmap级别。
对于D3DXCreateTextureFromFile()和D3DXCreateTexture()函数中的Miplevels和MipFilter两个参数,为它们设定不同的参数值即可完成Mipmap的设置。Direct3D可以生成Mipmap,所以实际上在图像编辑器中没必要手动创建这些Mipmap。Mipmap示例如图
纹理图像的Mipmap级别示例(从256×256到128×128再到64×64,依此类推)
纹理质量
有很多不同的可供选择的纹理采样模式,每种模式都会影响到纹理对象在Direct3D中的外观。默认情况下,Direct3D(和OpenGL)使用最近点采样模式。这种采样模式最快也最简单,并且它使用对应于顶点纹理坐标的最近纹理像素将纹理映射到表面上。使用程序清单4.7中的代码可以设置最近点纹理过滤。
g_D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
g_D3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
g_D3DDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
如程序清单4.7所示的一样,可以将滤波模式设置为min(缩小率)、mag(放大率)和mip(mipmap)。
SetSamplerState()函数的参数包括采样器阶段(或纹理单位,该值在0~1之间)、要选择的模式以及要设置的状态值。
为了使用线性滤波,可以将采样器的状态设置为D3DTEXF_LINEAR。D3DTEXF_LINEAR Direct3D(和OpenGL)中使用的纹理滤波技术是双线性纹理滤波技术。在对min、mag和mip使用D3DTEXF_LINEAR时,双线性滤波基于2×2区域中距离采样点4个最近的纹理像素进行滤波。这种滤波方式要比不使用滤波方式或使用最近点滤波可以获得更好的图像质量,但它的计算速度不快。在对min、mag和mip使用线性滤波使,也可以采用三线滤波。这一点可以从滤波模式设定为bi或是tri看出。
各向同性滤波是可以实现的第三种滤波模式。双线性滤波和三线滤波的主要问题在于当表面和观察者之间有急剧的角度变化时,就会出现块斑。这类问题被称为各想同性失真。使用各向同性滤波就可以避免出现块斑,并且在渲染纹理图像时能获取最佳的质量。虽然各向同性滤波的质量很高,但它的计算速度是最慢的。将采样器状态设置为D3DTEXF_ANISOTROPIC就可以使用各向同性滤波。
Textures演示程序
#include<d3d9.h>
#include<d3dx9.h>
#define WINDOW_CLASS "UGPDX"
#define WINDOW_NAME "D3D Texture Mapping"
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
// Function Prototypes...
bool InitializeD3D(HWND hWnd, bool fullscreen);
bool InitializeObjects();
void RenderScene();
void Shutdown();
// Direct3D object and device.
LPDIRECT3D9 g_D3D = NULL;
LPDIRECT3DDEVICE9 g_D3DDevice = NULL;
// Matrices.
D3DXMATRIX g_projection;
D3DXMATRIX g_ViewMatrix;
// Vertex buffer to hold the geometry.
LPDIRECT3DVERTEXBUFFER9 g_VertexBuffer = NULL;
// Holds a texture image.
LPDIRECT3DTEXTURE9 g_Texture = NULL;
// A structure for our custom vertex type
struct stD3DVertex
{
float x, y, z;
unsigned long color;
float tu, tv;
};
// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
case WM_KEYUP:
if(wParam == VK_ESCAPE) PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmdLine, int show)
{
// Register the window class
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
WINDOW_CLASS, NULL };
RegisterClassEx(&wc);
// Create the application's window
HWND hWnd = CreateWindow(WINDOW_CLASS, WINDOW_NAME, WS_OVERLAPPEDWINDOW,
100, 100, WINDOW_WIDTH, WINDOW_HEIGHT,
GetDesktopWindow(), NULL, wc.hInstance, NULL);
// Initialize Direct3D
if(InitializeD3D(hWnd, false))
{
// Show the window
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
// Enter the message loop
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
RenderScene();
}
}
// Release any and all resources.
Shutdown();
// Unregister our window.
UnregisterClass(WINDOW_CLASS, wc.hInstance);
return 0;
}
bool InitializeD3D(HWND hWnd, bool fullscreen)
{
D3DDISPLAYMODE displayMode;
// Create the D3D object.
g_D3D = Direct3DCreate9(D3D_SDK_VERSION);
if(g_D3D == NULL) return false;
// Get the desktop display mode.
if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode)))
return false;
// Set up the structure used to create the D3DDevice
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
if(fullscreen)
{
d3dpp.Windowed = FALSE;
d3dpp.BackBufferWidth = WINDOW_WIDTH;
d3dpp.BackBufferHeight = WINDOW_HEIGHT;
}
else
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = displayMode.Format;
// Create the D3DDevice
if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_D3DDevice)))
{
return false;
}
// Initialize any objects we will be displaying.
if(!InitializeObjects()) return false;
return true;
}
bool InitializeObjects()
{
// Fill in our structure to draw an object.
// x, y, z, color, texture coords.
stD3DVertex objData[] =
{
{-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255,255,255), 0, 1},
{0.3f, -0.4f, 0, D3DCOLOR_XRGB(255,255,255), 1, 1},
{0.3f, 0.4f, 0, D3DCOLOR_XRGB(255,255,255), 1, 0},
{0.3f, 0.4f, 0, D3DCOLOR_XRGB(255,255,255), 1, 0},
{-0.3f, 0.4f, 0, D3DCOLOR_XRGB(255,255,255), 0, 0},
{-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255,255,255), 0, 1}
};
// Create the vertex buffer.
if(FAILED(g_D3DDevice->CreateVertexBuffer(sizeof(objData), 0,
D3DFVF_VERTEX, D3DPOOL_DEFAULT,
&g_VertexBuffer, NULL))) return false;
// Fill the vertex buffer.
void *ptr;
if(FAILED(g_VertexBuffer->Lock(0, sizeof(objData),
(void**)&ptr, 0))) return false;
memcpy(ptr, objData, sizeof(objData));
g_VertexBuffer->Unlock();
// Load the texture image from file.
if(D3DXCreateTextureFromFile(g_D3DDevice, "ugp.tga",&g_Texture) != D3D_OK) return false;
// Set the image states to get a good quality image.
// 设置放大过滤器为线性过滤器
g_D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
// 设置缩小过滤器为线性过滤器
g_D3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
// Set default rendering states.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
// Set the projection matrix.
D3DXMatrixPerspectiveFovLH(&g_projection, 45.0f,
WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f);
g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);
// Define camera information.
D3DXVECTOR3 cameraPos(0.0f, 0.0f, -1.0f);
D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 upDir(0.0f, 1.0f, 0.0f);
// Build view matrix.
D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos,
&lookAtPos, &upDir);
return true;
}
void RenderScene()
{
// Clear the backbuffer.
g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
// Begin the scene. Start rendering.
g_D3DDevice->BeginScene();
// Apply the view (camera).
g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);
// Draw square.
g_D3DDevice->SetTexture(0, g_Texture);
g_D3DDevice->SetStreamSource(0, g_VertexBuffer, 0, sizeof(stD3DVertex));
g_D3DDevice->SetFVF(D3DFVF_VERTEX);
g_D3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
// End the scene. Stop rendering.
g_D3DDevice->EndScene();
// Display the scene.
g_D3DDevice->Present(NULL, NULL, NULL, NULL);
}
void Shutdown()
{
if(g_D3DDevice != NULL) g_D3DDevice->Release();
g_D3DDevice = NULL;
if(g_D3D != NULL) g_D3D->Release();
g_D3D = NULL;
if(g_VertexBuffer != NULL) g_VertexBuffer->Release();
g_VertexBuffer = NULL;
if(g_Texture != NULL) g_Texture->Release();
g_Texture = NULL;
}
/*
分配一个纹理到一个设备层
HRESULT SetTexture(
DWORD Stage,
IDirect3DBaseTexture9 *pTexture
);
参数(Parameters)
Stage
[in] Stage identifier to which the texture is set. Stage identifiers are zero-based. The maximum
number of stages supported is determined from two caps: D3DCAPS.MaxSimultaneousTextureStages and
D3DCAPS9.MaxTextureBlendingStages.
Displacement Mapping uses a special stage index, called D3DDDMAPSAMPLER.
Vertex Textures use a special stage index called D3DVERTEXTEXTURESAMPLER.
[in(用户给出参数的值)]标志要设置纹理的设备层,从0开始.支持的最大设备层数由两个标志决定:
D3DCAPS.MaxSimultaneousTextureStages 和 D3DCAPS9.MaxTextureBlendingStages.
位移映射 使用特殊的层索引,称为 D3DDDMAPSAMPLER
顶点文理 使用特殊的层索引,称为 D3DVERTEXTEXTURESAMPLER
pTexture
[in] Pointer to an IDirect3DBaseTexture9 interface, representing the texture being set.
IDirect3DBaseTexture9的指针,代表要设置的纹理
返回值(Return Value)
If the method succeeds, the return value is D3D_OK.
If the method fails, the return value can be D3DERR_INVALIDCALL.
如果该方法成功,返回值是D3D_OK
如果该方法失败,返回值可能是D3DERR_INVALICALL
备注(Remarks)
IDirect3DDevice9::SetTexture is not allowed if the texture is created with a pool type of D3DPOOL_SCRATCH.
IDirect3DDevice9::SetTexture is not allowed with a pool type of D3DPOOL_SYSTEMMEM texture unless DevCaps is set with D3DDEVCAPS_TEXTURESYSTEMMEMORY.
IDirect3DDevice9::SetTexture 不允许(调用)若文理是以D3DPOOL_SCRATCH类型池创建的话.
同样D3DPOOL_SYSTEMMEM池类型创建的纹理也不允许,除非DevCaps设置为D3DDEVCAPS_TEXTURESYSTEMMEMORY.
调用IDirect3DDevice9::SetSamplerState(),可分别设置纹理过滤的放大过滤器和缩小过滤器。
将第一个参数设置为纹理过滤器关联的纹理层序号(0~7)。如果要设置放大过滤器,第二个
参数设为D3DSAMP_MAGFILTER,如果要设置缩小过滤器,第二个参数设为D3DSAMP_MINFILTER。第
三个参数可设为表示最近点采样的枚举常量D3DTEXF_POINT。下列代码将纹理层0的纹理过滤方式
设置为最近点采样。
g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
如果纹理的大小和屏幕图元的实际大小将近,那么采用最近点采样方法对图像质量的影响不大。
但是,如果大小相差太多,就会降低图像精度,从而影响图像质量,出现色块或闪烁的失真现象。
*/
最近点采样
最近点采样是4种过滤方式中速度最快但效果最差的过滤方式。Direct3D计算得到的纹理元素地址通常是一个浮点数值,而非整数的纹理下标值,当使用最近点采样时,Direct3D会复制与这个浮点值地址最接近的整数地址的纹理元素的颜色。
设置最近点采样的具体方法如下:调用IDirect3DDevice9::SetSamplerState(),可分别设置纹理过滤的放大过滤器和缩小过滤器。将第一个参数设置为纹理过滤器关联的纹理层序号(0~7)。如果要设置放大过滤器,第二个参数设为D3DSAMP_MAGFILTER,如果要设置缩小过滤器,第二个参数设为D3DSAMP_MINFILTER。第三个参数可设为表示最近点采样的枚举常量D3DTEXF_POINT。下列代码将纹理层0的纹理过滤方式设置为最近点采样。
g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
如果纹理的大小和屏幕图元的实际大小将近,那么采用最近点采样方法对图像质量的影响不大。但是,如果大小相差太多,就会降低图像精度,从而影响图像质量,出现色块或闪烁的失真现象。
线性纹理过滤
线性纹理过滤是目前使用最广泛的纹理过滤方法。它与最近点采样相比,能有效地提高图像的显示质量,并且对系统性能影响不大。线性纹理过滤取得与计算得到的纹理元素的浮点地址最接近的上、下、左、右4个纹理元素,对这4个纹理元素进行加权平均,得到最终显示的颜色值。
与设置最近点采样的方法相似,调用函数IDirect3DDevice9::SetSamplerState()设置线性纹理过滤,所不同的是第三个参数设置为D3DTEXF_LINEAR。下面的代码将纹理层0的放大和缩小过滤器设置为线性纹理过滤。
g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
因为是在单一纹理层上的线性过滤,而且是x、y方向上的线性过滤,所以称为双线性纹理过滤。目前大多数显卡都为线性纹理过滤进行了优化,所以使用线性纹理过滤一方面可以获得较好的图形质量,另一方面对程序性能影响不大。
各项异性纹理过滤
当三维物体表面与投影平面不平行时,它在屏幕上的投影会有拉长或扭曲,这种现象称为各项异性(anisotropy)。当一个各向异性图元的像素映射到纹理元素时,它的形状发生扭曲。Direct3D根据屏幕像素反向转换到纹理元素的延长度,决定各项异性程度。
要使用各项异性纹理过滤,还应当设置最大各项异性程度值。通过将函数IDirect3DDevive9::SetSamplerState()的第一个参数设为纹理层索引,第二个参数设为D3DSAMP_MAXANISOTOPY,第三个参数设为大于1的任何值,可以完成最大各项异性程度值的设置。下面的示例代码指定了最大各项异性值为4。
g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
g_device->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 4);
最大各项异性程度值D3DSAMP_MAXANISOTROPY为1时,表示禁用各项异性过滤。一般说来,其值越大,图像效果越好,计算量越大,速度越慢。需要注意的是,在设置最大各项异性之前,应调用IDirect3D9::GetDeviceCaps()函数,查询当前设备支持的Direct3D特性,获取当前设备支持的最大各项异性度的取值范围,具体代码如下:
DWORD get_max_anisotropy(IDirect3DDevice9* device)
{
D3DCAPS9 caps;
device->GetDeviceCaps(&caps);
return caps.MaxAnisotropy;
}
//
1.什么是纹理坐标呢?
一般的纹理都是一个二维的图片,比如一幅画什么的,纹理坐标就是指画中每一个像素的坐标。当然还有其他格式的坐标,比如3为坐标---立体纹理坐标;一维坐标等等。
2.纹理坐标有啥用呢?
当画一个primitive的时候,需要给这个primitive填充颜色,当然不是简简单单的刷上一个颜色,要的是更复杂的东东。这个时候就需要给这个primitive指定一个纹理,制定完成后就等着画图了。画图的时候,DirectX 根据指定的primitive中的坐标------0.0到1.0,从纹理中去取,比如把一个纹理的都整个设置给了一个primitive,然后(0.5, 0.7)这个点的颜色就是(0.5*texture_width, 0.5*texture_height)的颜色值,当然啦,如果取出来的坐标不是一个整数,那么就最近取一个点的色值了。通过这种方法达到给primitive中的每个点赋值来达到显示效果。
当然啦,也可以不指定整个坐标给primitive,比如只想设置纹理的上半面给primitive,则设置纹理坐标为(0.0, 0.0) ,(0.5, 0.0); (0.0, 0.5),(0.5,0.5)
3.坐标映射的过程:
屏幕中的每个像素坐标映射到primitive上(当然,也可以说成每个primitive坐标映射到屏幕上),延后映射后的像素坐标(primitive坐标)再去从相应的纹理中根据纹理坐标来去除该坐标对应点的色值。