Direct3D纹理对象生成后,纹理对象指针指向的纹理资源指针还没有被有效赋值,如果想要通过磁盘图形文件载入纹理,那么必须将磁盘图形文件的内容载入Direct3D纹理资源,因为不同的文件具有不同的格式,所以为了将文件内容载入到Direct3D纹理资源,就要了解各种图形文件的格式,并针对不同的格式编写不同的代码将文件内容载入到纹理资源中。
从磁盘文件生成并载入纹理相当繁琐,它涉及到各种图形文件的存储格式。幸运的是,Direct3D扩展实用库函数D3DXCreateTextureFromFile()为我们提供了从磁盘图形文件创建纹理并载入纹理内容的快捷方法,该函数声明如下:
Creates a texture from a file.
HRESULT D3DXCreateTextureFromFile(
LPDIRECT3DDEVICE9 pDevice,
LPCTSTR pSrcFile,
LPDIRECT3DTEXTURE9 * ppTexture
);
Parameters
- pDevice
- [in] Pointer to an IDirect3DDevice9 interface,
representing the device to be associated with the texture.
- pSrcFile
- [in] Pointer to a string that specifies the
filename. If the compiler settings require Unicode, the data type LPCTSTR
resolves to LPCWSTR. Otherwise, the string data type resolves to LPCSTR. See
Remarks.
- ppTexture
- [out] Address of a pointer to an IDirect3DTexture9
interface, representing the created texture object.
Return Values
If the function succeeds, the return value is D3D_OK.
If the function fails, the return value can be one of the following:
D3DERR_NOTAVAILABLED3DERR_OUTOFVIDEOMEMORYD3DERR_INVALIDCALLD3DXERR_INVALIDDATAE_OUTOFMEMORY
Remarks
The compiler setting also determines the function
version. If Unicode is defined, the function call resolves to
D3DXCreateTextureFromFileW. Otherwise, the function call resolves to
D3DXCreateTextureFromFileA because ANSI strings are being used.
This function supports the following file formats:
.bmp, .dds, .dib, .hdr, .jpg, .pfm, .png, .ppm, and .tga. See
D3DXIMAGE_FILEFORMAT.
The function is equivalent to
D3DXCreateTextureFromFileEx(pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT,
D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0,
NULL, NULL, ppTexture).
Mipmapped textures automatically have each level filled
with the loaded texture.
When loading images into mipmapped textures, some
devices are unable to go to a 1x1 image and this function will fail. If this
happens, the images need to be loaded manually.
Note that a resource created with this function will be
placed in the memory class denoted by D3DPOOL_MANAGED.
Filtering is automatically applied to a texture created
using this method. The filtering is equivalent to D3DX_FILTER_TRIANGLE |
D3DX_FILTER_DITHER in D3DX_FILTER.
For the best performance when using
D3DXCreateTextureFromFile:
- Doing image scaling and format conversion at load
time can be slow. Store images in the format and resolution they will be
used. If the target hardware requires power of two dimensions, create and
store images using power of two dimensions.
- Consider using DirectDraw surface (DDS) files.
Because DDS files can be used to represent any Direct3D 9 texture format,
they are very easy for D3DX to read. Also, they can store mipmaps, so any
mipmap-generation algorithms can be used to author the images.
设置当前渲染纹理
Direct3D设备接口函数IDirect3DDevice9::SetTexture()将Direct3D纹理与指定的纹理层关联,该函数的声明如下:
Assigns a texture to a stage for a device.
HRESULT SetTexture(
DWORD Sampler,
IDirect3DBaseTexture9 * pTexture
);
Parameters
- Sampler
Zero based sampler number. Textures are bound to
samplers; samplers define sampling state such as the filtering mode and the
address wrapping mode. Textures are referenced differently by the
programmable and the fixed function pipeline:
- Programmable shaders reference textures using
the sampler number. The number of samplers available to a programmable
shader is dependent on the shader version. For vertex shaders, see
Sampler (Direct3D 9 asm-vs). For pixel shaders see Sampler (Direct3D 9
asm-ps).
- The fixed function pipeline on the other hand,
references textures by texture stage number. The maximum number of
samplers is determined from two caps: MaxSimultaneousTextures and
MaxTextureBlendStages of the D3DCAPS9 structure.
- [in] There are two other special cases for
stage/sampler numbers.
- A special number called D3DDMAPSAMPLER is used
for Displacement Mapping (Direct3D 9).
- A programmable vertex shader uses a special
number defined by a D3DVERTEXTEXTURESAMPLER when accessing Vertex
Textures in vs_3_0 (DirectX HLSL).
- pTexture
- [in] Pointer to an IDirect3DBaseTexture9
interface, representing the texture being set.
Return Values
If the method succeeds, the return value is D3D_OK. If
the method fails, the return value can be D3DERR_INVALIDCALL.
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.
设置纹理相关状态
纹理相关状态包括纹理过滤方式、纹理寻址模式、纹理阶段混合状态。因为Direct3D
9.0最多支持8层纹理贴图,所以最多存在8个纹理阶段,这些纹理相关状态需要针对每个纹理阶段分别进行设置,用于控制每个阶段纹理的相关操作。
示例程序:
#include <d3dx9.h>
#pragma warning(disable : 4127)
#define CLASS_NAME "GameApp"
#define release_com(p) do { if(p) { (p)->Release(); (p) = NULL; } } while(0)
IDirect3D9* g_d3d;
IDirect3DDevice9* g_device;
IDirect3DVertexBuffer9* g_vertex_buffer;
IDirect3DTexture9* g_texture;
struct sCustomVertex
{
float x, y, z;
float u, v;
};
#define D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
void setup_matrices()
{
// build world matrix
D3DXMATRIX mat_world;
D3DXMatrixIdentity(&mat_world);
g_device->SetTransform(D3DTS_WORLD, &mat_world);
// setup view matrix
D3DXVECTOR3 eye(0.0f, 0.0f, -10.0f);
D3DXVECTOR3 at(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX mat_view;
D3DXMatrixLookAtLH(&mat_view, &eye, &at, &up);
g_device->SetTransform(D3DTS_VIEW, &mat_view);
// setup projection matrix
D3DXMATRIX mat_proj;
D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
g_device->SetTransform(D3DTS_PROJECTION, &mat_proj);
}
bool init_graphics()
{
if(FAILED(D3DXCreateTextureFromFile(g_device, "texture.jpg", &g_texture)))
{
MessageBox(NULL, "Create texture failed!", "ERROR", MB_OK);
return false;
}
sCustomVertex vertices[] =
{
{ -3, -3, 0.0f, 0.0f, 1.0f},
{ -3, 3, 0.0f, 0.0f, 0.0f},
{ 3, -3, 0.0f, 1.0f, 1.0f},
{ 3, 3, 0.0f, 1.0f, 0.0f }
};
g_device->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_MANAGED, &g_vertex_buffer, NULL);
void* ptr;
g_vertex_buffer->Lock(0, 0, (void**)&ptr, 0);
memcpy(ptr, vertices, sizeof(vertices));
g_vertex_buffer->Unlock();
return true;
}
bool init_d3d(HWND hwnd)
{
g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if(g_d3d == NULL)
return false;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_device)))
{
return false;
}
if(! init_graphics())
return false;
setup_matrices();
g_device->SetRenderState(D3DRS_LIGHTING, FALSE);
return true;
}
void cleanup()
{
release_com(g_texture);
release_com(g_vertex_buffer);
release_com(g_device);
release_com(g_d3d);
}
void render()
{
g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(5, 5, 5), 1.0f, 0);
g_device->BeginScene();
g_device->SetTexture(0, g_texture);
g_device->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));
g_device->SetFVF(D3DFVF_CUSTOM_VERTEX);
g_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
g_device->EndScene();
g_device->Present(NULL, NULL, NULL, NULL);
}
LRESULT WINAPI WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_KEYDOWN:
if(wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR, INT)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_CLASSDC;
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = inst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASS_NAME;
wc.hIconSm = NULL;
if(! RegisterClassEx(&wc))
return -1;
HWND hwnd = CreateWindow(CLASS_NAME, "Direct3D App", WS_OVERLAPPEDWINDOW, 200, 100, 640, 480,
NULL, NULL, wc.hInstance, NULL);
if(hwnd == NULL)
return -1;
if(init_d3d(hwnd))
{
ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
render();
}
}
cleanup();
UnregisterClass(CLASS_NAME, wc.hInstance);
return 0;
}