每日一语:
拜仁和多特,竟然在欧冠决赛中碰面了,这不可不说,是日耳曼帝国的胜利。德国,一个工业化技术极高的国度。这个国家的人,就极强的意志力。在足球界,一般将他们称做日耳曼战车,时刻都为战斗准备着,不到最后一刻,绝不罢休,这一思想观念,无时无刻不影响着这个国家的每一个人。这个让,这个经历过两次世界大战的国家,直到今日,还处于不败之地。我们也应该保持,这样的品质,坚持下去,没有可能不成功。加油吧!(PS:我喜欢的拜仁2:1赢了).
下面,我们看一下,DirectX3D中的颜色,这个颜色所指的就是图元的颜色,也就是构成图元的像素的颜色。在显卡中,也就是构成其顶点的颜色。
还是先看一下,DirectX3D.h的源代码,这个文件中,基本没怎么变化:
#ifndef __DirectX3DH__
#define __DirectX3DH__
#include <d3dx9.h>
#include <string>
namespace d3d
{
bool InitD3D(
HINSTANCE hInstance, // [in] Application instance.
int width, int height, // [in] Backbuffer dimensions.
bool windowed, // [in] Windowed (true)or full screen (false).
D3DDEVTYPE deviceType, // [in] HAL or REF
IDirect3DDevice9** device);// [out]The created device.
int EnterMsgLoop(
bool (*ptr_display)(float timeDelta));
LRESULT CALLBACK WndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam);
template<class T> void Release(T t)
{
if( t )
{
t->Release();
t = 0;
}
}
template<class T> void Delete(T t)
{
if( t )
{
delete t;
t = 0;
}
}
}
#endif
在看一下,DirextX3D.cpp的代码,这个里面也基本没怎么变化:
#include "DirectX3D.h"
bool d3d::InitD3D(
HINSTANCE hInstance,
int width, int height,
bool windowed,
D3DDEVTYPE deviceType,
IDirect3DDevice9** device)
{
//
// Create the main application window.
//
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)d3d::WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "Direct3D9App";
if( !RegisterClass(&wc) )
{
::MessageBox(0, "RegisterClass() - FAILED", 0, 0);
return false;
}
HWND hwnd = 0;
hwnd = ::CreateWindow("Direct3D9App", "Direct3D9App",
WS_EX_TOPMOST,
0, 0, width, height,
0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/);
if( !hwnd )
{
::MessageBox(0, "CreateWindow() - FAILED", 0, 0);
return false;
}
::ShowWindow(hwnd, SW_SHOW);
::UpdateWindow(hwnd);
//
// Init D3D:
//
//第一步
//要初始化IDirect3D 首先必须获取IDirect3D9的指针,使用一个专门的Direct3D函数就可以很容易做到
IDirect3D9 * _d3d9;
//这个对象的主要有两个用途:设备枚举以及创建IDirect3DDevice9类型的对象。设备枚举是指获取系统中可用的的每块图形卡的
//性能,显示模型,格式以及其他信息。这个函数调用失败会返回一个NULL指针。
if(NULL == (_d3d9 = Direct3DCreate9(D3D_SDK_VERSION))){
return FALSE;
}
//第二步
//创建一个代表主显卡的IDirect3DDevice9类型对象时,必须指定使用该对象进行顶点运算的类型。如果可以,我们希望使用硬件顶点运算
//但是由于并非所有的显卡都支持硬件顶点运算,我们必须首先检查图形卡是否支持该类型的运算。
//要进行检查,必须先根据主显卡的性能参数初始化一个IDirect3DDevice9类型的对象。我们使用如下方法来完成初始化:
/*
HRESULT IDirect3D9:GetDeviceCaps(
UINT Adapter,
D3DDEVTYPE DeviceType,
D3DCAPS9 * pCaps;
)
Adapter : 指定物理显卡的序号。
DeviceType:指定设备类(例如硬件设备(D3DDEVTYPE_HAL)或软件设备(D3DDEVTYPE_REF));
pCaps 返回已初始化的设备性能结构实例。
*/
D3DCAPS9 caps;
int vp = 0; //代表顶点如何操作
_d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT){
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
//第三步是填充D3DPRESENT_PARAMETER结构
//该结构用于指定所要创建的IDirect3DDevice9类型对象的一些特性,该结构定义如下:
/*
typedef struct _D3DPRESENT_PARAMETERS_{
UINT BackBufferWidth;
UINT BackBufferHeight;
UINT BackBufferFormat;
UINT BackBufferCount;
D3DMULTISAMPLE_TYPE MultiSampleType;
DWORD MultiSampleQuality;
D3DSWAPEFFECT SwapEffect;
HWND hDeviceWindow;
BOOL Windowed;
BOOL EnableAutoDepthStencil;
D3DFORMAT AutoDepthStencilFormat;
DWORD Flags;
UINT FullScreen_RefreshRateInHz;
UINT PresentationInterval;
};
*/
/*
BackBufferWidth: 后台缓存中表面的宽度,单位为像素。
BackBufferHeight:后台缓存中表面的高度,单位为像素。
BackBufferFormat:后台缓存的像素格式(如32位像素格式:D3DFMT_A8R8G8B8);
BackBufferCount: 所需使用的后台缓存的个数,通常指定为1,表明我们仅需要一个后台缓存。
MultiSampleType: 后台缓存所使用的多重采样类型。
MultiSampleQuality:多重采样的质量水平。
SwapEffect:D3DSWAPEFFECT 枚举类型的一个成员。该枚举类型指定了交换链中的缓存的页面置换方式。指定D3DSWAPEFFECT_DISCARD时效率最高。
hDeviceWindow:与设备相关的窗口句柄。指定了所要进行绘制的应用程序窗口。
Windowed:为true时表示窗口模式,false时为全屏模式
EnableAutoDepthStencil:设为true,则Direct3D自动创建并维护深度缓存或模板缓存。
AutoDepthStencilFormat:深度缓存或模板缓存的像素格式(例如,用24位表示深度并将8位保留供模板缓存使用,D3DFMT_D24S8).
Flags:一些附加的特性。可以指定为0,表示无标记,或D3DPRESENTFLAG集合中的一个成员,其中两个成员较常用。
D3DPRESENTFLAG_LOCKABLE_DEPTHBUFFER 指定为可锁定的后台缓存。注意,使用一个可锁定的后台缓存会降低性能。
D3DPRESENTFLAG_DISCARD_DEPTHBUFFER 指定当下一个后台缓存提交时,哪个深度或模块缓存将被丢弃。丢弃的意思是深度或模板缓存存储区
中的内容别丢弃或无效。这样可以提升性能。
FullScreen_RefreshRateInHz: 刷新频率,如果想使用默认的刷新频率,则可将该参数指定为D3DPRESENT_RATE_DEFAULT;
PresentationInterval:D3DPRESENT集合的一个成员,其中有两个比较常用。
D3DPRESENT_INTERVAL_IMMEDIATE 立即提交。
D3DPRESENT_INTERVAL_DEFAULT 由Direct3D来选择提交频率,通常该值等于刷新频率。
*/
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth = 800;
d3dpp.BackBufferHeight = 600;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = true;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
//第四步 创建IDirectDevice9类型的对象
/*
HRESULT IDirect3D9::CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS *pPresentationParameters,
IDirect3DDevice9 ** ppReturnedDeviceInterface
);
Adapter:指定我们希望用已创建的IDirect3DDevice9对象代表哪块物理显卡。
DeviceType:指定需要使用的设备类型()如,硬件设备用D3DDEVTYPE_HAL,或D3DDEVTYPE_REF代表软件设备。
hFocusWindow:与设备相关的窗口句柄。通常情况下是指设备所要进行绘制的目标窗口。
为了达到预期的目的,该句柄与D3DPRESENT_PARAMETER结构的数据成员hDeviceWindow应为同一个句柄。
BehaviorFlags:该参数可为D3DCREATE_HARDWARE_VERTEXPROCESSING或D3DCREATE_SOFTWARE_VERTEXPROCESSING.
pPresentationParameters:一个已经完成初始化的D3DPRESENT_PARAMETERS类型的实例,该实例定义了设备的一些特性。
ppReturnedDeviceInterface:返回所创建的设备。
*/
if(FAILED(_d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hwnd, vp, &d3dpp, device)))
return FALSE;
_d3d9->Release();
return TRUE;
}
int d3d::EnterMsgLoop( bool (*ptr_display)(float timeDelta) )
{
MSG msg;
::ZeroMemory(&msg, sizeof(MSG));
static float lastTime = (float)timeGetTime();
while(msg.message != WM_QUIT)
{
if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else
{
float currTime = (float)timeGetTime();
float timeDelta = (currTime - lastTime)*0.001f;
ptr_display(timeDelta);
lastTime = currTime;
}
}
return msg.wParam;
}
最主要的变化在wmain.cpp中:
#include "DirectX3D.h"
#include <fstream>
#include <vector>
//
// Globals
//
IDirect3DDevice9* Device = 0;
D3DXMATRIX World;
IDirect3DVertexBuffer9 * Triangle = 0;//顶点缓存的指针
//初始化两个全局常量,以定义屏幕的分辨率。r
const int Width = 800;
const int Height = 600;
//接下来,定义灵活的顶点格式和该结构的灵活顶点格式。该例程中的顶点结构中仅包含位置信息和颜色信息。
struct ColorVertex
{
ColorVertex(){}
ColorVertex(float x, float y, float z, D3DCOLOR c)
{
_x = x; _y = y; _z = z; _color = c;
}
float _x, _y, _z;
D3DCOLOR _color;
static const DWORD FVF;
};
const DWORD ColorVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
//
// Framework Functions
//
//面我们在Setup函数里面创建顶点缓存和索引缓存,
//然后对缓存进行锁定,这里我们没有用到索引缓存
bool Setup()
{
// Nothing to setup in this sample.
//创建顶点缓存
Device->CreateVertexBuffer(
3*sizeof(ColorVertex),
D3DUSAGE_WRITEONLY,
ColorVertex::FVF,
D3DPOOL_MANAGED,
&Triangle,
0);
//回忆一下这个函数的参数
/*
第一个参数是缓存空间的大小,这里分配3个顶点结构的字节数。
第二个参数是使用缓存的属性,这里用的只写属性,后面如果读就会有问题。
第三个参数,顶点的灵活顶点格式。
第四个参数,容纳缓存的内存池。
*/
ColorVertex * v;//定义一个顶点结构的指针,用来装从Triangle得到的分配的顶点空间。
Triangle->Lock(0,0,(void**)&v,0);
//回忆一下lock的参数,第一个是锁定的VB的偏移,第二个是锁定的字节数,第四个是锁定的方式。
//下面给顶点赋值。增加了顶点颜色信息。
v[0] = ColorVertex(-1.0f,0.0f,2.0f,D3DCOLOR_XRGB(255,0,0));
v[1] = ColorVertex(0.0f,1.0f,2.0f,D3DCOLOR_XRGB(0,255,0));
v[2] = ColorVertex(1.0f,0.0f,2.0f,D3DCOLOR_XRGB(0,0,255));
Triangle->Unlock();
D3DXMATRIX proj;
//生成投影矩阵
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI*0.5f,//Y方向的视图,弧度表示。90度
(float)Width / (float)Height,//纵横比
1.0f,//近裁剪面到坐标原点的距离
1000.0f//远裁剪面到坐标原点的距离
);
Device->SetTransform(D3DTS_PROJECTION,&proj); //设置投影变换。
//关闭光照
Device->SetRenderState(D3DRS_LIGHTING,false);
return true;
}
//将之前分配的内存进行清理,也就是顶点缓存和索引缓存
void Cleanup()
{
d3d::Release<IDirect3DVertexBuffer9*>(Triangle);
// Nothing to cleanup in this sample.
}
/*
这里的Display在两个不同的位置以两种不同的着色模式分别绘制了Triangle。每个三角形的位置由世界变换矩阵World来控制
*/
bool Display(float timeDelta)
{
if( Device ) // Only use Device methods if we have a valid device.
{
//清屏
Device -> Clear(0,0,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,0xffffffff,1.0f,0);
//所有的绘制方法都必须在BeginScene和EndScene中进行调用
Device->BeginScene();
Device->SetFVF(ColorVertex::FVF);
//SetStreamSource函数,第一个参数是,资源号,比如有几个顶点缓存,第二个参数,顶点缓存的指针接口,
//第三个参数,是顶点缓存数据结构中的偏移字节。第四个是,顶点缓存的大小。
Device->SetStreamSource(0,Triangle,0,sizeof(ColorVertex));
// 第一种模式 DrawPrimitive这个函数,专门用于绘制没有索引信息的图元。
/* 第一个参数是,图元的类型,
typedef enum D3DPRIMITIVETYPE {
D3DPT_POINTLIST = 1,
D3DPT_LINELIST = 2,
D3DPT_LINESTRIP = 3,
D3DPT_TRIANGLELIST = 4,
D3DPT_TRIANGLESTRIP = 5,
D3DPT_TRIANGLEFAN = 6,
D3DPT_FORCE_DWORD = 0x7fffffff
} D3DPRIMITIVETYPE, *LPD3DPRIMITIVETYPE;
第二个参数,顶点数据流中标识顶点数据读取起点的元素的索引。该参数赋予我们一定的自由度
使得,我们可以只对顶点缓存中的某一部分进行绘制。
第三个参数,所要绘制的图元数量。
关于D3DRS_SHADEMODE,一般规定了我们如何利用顶点的颜色来计算构成图元的像素的颜色,目前一般我们
使用两种着色模式,分别是平面着色D3DSHADE_FLAT ,另一种是,D3DSHADE_GOURAUD。
D3DSHADE_FLAT 着色,每个图元的每个像素都被一直地赋予该图元的第一个顶点所指定的颜色。屏幕颜色
容易呈现出块状,这是因为个颜色之间没有平滑的过度。另一种更好的着色模式是D3DSHADE_GOURAUD,也
称平滑着色,在这种模式下,图元中的各像素的颜色值由各顶点的颜色经线性插值得到。
*/
D3DXMatrixTranslation(&World,-1.25f,0.0f,0.0f);
Device->SetTransform(D3DTS_WORLD,&World);
Device->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_FLAT);
Device->DrawPrimitive(D3DPT_TRIANGLELIST,0,1);
//
D3DXMatrixTranslation(&World,1.25f,0.0f,0.0f);
Device->SetTransform(D3DTS_WORLD,&World);
Device->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_GOURAUD);
Device->DrawPrimitive(D3DPT_TRIANGLELIST,0,1);
Device->EndScene();
// Swap the back and front buffers.
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,
640, 480, 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;
}
看一下,程序运行的截图:
每日总结:
通过这一章,我们要了解,或者有如下的映像:
1,颜色可用红色,绿色和蓝色的光强(亮度和辉度)来描述,这3种分量可按不同的亮度进行加性混合,这样我们就可描述百万种颜色。在DirectX3D程序中,可用D3DCOLOR,D3DCOLRVALUE或D3DXCOLOR类型对颜色进行描述。
2,有时,我们将颜色看作是一个4D向量(r,g,b,a)。颜色向量可以像普通向量那样做加减和比例运算。而点积和叉积对于颜色向量没有什么实际的意义。但对于颜色分量的乘法是有意义的。符号☒表示对于元素相乘的乘法,其定义如下:就是互相相乘。
3,指定了每个顶点的颜色后,DirectX3D依照当前的着色模式确定这些顶点颜色的使用方式,以在光栅化时计算出三角形中每个像素的颜色。
4,如果使用了平面着色模式,每个图元的每个像素都被赋予该图元第一个顶点所指定的颜色,在Gouraud着色模式下,图元表面各像素的颜色值由各顶点的颜色进行线性插值得到。