【转载注明】来之
【1】LPDIRECT3DTEXTURE9
在Direct3D中加载图像时要用到一个名为LPDIRECT3DTEXTURE9的结构。
LPDIRECT3DTEXTURE9结构是Direct3D中的纹理对象,在加载1D或2D纹理图像时要用到该结构。
无论何时创建LPDIRECT3DTEXTURE9纹理对象,都要调用对象的Release()函数对其进行释放。创建纹理时,可以选择手动将图像数据加载到对象上,或使用Direct3D的函数将文件中的图像数据加载到对象上。
【2】D3DXCreateTexture和D3DXCreateTextureFromFile
(1)D3DXCreateTexture
可以使用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 // 指向新创建的纹理对象
);
4.2 创建和使用纹理
高度和宽度是图像的分辨率,设备对象是渲染要用的Direct3D9设备对象。为了创建无错的纹理对象就要成功地创建设备对象。为了使用该函数,同样要了解正在创建的纹理的宽度和高度。
图像的参数MipLevels中Mipmap的总数与图像质量有关。默认情况下,该标识符为0,如果正在创建一个要渲染的纹理,那么该标识符为D3DUSAGE_RENDERTARGET,如果该纹理是动态纹理,则该标识符为D3DUSAGE_DYNAMIC。本书出于开发目的,多数情况下将该标识符设为0,除了在本章后面的后台渲染演示程序时该标识符的设置为非0。
Format参数将确定每个颜色成分使用的位数,同样,颜色成分的数量确定了整幅图像的大小。从文件加载图像时,可以将该参数设为0,这样Direct3D可以根据文件自身的内容选择正确的图像格式。从文件加载图像时,也不可能总知道图像的格式。
Pool参数确定了纹理对象驻留的内存类别。该参数可以取值为D3DPOOL_DEFAULT,这样可以将内存放置到视频内存中(这是默认的);取值为D3DPOOL_MANAGED时,则是将纹理对象保存在系统内存中;当Pool取值为D3DPOOL_SYSTEMMEN时,则是将纹理对象保存在计算机的RAM内存中。如果Direct3D设备丢失,则不必重新创建资源。使用经过管理的资源可以避免在设备丢失的情况下恢复纹理对象。
D3DXCreateTexture()函数原型中的{zh1}一个参数通过函数调用正在创建的纹理对象。如果调用该函数后,该参数不为NULL(空),并且如果函数的返回值为D3D_OK,则函数调用成功。
(2)D3DXCreateTextureFromFile
HRESULT WINAPI D3DXCreateTextureFromFile(
LPDIRECT3DDEVICE9 pDevice, // 设备对象
LPCTSTR pSrcFile, // 图像文件名
LPDIRECT3DTEXTURE9 * ppTexture // 用来储存载入图片的纹理对象实例
);
该函数的参数比D3DXCreateTexture()函数的要少。这是因为Direct3D正在处理创建和加载纹理对象时所遇到的各种问题。 为了使从文件加载图像的方法发挥更多的控制作用,可以使用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 // 用来储存载入图片的纹理对象实例
);
Filter参数处理图像质量,并控制Direct3D填充图像数据的方法。在指明纹理图像为原始图像宽度和高度一半,或是比原始图像小时,这个参数非常有用。例如,如果使用该函数创建的图像只有原始图像尺寸的一半,那么可以使用D3DX_FILTER_BOX标识符。这样就会用2×2的盒子将图像的像素平均处理。
4.2 创建和使用纹理
MipFilter参数除了用于纹理图像的mipmap之外,和Filter参数xx相同。滤镜的目的是为了控制要加载到图形应用程序中的纹理图像质量。有时候,最终可以在不放弃全部图像质量的情况下,使用低质量的滤波,获取应用的纹理图像质量。
ColorKey参数是用于指定图像中像素透明或不可见时的颜色值。可以将与发送给该参数的颜色相配的每个像素设为透明,并且可以用纯黑色替代。这对那些有一部分内容不可见的图像,例如菜单按钮和句色的二维图像,非常有用。
4.2 创建和使用纹理
pSrcInfo参数返回一个包含原始图像所有信息的结构。该信息存储在D3DIMAGE_INFO结构中,包含了图像的原始宽度和高度、格式、深度、Mip级别、资源类型和文件格式类型。
{zh1}一个新出现的参数pPalette用于返回用该函数加载的所有经过调色处理的纹理图像的调色板。典型情况下,这些图像是8位图像(即所有的颜色成分都是8位的),如今很少使用。过去该函数被限制了在纹理中可以使用的位数。调色板可以采用8位数据。并以足够好的级别将纹理显示在屏幕上。如今使用的是32位的图像,比以前要高很多,所以要更好地在屏幕上显示纹理,没必要使用调色板。
【3】加载纹理图像
HRESULT SetTexture(
DWORD Sampler, // 纹理要施加的采样器阶段
IDirect3DBaseTexture9 * pTexture // Direct3D9纹理对象
);
SetTexture()函数中的{dy}个参数是纹理要施加的采样器阶段。该参数值位于0~1之间。支持纹理的{zd0}数量取决于硬件。调用Direct3D对象的GetDeviceCaps()函数,并使用该函数填充D3DCAP9对象就可以了解计算机的硬件性能。D3DCAP9对象成员存储了采样器阶段总数,该对象的值要么是MaxSimultaneousTexture,要么是MaxTextureBlendStages。
SetTexture()函数中的{zh1}一个参数是Direct3D9纹理对象。如果函数中该参数的值为NULL,就会清空限定在采样器阶段的所有纹理。
【4】指定纹理坐标
纹理坐标是一对浮点值,用于访问纹理图像中的信息。在处理二维图像时,纹理坐标范围从0.0~1.0,分别称为“tu”和“tv”。tu和tv分别用于设置顶点纹理信息起始位置的宽度比和高度比。可以在多边形表面上的不同点之间对纹理图像做内插处理。重要的是在
定义纹理坐标时要保持一致,这样才能按照预期的方式映射图像。
借助纹理坐标可以使用纹理图像的任意部分内容。如果只想使用一半的纹理,那么只要将纹理坐标的水平方向和垂直方向各设为0.5即可。
【4】MipMap
Mipmap是一系列纹理,它包含了低分辨率的原始纹理图像。
每个Mipmap级别有一个宽度和高度,它们分别是该Mipmap之前的那个Mipmap级别的一半。例如,{dy}个mip级别是原始纹理宽度和高度的一半,而第二个mip级别则是{dy}个mip级别纹理宽度和高度的一半。使用Mipmap的目的是在观察者靠近或远离某个表面时为纹理图像保留幅度比,这也可称为缩小率和放大率。同样借助Mipmap可以减小需要将纹理发送给渲染管道的带宽。如果物体远离观察视角,那么只要使用较低的分辨率替代原始分辨率即可。这样做的好处就是还可以提高性能。只要在程序中设置了Mipmap级别,Direct3D就负责为程序调用正确的Mipmap级别。
对于D3DXCreateTextureFromFile()和D3DXCreateTexture()函数中的Miplevels和MipFilter两个参数,为它们设定不同的参数值即可完成Mipmap的设置。
Direct3D可以生成Mipmap,所以实际上在图像编辑器中没必要手动创建这些Mipmap。
【5】纹理质量
有很多不同的可供选择的纹理采样模式,每种模式都会影响到纹理对象在Direct3D中的外观。默认情况下,Direct3D(和OpenGL)使用最近点采样模式。这种采样模式最快也最简单,并且它使用对应于顶点纹理坐标的最近纹理像素将纹理映射到表面上。
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.2 创建和使用纹理
为了使用线性滤波,可以将采样器的状态设置为D3DTEXF_LINEAR。D3DTEXF_LINEAR Direct3D(和OpenGL)中使用的纹理滤波技术是双线性纹理滤波技术。在对min、mag和mip使用D3DTEXF_LINEAR时,双线性滤波基于2×2区域中距离采样点4个最近的纹理像素进行滤波。这种滤波方式要比不使用滤波方式或使用最近点滤波可以获得更好的图像质量,但它的计算速度不快。在对min、mag和mip使用线性滤波使,也可以采用三线滤波。这一点可以从滤波模式设定为bi或是tri看出。
各向同性滤波是可以实现的第三种滤波模式。双线性滤波和三线滤波的主要问题在于当表面和观察者之间有急剧的角度变化时,就会出现块斑。这类问题被称为各想同性失真。使用各向同性滤波就可以避免出现块斑,并且在渲染纹理图像时能获取{zj0}的质量。虽然各向同性滤波的质量很高,但它的计算速度是最慢的。将采样器状态设置为D3DTEXF_ANISOTROPIC就可以使用各向同性滤波。
【6】示例程序
/*
Demo Name: Template
Author: Allen Sherrod
Chapter: Ch 1
*/
#include<d3d9.h>
#include<d3dx9.h>
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#define WINDOW_CLASS "UGPDX"
#define WINDOW_NAME "Template"
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
// Function Prototypes...
bool InitializeD3D(HWND hWnd, bool fullscreen);
bool InitializeObjects();
void RenderScene();
void Shutdown();
// 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)
// Direct3D object and device.
LPDIRECT3D9 g_D3D = NULL;
LPDIRECT3DDEVICE9 g_D3DDevice = NULL;
// Matrices.
D3DXMATRIX g_projection;
D3DXMATRIX g_ViewMatrix;
D3DXMATRIX g_WorldMatrix;
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
case WM_KEYUP:
if(wp == VK_ESCAPE) PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, msg, wp, lp);
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE ph, LPSTR cmd, int s)
{
// 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_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE,
&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;
// 锁定顶点缓存,以进行读写操作。ptr指向该顶点缓存内存区域
if(FAILED(g_VertexBuffer->Lock(0, sizeof(objData),
(void**)&ptr, 0))) return false;
// 将objData内存区域的数据复制到ptr所指向的内存区域中
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 the projection matrix.
D3DXMatrixPerspectiveFovLH(&g_projection, 45.0f,
WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f);
g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);
// Set default rendering states.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // 不剔除任何面
// 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);
// 设置纹理
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()
{
// Release all resources.
if(g_D3DDevice != NULL) g_D3DDevice->Release();
if(g_D3D != NULL) g_D3D->Release();
g_D3DDevice = NULL;
g_D3D = NULL;
if(g_VertexBuffer != NULL) g_VertexBuffer->Release();
g_VertexBuffer = NULL;
if(g_Texture != NULL) g_Texture->Release();
g_Texture = NULL;
}
//注意需要一张ugp.tga的图片
【7】多纹理贴图
4.2 创建和使用纹理
计算机图形学中,很多次都想要在单独一个表面上显示多个纹理图像。这样可以用于混合多个图像,看上去像是一幅图像,这可用于在场景中添加灯光映射、阴影映射等更好的效果。使用多个纹理,或多纹理贴图,可以超越所学的一般纹理映射,在深入学习Direct3D编程知识时,这是一定需要深入了解的内容。在现代游戏中,场景中几乎没有只使用一个纹理图像的表面,即使对简单的物体也是如此。
为了实现多纹理贴图,通常有两种办法,需要使用其中的一个。首先,可以用想要用的每个纹理图像多次渲染几何图形,每渲染一次都将渲染结果混合在一起。这种办法对于较老的硬件非常合适,但却要浪费处理时间和做大量的工作,不止是要多次渲染几何图形,而且还要将结果混合,从而显示想要显示的外观。这种技术被称为多通道渲染。
第二种办法是使用硬件多纹理贴图。如果是在过去五年的某个时间内买过一款显卡,那么可以确信这款显卡是支持多纹理贴图的。硬件多纹理贴图可以只渲染对象和场景一次,并且指定想要施加的所有图像。当然这个过程要比多通道技术快得多,这是因为这里只需渲染一次,而不是为每个纹理图像都渲染一次几何图形。底层硬件完成图像的合并,可以在一次传递中完成所有的合并工作。根据一次传递中合并的纹理图像数目,硬件多纹理贴图受到硬件的限制。当然,性能会受到不良影响,但如果选择这种方式,就可以使用硬件多纹理贴图。当谈到硬件多纹理贴图时,通常会有一个限制,上限也就是16个纹理贴图,可以在单独一个传递过程中完成。这不是问题,因为很少会用完纹理装置,即使用完了,最糟糕的情况也就是要多使用1个或2个传递,而如果出现使用完的情况,这也比使用16个传递要好得多。无论如何,使用硬件多纹理贴图要比多通道渲染好得多。用在单个传递中的纹理数目取决于硬件可以处理的{zd0}纹理单位。使用Direct3D设备的GetDeviceCaps()函数并填充D3DCAPS9对象可以获取硬件性能。支持的总数存储在D3DCAPS9对象的MaxSimultaniousTextures成员变量中。
【8】多纹理贴图示例程序
/*
Demo Name: Multi-Texture Mapping
Author: Allen Sherrod
Chapter: Ch 4
*/
#include<d3d9.h>
#include<d3dx9.h>
#define WINDOW_CLASS "UGPDX"
#define WINDOW_NAME "D3D Multi-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;
LPDIRECT3DTEXTURE9 g_Texture2 = NULL;
// A structure for our custom vertex type
struct stD3DVertex
{
float x, y, z;
unsigned long color;
float tu, tv;
float tu2, tv2;
};
// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2)
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.0f, D3DCOLOR_XRGB(255,255,255), 0.0f, 1.0f, 0.0f, 1.0f},
{0.3f, -0.4f, 0.0f, D3DCOLOR_XRGB(255,255,255), 1.0f, 1.0f, 1.0f, 1.0f},
{0.3f, 0.4f, 0.0f, D3DCOLOR_XRGB(255,255,255), 1.0f, 0.0f, 1.0f, 0.0f},
{0.3f, 0.4f, 0.0f, D3DCOLOR_XRGB(255,255,255), 1.0f, 0.0f, 1.0f, 0.0f},
{-0.3f, 0.4f, 0.0f, D3DCOLOR_XRGB(255,255,255), 0.0f, 0.0f, 0.0f, 0.0f},
{-0.3f, -0.4f, 0.0f, D3DCOLOR_XRGB(255,255,255), 0.0f, 1.0f, 0.0f, 1.0f}
};
// 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, "Image1.bmp",
&g_Texture) != D3D_OK) return false;
if(D3DXCreateTextureFromFile(g_D3DDevice, "Image2.bmp",
&g_Texture2) != D3D_OK) return false;
// 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);
// Set the texture stages for the first texture unit (image).
g_D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_D3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_D3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
g_D3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_D3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_D3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
// Set the texture stages for the second texture unit (image).
g_D3DDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_D3DDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_D3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
g_D3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_D3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_D3DDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
// Draw square.
g_D3DDevice->SetTexture(0, g_Texture);
g_D3DDevice->SetTexture(1, g_Texture2);
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;
if(g_Texture2 != NULL) g_Texture2->Release();
g_Texture2 = NULL;
}
【9】透明度
使用RGBA纹理图像中的Alpha成分或顶点颜色的alpha成分可以控制透明度。同样,可以将像素设为半透明,而不是可见或不可见。这意味着图像的某些部分在某种程度上是可见的,而某种程度上像玻璃一样是可以看穿的。这对于像菜单或GUI对象、窗口、X射线视觉等这样的东西而言非常有用。控制图像的alpha通道或是顶点颜色的alpha通道可以控制显示给终端用户的物体透明度。为了在Direct3D中使用透明度,只要启用混合模式渲染对象即可,这样Direct3D就会知道基于Alpha通道的混合结果
// Set alpha transparency on for the texture image.
// 启用D3D Alpha混合运算
g_D3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
// 设置源混合因子
g_D3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
// 设置目标混合因子
g_D3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
【10】立方体贴图纹理
4.2 创建和使用纹理
球是2D图像,代表了对环境进行类似鱼眼的球状观察。球是2D图像,存储了整个360°环境视角。这些图像同立方体一样,主要用于像发光表面的反射和折射。如果读者能仔细观察周围的世界,就可以在3D场景中创建一个非常详细的发光物体。
立方体图纹理和球图纹理很相似,它们是由6个2D图像构成的。每幅图像保存一幅不同方向的环境图像。例如,如果有一幅天空的图像,用于代表正Y轴。那么同样要有一个负Y轴(表示地面),有一个正X轴和一个负X轴(左右方向),以及一个正Z轴和一个负Z轴(前后方向)。