- 浏览: 1450131 次
- 性别:
- 来自: 苏州
文章分类
- 全部博客 (564)
- 算法 (7)
- 流金岁月 (1)
- Javascript (30)
- actionscript (108)
- as3.0 game (14)
- flex (84)
- fms2 (27)
- 正则表达式 (7)
- 开源组件代码(as3.0) (1)
- Pv3d (13)
- Cairngorm (4)
- vbs (54)
- VB程序设计 (26)
- 计算机应用与维护 (4)
- 职场实用穿衣技巧 (3)
- 历史风云 (15)
- 淡泊明志,宁静致远 (12)
- 情感 (26)
- 杂谈 (41)
- 越南风 (14)
- DirectX (9)
- Dev-cpp (11)
- 回望百年 (2)
- 建站经验 (2)
- Python (24)
- 网络赚钱 (4)
- php (2)
- html (1)
- ob0短址网 (1)
- ob0.cn (1)
- wordpress (1)
- pandas logistic (1)
- haxe (1)
- opencv (1)
- 微信小程序 (3)
- vue (3)
- Flutter (1)
最新评论
-
GGGGeek:
第一个函数滚动监听不起作用,onPageScroll可以
微信小程序--搜索框滚动到顶部时悬浮 -
naomibyron:
解决办法:工具 -> 编译选项 -> 编译器 ...
dev-c++中编译含WINSOCK的代码出现错误的解决方法 -
haichuan11:
这个…… 代码不全真的是让人很憋屈的感觉啊
actionScript 3.0 图片裁剪及旋转 -
chenyw101:
老兄能留个QQ号吗?具体的我有些东西想请教下你
用VB制作网站登陆器 -
yantao1943:
貌似有点问题,只派发一次事件啊
使用ActionScript 2.0或ActionScript 3.0处理音频文件的提示点(cue
学习一样东西,最好能够从最基础做起。学习D3D,笔者并不赞同直接继承SDK Sample的CD3DApplication,然后override那几个虚函数,因为这样会让初学者对D3D更感神秘,因此我们需要从头开始,不用害怕,其实一点都不难:)
一、Win32 SDK框架
看过Petzold的《Windows程序设计》的朋友应该知道创建窗口的固定步骤。而利用Win32 SDK搭建D3D框架只不过是在这些步骤中加入一些调料罢了。具体步骤如下:
1、注册窗体类;
2、创建窗口;
3、创建消息处理函数;
4、显示窗口;
5、初始化D3D、初始化资源数据(如:顶点向量、纹理等);
6、进入消息循环,用PeekMessage处理消息,以便在空闲时进行渲染。
而初始化D3D又分下面四个步骤:
1、创建IDirect3D9[1]对象;
2、检查硬件性能,判断硬件是否支持特定的功能;
3、填充D3DPRESENT_PARAMETERS结构;
4、利用第3步中的结构体对象创建D3D设备(由于该步骤需要窗体的句柄,所以初始化D3D必须放在显示窗口之后)。
下面是框架代码:
//
// 全局变量
//
IDirect3DDevice9* Device = 0;
bool InitD3D(
HINSTANCE hInstance,
int width, int height,
bool windowed,
D3DDEVTYPE deviceType,
IDirect3DDevice9** device)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)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);
//
// 初始化D3D
//
HRESULT hr = 0;
// 步骤1:创建IDirect3D9对象。
IDirect3D9* d3d9 = 0;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if( !d3d9 )
{
MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
return false;
}
// 步骤2:检查硬件性能(这里只检查了是否支持顶点的硬件处理)
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
int vp = 0;
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
// 步骤3:填充D3DPRESENT_PARAMETERS结构(参数说明请参考MSDN)
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = windowed;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// 步骤4:创建D3D设备
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT, // 主设备
deviceType, // 设备类型
hwnd, // 分配给设备的窗口句柄
vp, // 顶点处理方式
&d3dpp, // 表现参数
device); // 返回创建的设备
if( FAILED(hr) )
{
// 如果创建失败,采用16为深度缓存试试
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT,
deviceType,
hwnd,
vp,
&d3dpp,
device);
if( FAILED(hr) )
{
d3d9->Release();
MessageBox(0, "CreateDevice() - FAILED", 0, 0);
return false;
}
}
d3d9->Release();
return true;
}
// 消息循环
int MsgLoop()
{
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Display(); // 渲染
}
}
return msg.wParam;
}
//
// 框架函数
//
bool Setup()
{
// 你可以在此初始化顶点向量、载入纹理等
return true;
}
void Cleanup()
{
// 清除在Setup中载入的资源
}
bool Display()
{
if( Device ) // 只有当设备有效时才能渲染
{
// 在此填入渲染代码
}
return true;
}
//
// 窗口处理函数
//
LRESULT CALLBACK 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);
}
//
// 程序入口
//
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE prevInstance,
PSTR cmdLine,
int showCmd)
{
if(!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;
}
MsgLoop();
Cleanup();
Device->Release();
return 0;
}
二、MFC框架
利用MFC,我们不用写一行代码就可以创建一个窗体,这是MFC封装了那些繁琐而固定的窗口创建代码,这样我们只需要初始化D3D就可以了。下面是通过不带文档的SDI 作为示例来创建D3D的框架,具体步骤如下:
1、将InitD3D、Setup、Cleanup、Display作为CMainFrame的成员函数,其中InitD3D需被应用程序类调用,应该将其置为public,其余为内部函数;
2、在应用程序类(CWinApp的子类)的InitInstance()中显示窗口之后,对D3D进行初始化;
3、override Run(),其实,这里就是消息循环;
这里需要注意:
填充D3DPRESENT_PARAMETERS时,BackBufferWidth和BackBufferHeight最好设置为客户区大小,hDeviceWindow设置为视窗口的句柄m_wndView.m_hWnd,最重要的是Windowed[2]一定要置为true,否则会产生“无效调用”的错误。
下面是实际代码,该代码渲染了一个带贴图的旋转正方体:
// MFCD3D.cpp : 定义应用程序的类行为。
//
#include "stdafx.h"
#include "MFCD3D.h"
#include "MainFrm.h"
#include <mmsystem.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMFCD3DApp
BEGIN_MESSAGE_MAP(CMFCD3DApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
END_MESSAGE_MAP()
// CMFCD3DApp 构造
CMFCD3DApp::CMFCD3DApp()
{
// TODO: 在此处添加构造代码,
// 将所有重要的初始化放置在 InitInstance 中
}
// 唯一的一个 CMFCD3DApp 对象
CMFCD3DApp theApp;
// CMFCD3DApp 初始化
BOOL CMFCD3DApp::InitInstance()
{
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControls()。否则,将无法创建窗口。
InitCommonControls();
CWinApp::InitInstance();
// 初始化 OLE 库
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
// 标准初始化
// 如果未使用这些功能并希望减小
// 最终可执行文件的大小,则应移除下列
// 不需要的特定初始化例程
// 更改用于存储设置的注册表项
// TODO: 应适当修改该字符串,
// 例如修改为公司或组织名
SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
// 若要创建主窗口,此代码将创建新的框架窗口
// 对象,然后将其设置为应用程序的主窗口对象
CMainFrame* pFrame = new CMainFrame;
if (!pFrame)
return FALSE;
m_pMainWnd = pFrame;
// 创建并加载带有其资源的框架
pFrame->LoadFrame(IDR_MAINFRAME,
WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,
NULL);
// 唯一的一个窗口已初始化,因此显示它并对其进行更新
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
// 仅当存在后缀时才调用 DragAcceptFiles,
// 在 SDI 应用程序中,这应在 ProcessShellCommand 之后发生
// D3D初始化
return pFrame->InitD3D();
}
// CMFCD3DApp 消息处理程序
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// 用于运行对话框的应用程序命令
void CMFCD3DApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
// CMFCD3DApp 消息处理程序
int CMFCD3DApp::Run()
{
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;
lastTime = currTime;
((CMainFrame*)m_pMainWnd)->Render(timeDelta);
}
}
return CWinApp::Run();
}
// MainFrm.cpp : CMainFrame 类的实现
//
#include "stdafx.h"
#include "MFCD3D.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
ON_WM_SETFOCUS()
ON_WM_DESTROY()
END_MESSAGE_MAP()
// CMainFrame 构造/析构
CMainFrame::CMainFrame()
: m_d3dDevice(NULL)
, m_pVB(NULL)
, m_pIB(NULL)
, m_pTex(NULL)
{
// TODO: 在此添加成员初始化代码
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// 创建一个视图以占用框架的工作区
if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
{
TRACE0("未能创建视图窗口\n");
return -1;
}
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("未能创建工具栏\n");
return -1; // 未能创建
}
// TODO: 如果不需要工具栏可停靠,则删除这三行
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: 在此处通过修改 CREATESTRUCT cs 来修改窗口类或
// 样式
cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
| WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
cs.lpszClass = AfxRegisterWndClass(0);
return TRUE;
}
// CMainFrame 诊断
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
// CMainFrame 消息处理程序
void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
{
// 将焦点前移到视图窗口
m_wndView.SetFocus();
}
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// 让视图第一次尝试该命令
if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// 否则,执行默认处理
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
// 初始化D3D
BOOL CMainFrame::InitD3D(void)
{
ASSERT(IsWindow(m_wndView.m_hWnd));
// 初始化Direct3D9
// Step1.获得IDirect3D9接口
IDirect3D9* _d3d9;
_d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if(!_d3d9)
{
::AfxMessageBox(_T("Get Interface of Direct3D Failed!") , MB_ICONSTOP);
return FALSE;
}
// Step2.检查显卡能力
D3DCAPS9 caps;
_d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT ,
D3DDEVTYPE_HAL ,
&caps);
int vp = 0;
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
// Step3.填充D3DPRESENT_PARAMETERS
D3DPRESENT_PARAMETERS d3dpp;
CRect rect;
GetClientRect(&rect);
ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
d3dpp.BackBufferWidth = rect.Width();
d3dpp.BackBufferHeight = rect.Height();
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = m_wndView.m_hWnd;
d3dpp.Windowed = true; // 一定要为true
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// Step4.创建Direct3D设备
HRESULT hr;
hr = _d3d9->CreateDevice(D3DADAPTER_DEFAULT ,
D3DDEVTYPE_HAL ,
m_wndView.m_hWnd ,
vp ,
&d3dpp ,
&m_d3dDevice);
if(FAILED(hr))
{
switch(hr)
{
case D3DERR_DEVICELOST:
AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_DEVICELOST>") , MB_ICONSTOP);
break;
case D3DERR_INVALIDCALL:
AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_INVALIDCALL>") , MB_ICONSTOP);
break;
case D3DERR_NOTAVAILABLE:
AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_NOTAVAILABLE>") , MB_ICONSTOP);
break;
case D3DERR_OUTOFVIDEOMEMORY:
AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_OUTOFVIDEOMEMORY>") , MB_ICONSTOP);
break;
}
_d3d9->Release();
return FALSE;
}
_d3d9->Release();
// Direct3D9初始化完成
// 装载资源
Setup();
return TRUE;
}
// 装载资源
BOOL CMainFrame::Setup(void)
{
// 创建顶点缓冲区和索引缓冲
m_d3dDevice->CreateVertexBuffer(36 * sizeof(Vertex) ,
D3DUSAGE_WRITEONLY ,
Vertex::FVF ,
D3DPOOL_MANAGED ,
&m_pVB ,
0);
// 填充顶点缓冲区
Vertex* pVertices;
m_pVB->Lock(0 , 0 , (void**)&pVertices , 0);
// 前面
pVertices[0] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 0.0f);
pVertices[1] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
pVertices[2] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[3] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 0.0f);
pVertices[4] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[5] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
// 后面
pVertices[6] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[7] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
pVertices[8] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 1.0f);
pVertices[9] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[10] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 1.0f);
pVertices[11] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
// 上面
pVertices[12] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[13] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
pVertices[14] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 1.0f);
pVertices[15] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
pVertices[16] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 1.0f);
pVertices[17] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 1.0f);
// 下面
pVertices[18] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 0.0f);
pVertices[19] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 0.0f);
pVertices[20] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
pVertices[21] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 0.0f);
pVertices[22] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[23] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
// 左面
pVertices[24] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[25] = Vertex(-1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
pVertices[26] = Vertex(-1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[27] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[28] = Vertex(-1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[29] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
// 右面
pVertices[30] = Vertex(1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[31] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
pVertices[32] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[33] = Vertex(1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[34] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[35] = Vertex(1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
m_pVB->Unlock();
// 创建纹理
D3DXCreateTextureFromFile(m_d3dDevice , _T("bbq.jpg") , &m_pTex);
m_d3dDevice->SetTexture(0 , m_pTex);
m_d3dDevice->SetSamplerState(0 , D3DSAMP_MAGFILTER , D3DTEXF_LINEAR);
m_d3dDevice->SetSamplerState(0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR);
m_d3dDevice->SetSamplerState(0 , D3DSAMP_MIPFILTER , D3DTEXF_POINT);
// 摄像机位置
D3DXVECTOR3 pos(0.0f , 0.0f , -5.0f);
D3DXVECTOR3 tag(0.0f , 0.0f , 0.0f);
D3DXVECTOR3 up(0.0f , 1.0f , 0.0f);
D3DXMATRIX v;
D3DXMatrixLookAtLH(&v , &pos , &tag , &up);
m_d3dDevice->SetTransform(D3DTS_VIEW , &v);
// 设置投影矩阵
D3DXMATRIX proj;
CRect rect;
GetClientRect(&rect);
D3DXMatrixPerspectiveFovLH(&proj , D3DX_PI * 0.5f ,
(float)rect.Width()/(float)rect.Height() ,
1.0f ,
1000.0f);
m_d3dDevice->SetTransform(D3DTS_PROJECTION , &proj);
// 设置渲染状态
m_d3dDevice->SetRenderState(D3DRS_LIGHTING , false);
m_d3dDevice->SetRenderState(D3DRS_CULLMODE , D3DCULL_NONE);
return TRUE;
}
// 渲染
void CMainFrame::Render(float timeDelta)
{
if(m_d3dDevice) // Only use Device methods if we have a valid device.
{
// 旋转正方体
D3DXMATRIX Rx , Ry;
// 在x方向旋转45度
D3DXMatrixRotationX(&Rx , 3.14f / 4.0f);
// 每一帧增加y
static float y = 0.0f;
D3DXMatrixRotationY(&Ry , y);
y += timeDelta;
// 当绕y轴旋转的角度达到360度时,置y为0
if(y >= 6.28f) y = 0.0f;
// 组合两个方向上的旋转
D3DXMATRIX p = Rx * Ry;
m_d3dDevice->SetTransform(D3DTS_WORLD , &p);
// 绘制场景
m_d3dDevice->Clear(0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , 0x000000ff , 1.0f , 0);
// 开始
m_d3dDevice->BeginScene();
{
m_d3dDevice->SetStreamSource(0 , m_pVB , 0 , sizeof(Vertex));
m_d3dDevice->SetFVF(Vertex::FVF);
m_d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST , 0 , 12);
}
m_d3dDevice->EndScene();
// 结束
m_d3dDevice->Present(0 , 0 , 0 , 0);
}
}
// 清除资源
void CMainFrame::CleanUp(void)
{
m_pVB->Release();
m_pTex->Release();
}
void CMainFrame::OnDestroy()
{
CFrameWnd::OnDestroy();
CleanUp();
m_d3dDevice->Release();
}
效果图:
一、Win32 SDK框架
看过Petzold的《Windows程序设计》的朋友应该知道创建窗口的固定步骤。而利用Win32 SDK搭建D3D框架只不过是在这些步骤中加入一些调料罢了。具体步骤如下:
1、注册窗体类;
2、创建窗口;
3、创建消息处理函数;
4、显示窗口;
5、初始化D3D、初始化资源数据(如:顶点向量、纹理等);
6、进入消息循环,用PeekMessage处理消息,以便在空闲时进行渲染。
而初始化D3D又分下面四个步骤:
1、创建IDirect3D9[1]对象;
2、检查硬件性能,判断硬件是否支持特定的功能;
3、填充D3DPRESENT_PARAMETERS结构;
4、利用第3步中的结构体对象创建D3D设备(由于该步骤需要窗体的句柄,所以初始化D3D必须放在显示窗口之后)。
下面是框架代码:
//
// 全局变量
//
IDirect3DDevice9* Device = 0;
bool InitD3D(
HINSTANCE hInstance,
int width, int height,
bool windowed,
D3DDEVTYPE deviceType,
IDirect3DDevice9** device)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)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);
//
// 初始化D3D
//
HRESULT hr = 0;
// 步骤1:创建IDirect3D9对象。
IDirect3D9* d3d9 = 0;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if( !d3d9 )
{
MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
return false;
}
// 步骤2:检查硬件性能(这里只检查了是否支持顶点的硬件处理)
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
int vp = 0;
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
// 步骤3:填充D3DPRESENT_PARAMETERS结构(参数说明请参考MSDN)
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = windowed;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// 步骤4:创建D3D设备
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT, // 主设备
deviceType, // 设备类型
hwnd, // 分配给设备的窗口句柄
vp, // 顶点处理方式
&d3dpp, // 表现参数
device); // 返回创建的设备
if( FAILED(hr) )
{
// 如果创建失败,采用16为深度缓存试试
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT,
deviceType,
hwnd,
vp,
&d3dpp,
device);
if( FAILED(hr) )
{
d3d9->Release();
MessageBox(0, "CreateDevice() - FAILED", 0, 0);
return false;
}
}
d3d9->Release();
return true;
}
// 消息循环
int MsgLoop()
{
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Display(); // 渲染
}
}
return msg.wParam;
}
//
// 框架函数
//
bool Setup()
{
// 你可以在此初始化顶点向量、载入纹理等
return true;
}
void Cleanup()
{
// 清除在Setup中载入的资源
}
bool Display()
{
if( Device ) // 只有当设备有效时才能渲染
{
// 在此填入渲染代码
}
return true;
}
//
// 窗口处理函数
//
LRESULT CALLBACK 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);
}
//
// 程序入口
//
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE prevInstance,
PSTR cmdLine,
int showCmd)
{
if(!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;
}
MsgLoop();
Cleanup();
Device->Release();
return 0;
}
二、MFC框架
利用MFC,我们不用写一行代码就可以创建一个窗体,这是MFC封装了那些繁琐而固定的窗口创建代码,这样我们只需要初始化D3D就可以了。下面是通过不带文档的SDI 作为示例来创建D3D的框架,具体步骤如下:
1、将InitD3D、Setup、Cleanup、Display作为CMainFrame的成员函数,其中InitD3D需被应用程序类调用,应该将其置为public,其余为内部函数;
2、在应用程序类(CWinApp的子类)的InitInstance()中显示窗口之后,对D3D进行初始化;
3、override Run(),其实,这里就是消息循环;
这里需要注意:
填充D3DPRESENT_PARAMETERS时,BackBufferWidth和BackBufferHeight最好设置为客户区大小,hDeviceWindow设置为视窗口的句柄m_wndView.m_hWnd,最重要的是Windowed[2]一定要置为true,否则会产生“无效调用”的错误。
下面是实际代码,该代码渲染了一个带贴图的旋转正方体:
// MFCD3D.cpp : 定义应用程序的类行为。
//
#include "stdafx.h"
#include "MFCD3D.h"
#include "MainFrm.h"
#include <mmsystem.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMFCD3DApp
BEGIN_MESSAGE_MAP(CMFCD3DApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
END_MESSAGE_MAP()
// CMFCD3DApp 构造
CMFCD3DApp::CMFCD3DApp()
{
// TODO: 在此处添加构造代码,
// 将所有重要的初始化放置在 InitInstance 中
}
// 唯一的一个 CMFCD3DApp 对象
CMFCD3DApp theApp;
// CMFCD3DApp 初始化
BOOL CMFCD3DApp::InitInstance()
{
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControls()。否则,将无法创建窗口。
InitCommonControls();
CWinApp::InitInstance();
// 初始化 OLE 库
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
// 标准初始化
// 如果未使用这些功能并希望减小
// 最终可执行文件的大小,则应移除下列
// 不需要的特定初始化例程
// 更改用于存储设置的注册表项
// TODO: 应适当修改该字符串,
// 例如修改为公司或组织名
SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
// 若要创建主窗口,此代码将创建新的框架窗口
// 对象,然后将其设置为应用程序的主窗口对象
CMainFrame* pFrame = new CMainFrame;
if (!pFrame)
return FALSE;
m_pMainWnd = pFrame;
// 创建并加载带有其资源的框架
pFrame->LoadFrame(IDR_MAINFRAME,
WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,
NULL);
// 唯一的一个窗口已初始化,因此显示它并对其进行更新
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
// 仅当存在后缀时才调用 DragAcceptFiles,
// 在 SDI 应用程序中,这应在 ProcessShellCommand 之后发生
// D3D初始化
return pFrame->InitD3D();
}
// CMFCD3DApp 消息处理程序
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// 用于运行对话框的应用程序命令
void CMFCD3DApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
// CMFCD3DApp 消息处理程序
int CMFCD3DApp::Run()
{
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;
lastTime = currTime;
((CMainFrame*)m_pMainWnd)->Render(timeDelta);
}
}
return CWinApp::Run();
}
// MainFrm.cpp : CMainFrame 类的实现
//
#include "stdafx.h"
#include "MFCD3D.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
ON_WM_SETFOCUS()
ON_WM_DESTROY()
END_MESSAGE_MAP()
// CMainFrame 构造/析构
CMainFrame::CMainFrame()
: m_d3dDevice(NULL)
, m_pVB(NULL)
, m_pIB(NULL)
, m_pTex(NULL)
{
// TODO: 在此添加成员初始化代码
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// 创建一个视图以占用框架的工作区
if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
{
TRACE0("未能创建视图窗口\n");
return -1;
}
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("未能创建工具栏\n");
return -1; // 未能创建
}
// TODO: 如果不需要工具栏可停靠,则删除这三行
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: 在此处通过修改 CREATESTRUCT cs 来修改窗口类或
// 样式
cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
| WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
cs.lpszClass = AfxRegisterWndClass(0);
return TRUE;
}
// CMainFrame 诊断
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
// CMainFrame 消息处理程序
void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
{
// 将焦点前移到视图窗口
m_wndView.SetFocus();
}
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// 让视图第一次尝试该命令
if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// 否则,执行默认处理
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
// 初始化D3D
BOOL CMainFrame::InitD3D(void)
{
ASSERT(IsWindow(m_wndView.m_hWnd));
// 初始化Direct3D9
// Step1.获得IDirect3D9接口
IDirect3D9* _d3d9;
_d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if(!_d3d9)
{
::AfxMessageBox(_T("Get Interface of Direct3D Failed!") , MB_ICONSTOP);
return FALSE;
}
// Step2.检查显卡能力
D3DCAPS9 caps;
_d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT ,
D3DDEVTYPE_HAL ,
&caps);
int vp = 0;
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
// Step3.填充D3DPRESENT_PARAMETERS
D3DPRESENT_PARAMETERS d3dpp;
CRect rect;
GetClientRect(&rect);
ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
d3dpp.BackBufferWidth = rect.Width();
d3dpp.BackBufferHeight = rect.Height();
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = m_wndView.m_hWnd;
d3dpp.Windowed = true; // 一定要为true
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// Step4.创建Direct3D设备
HRESULT hr;
hr = _d3d9->CreateDevice(D3DADAPTER_DEFAULT ,
D3DDEVTYPE_HAL ,
m_wndView.m_hWnd ,
vp ,
&d3dpp ,
&m_d3dDevice);
if(FAILED(hr))
{
switch(hr)
{
case D3DERR_DEVICELOST:
AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_DEVICELOST>") , MB_ICONSTOP);
break;
case D3DERR_INVALIDCALL:
AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_INVALIDCALL>") , MB_ICONSTOP);
break;
case D3DERR_NOTAVAILABLE:
AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_NOTAVAILABLE>") , MB_ICONSTOP);
break;
case D3DERR_OUTOFVIDEOMEMORY:
AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_OUTOFVIDEOMEMORY>") , MB_ICONSTOP);
break;
}
_d3d9->Release();
return FALSE;
}
_d3d9->Release();
// Direct3D9初始化完成
// 装载资源
Setup();
return TRUE;
}
// 装载资源
BOOL CMainFrame::Setup(void)
{
// 创建顶点缓冲区和索引缓冲
m_d3dDevice->CreateVertexBuffer(36 * sizeof(Vertex) ,
D3DUSAGE_WRITEONLY ,
Vertex::FVF ,
D3DPOOL_MANAGED ,
&m_pVB ,
0);
// 填充顶点缓冲区
Vertex* pVertices;
m_pVB->Lock(0 , 0 , (void**)&pVertices , 0);
// 前面
pVertices[0] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 0.0f);
pVertices[1] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
pVertices[2] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[3] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 0.0f);
pVertices[4] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[5] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
// 后面
pVertices[6] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[7] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
pVertices[8] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 1.0f);
pVertices[9] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[10] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 1.0f);
pVertices[11] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
// 上面
pVertices[12] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[13] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
pVertices[14] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 1.0f);
pVertices[15] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
pVertices[16] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 1.0f);
pVertices[17] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 1.0f);
// 下面
pVertices[18] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 0.0f);
pVertices[19] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 0.0f);
pVertices[20] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
pVertices[21] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 0.0f);
pVertices[22] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[23] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
// 左面
pVertices[24] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[25] = Vertex(-1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
pVertices[26] = Vertex(-1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[27] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[28] = Vertex(-1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[29] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
// 右面
pVertices[30] = Vertex(1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[31] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
pVertices[32] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[33] = Vertex(1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
pVertices[34] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
pVertices[35] = Vertex(1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
m_pVB->Unlock();
// 创建纹理
D3DXCreateTextureFromFile(m_d3dDevice , _T("bbq.jpg") , &m_pTex);
m_d3dDevice->SetTexture(0 , m_pTex);
m_d3dDevice->SetSamplerState(0 , D3DSAMP_MAGFILTER , D3DTEXF_LINEAR);
m_d3dDevice->SetSamplerState(0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR);
m_d3dDevice->SetSamplerState(0 , D3DSAMP_MIPFILTER , D3DTEXF_POINT);
// 摄像机位置
D3DXVECTOR3 pos(0.0f , 0.0f , -5.0f);
D3DXVECTOR3 tag(0.0f , 0.0f , 0.0f);
D3DXVECTOR3 up(0.0f , 1.0f , 0.0f);
D3DXMATRIX v;
D3DXMatrixLookAtLH(&v , &pos , &tag , &up);
m_d3dDevice->SetTransform(D3DTS_VIEW , &v);
// 设置投影矩阵
D3DXMATRIX proj;
CRect rect;
GetClientRect(&rect);
D3DXMatrixPerspectiveFovLH(&proj , D3DX_PI * 0.5f ,
(float)rect.Width()/(float)rect.Height() ,
1.0f ,
1000.0f);
m_d3dDevice->SetTransform(D3DTS_PROJECTION , &proj);
// 设置渲染状态
m_d3dDevice->SetRenderState(D3DRS_LIGHTING , false);
m_d3dDevice->SetRenderState(D3DRS_CULLMODE , D3DCULL_NONE);
return TRUE;
}
// 渲染
void CMainFrame::Render(float timeDelta)
{
if(m_d3dDevice) // Only use Device methods if we have a valid device.
{
// 旋转正方体
D3DXMATRIX Rx , Ry;
// 在x方向旋转45度
D3DXMatrixRotationX(&Rx , 3.14f / 4.0f);
// 每一帧增加y
static float y = 0.0f;
D3DXMatrixRotationY(&Ry , y);
y += timeDelta;
// 当绕y轴旋转的角度达到360度时,置y为0
if(y >= 6.28f) y = 0.0f;
// 组合两个方向上的旋转
D3DXMATRIX p = Rx * Ry;
m_d3dDevice->SetTransform(D3DTS_WORLD , &p);
// 绘制场景
m_d3dDevice->Clear(0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , 0x000000ff , 1.0f , 0);
// 开始
m_d3dDevice->BeginScene();
{
m_d3dDevice->SetStreamSource(0 , m_pVB , 0 , sizeof(Vertex));
m_d3dDevice->SetFVF(Vertex::FVF);
m_d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST , 0 , 12);
}
m_d3dDevice->EndScene();
// 结束
m_d3dDevice->Present(0 , 0 , 0 , 0);
}
}
// 清除资源
void CMainFrame::CleanUp(void)
{
m_pVB->Release();
m_pTex->Release();
}
void CMainFrame::OnDestroy()
{
CFrameWnd::OnDestroy();
CleanUp();
m_d3dDevice->Release();
}
效果图:
发表评论
-
骨骼蒙皮动画(Skinned Mesh)的原理解析
2015-12-05 19:11 967一)3D模型动画基本原理和分类 3D模型动画的基本原 ... -
Visual C++游戏编程基础(肖永亮)2_1
2009-04-03 19:42 2117// yxbcjc2_1.cpp : 定义应用程序的入口点。 ... -
Papervision Perspective Line material
2008-05-04 10:16 1696// Perspective Line material fo ... -
PV3D学习(1)--插入图片
2008-05-04 09:58 2104只需要将上一例中以下 ... -
详解DX9下3D游戏编程1
2008-04-19 21:28 3168Introduction to 3D Game Program ... -
Papervision3D の BitmapMaterial と MovieMaterial の使用
2008-04-03 16:01 2247package { import flash.disp ... -
BitmapFileMaterial的用法
2008-04-01 12:19 2971package com.hclown.earth3d.map ... -
pv教学
2008-03-28 09:50 1702Papervision3D 教學 part 3.2 -- 子母 ... -
魔術方塊
2008-03-28 09:47 1278看到以前已經有人在沒有 Flash 3D engine 的幫助 ... -
賽車程式
2008-03-28 09:46 1176package { import flash.display. ... -
PV3D2 .0 的经典 包含各种渲染和触发
2008-03-17 14:52 2412最近发现的宝贝,分享下!!值得收藏!! /* ... -
PV3D第一个测试文件
2008-03-15 11:34 2550第一个PV3D的测试文件: 这个实例是根据一个网站视频教程里 ...
相关推荐
DirectX9是微软推出的一套用于Windows平台的多媒体编程接口,它为开发者提供了丰富的图形、音频和输入功能,尤其在...在游戏开发过程中,结合DirectX9的API和实例代码,能够快速搭建游戏框架,实现丰富的3D视觉效果。
3. **框架搭建**: - **初始化Direct3D**:创建设备和上下文,设置特征级别。 - **创建交换链(Swap Chain)**:管理后台缓冲区,用于呈现画面。 - **创建深度/模板缓冲区(DepthStencil Buffer)**:用于判断...
对于初学者来说,理解Direct3D的基本概念,如设备创建、顶点缓冲区、索引缓冲区、像素着色器和顶点着色器等,是入门的关键。Direct3D允许开发者直接控制GPU,实现高效、高质量的3D图形渲染。 .x文件是一种由...
在Windows程序设计中,"框架"一词通常指的是一个预设的结构,它提供了..."到复杂的DirectDraw全屏框架,涵盖了从入门到进阶的多种开发技术,对于任何想深入学习Windows编程或游戏开发的人来说都是一份宝贵的学习材料。
DWR(Direct Web Remoting)是一个开放源码的JavaScript库,它使得在浏览器端与Java后端进行异步通信变得更加简单。DWR的核心功能是提供一种安全、高效的方法,允许JavaScript与服务器上的Java对象直接交互,类似于...
在【基本程序框架的搭建】部分,我们将学习如何利用VC++这一强大的开发工具进行四杆机构程序的编写。VC++支持32位应用程序开发,并广泛应用于桌面应用、服务器软件、系统软件等多个领域。为了构建四杆机构的模拟程序...
在IT领域,DWR(Direct Web Remoting)和Hibernate是两个非常重要的工具,它们分别处理Web应用程序的远程调用和对象关系映射。本文将深入探讨如何结合DWR与Hibernate,通过一个简单的用户名检查功能,帮助初学者理解...
尽管Direct3D(DirectX的一部分)也是一个非常优秀的图形API,但它主要面向Windows平台。相比之下,OpenGL具有更好的跨平台特性,可以在多种操作系统上使用。此外,OpenGL提供了更多底层控制的能力,这对于需要高度...
DWR(Direct Web Remoting)是一种用于在Web应用程序中实现Ajax技术的框架,它使得JavaScript可以直接调用服务器端的Java方法,从而实现了页面的异步更新,提供了更加流畅的用户体验。DWR简化了前端与后端的交互,...
- **传统方法**:早期GPGPU开发主要依赖于图形API如Direct3D和OpenGL,使用汇编或Cg、HLSL等高级着色器语言进行编程,这种方式对于开发者来说难度较大且难以优化。 **知识点4:CUDA简介** - **定义**:CUDA...
Duilib界面编程是一种基于DirectUI技术的用户界面开发框架,主要应用于Windows平台的桌面应用程序开发。这个框架由DuiLib库提供支持,它为开发者提供了丰富的控件和设计工具,以帮助他们创建出美观且功能丰富的图形...