很久没有写博客了,今天就是实现了一个天空盒。嘚瑟一下,我写的博客很少有人看,纯粹自语自乐,就是为了记录自己的学习过程的。
程序主要两个类, gameapp和skybox 我的图片就是随便下载了一张,貌似就是赤裸裸的盗版。
创建windows程序以后 直接修改关键代码就是都d3d游戏框架了,很速度。
额 直接上结果和代码吧。
就是这个样子。呵呵,围绕着y轴旋转。
然后呢 架构代码
// dxskybox.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "dxskybox.h"
#include "gameapp.h"
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
GameApp g_GameApp;
// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代码。
MSG msg;
HACCEL hAccelTable;
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_DXSKYBOX, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DXSKYBOX));
// 主消息循环:
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
g_GameApp.Update();
}
}
return (int) msg.wParam;
}
//
// 函数: MyRegisterClass()
//
// 目的: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DXSKYBOX));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_DXSKYBOX);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 将实例句柄存储在全局变量中
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
if (!g_GameApp.Init(hInstance, hWnd))
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
g_GameApp.Release();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
挺能吓唬人的 不过能看懂的看客会发现没有修改几行,看不懂额看客就会觉得坑爹。
然后是程序类实现 文件 头文件由实现文件就可以推理出来的
#include "stdafx.h"
#include "GameApp.h"
GameApp::GameApp(void)
{
m_pD3D = NULL;
m_pDevice = NULL;
m_pSkyBox = NULL;
}
GameApp::~GameApp(void)
{
Release();
}
bool GameApp::Init(HINSTANCE hInstance, HWND hWnd)
{
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!m_pD3D)
{
return false;
}
D3DCAPS9 caps;
ZeroMemory(&caps, sizeof(caps));
m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
int vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.EnableAutoDepthStencil = TRUE;
if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, vp, &d3dpp, &m_pDevice)))
{
return false;
}
m_pSkyBox = new SkyBox();
if (!m_pSkyBox->Init(m_pDevice, 500.0f))
{
return false;
}
vector<string> szFiles;
szFiles.push_back("tkh.jpg");
szFiles.push_back("tkh.jpg");
szFiles.push_back("tkh.jpg");
szFiles.push_back("tkh.jpg");
szFiles.push_back("tkh.jpg");
szFiles.push_back("tkh.jpg");
if (!m_pSkyBox->LoadTextures(szFiles))
{
return false;
}
return true;
}
void GameApp::Update(void)
{
m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, D3DCOLOR_XRGB(0,0,20), 1.0f, 0);
if (SUCCEEDED(m_pDevice->BeginScene()))
{
m_pSkyBox->Render();
m_pDevice->EndScene();
m_pDevice->Present(NULL, NULL, NULL, NULL);
}
}
void GameApp::Release(void)
{
if (m_pDevice)
{
m_pDevice->Release();
m_pDevice = NULL;
}
if (m_pD3D)
{
m_pD3D->Release();
m_pD3D = NULL;
}
}
恩 非常简单的类实现 标准的游戏结构
初始化
更新
释放资源 感觉高大上
然后是这个文章的噱头 那就是天空盒子
#include "stdafx.h"
#include "SkyBox.h"
#include "mmsystem.h"
SkyBox::SkyBox(void)
{
m_pDevice = NULL;
m_pVB = NULL;
m_pIB = NULL;
ZeroMemory(m_pTextures, sizeof(m_pTextures));
}
SkyBox::~SkyBox(void)
{
Release();
}
bool SkyBox::Init(LPDIRECT3DDEVICE9 pDevice, float fWidth)
{
m_pDevice = pDevice;
if (FAILED(m_pDevice->CreateVertexBuffer(24 * sizeof(SkyBoxVertex), D3DUSAGE_WRITEONLY, eSkyBoxFVF, D3DPOOL_MANAGED, &m_pVB, NULL)))
{
return false;
}
SkyBoxVertex* pVertices = NULL;
if (FAILED(m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD)))
{
return false;
}
//上面
pVertices[0] = SkyBoxVertex(-fWidth/2.0f, fWidth/2.0f, -fWidth/2.0f, 0.0f, 0.0f);
pVertices[1] = SkyBoxVertex(fWidth/2.0f, fWidth/2.0f, -fWidth/2.0f, 1.0f, 0.0f);
pVertices[2] = SkyBoxVertex(fWidth/2.0f, fWidth/2.0f, fWidth/2.0f, 1.0f, 1.0f);
pVertices[3] = SkyBoxVertex(-fWidth/2.0f, fWidth/2.0f, fWidth/2.0f, 0.0f, 1.0f);
//下面
pVertices[4] = SkyBoxVertex(-fWidth/2.0f, -fWidth/2.0f, fWidth/2.0f, 0.0f, 0.0f);
pVertices[5] = SkyBoxVertex(fWidth/2.0f, -fWidth/2.0f, fWidth/2.0f, 1.0f, 0.0f);
pVertices[6] = SkyBoxVertex(fWidth/2.0f, -fWidth/2.0f, -fWidth/2.0f, 1.0f, 1.0f);
pVertices[7] = SkyBoxVertex(-fWidth/2.0f, -fWidth/2.0f, -fWidth/2.0f, 0.0f, 1.0f);
//左面
pVertices[8] = SkyBoxVertex(-fWidth/2.0f, fWidth/2.0f, -fWidth/2.0f, 0.0f, 0.0f);
pVertices[9] = SkyBoxVertex(-fWidth/2.0f, fWidth/2.0f, fWidth/2.0f, 1.0f, 0.0f);
pVertices[10] = SkyBoxVertex(-fWidth/2.0f, -fWidth/2.0f, fWidth/2.0f, 1.0f, 1.0f);
pVertices[11] = SkyBoxVertex(-fWidth/2.0f, -fWidth/2.0f, -fWidth/2.0f, 0.0f, 1.0f);
//右面
pVertices[12] = SkyBoxVertex(fWidth/2.0f, fWidth/2.0f, fWidth/2.0f, 0.0f, 0.0f);
pVertices[13] = SkyBoxVertex(fWidth/2.0f, fWidth/2.0f, -fWidth/2.0f, 1.0f, 0.0f);
pVertices[14] = SkyBoxVertex(fWidth/2.0f, -fWidth/2.0f, -fWidth/2.0f, 1.0f, 1.0f);
pVertices[15] = SkyBoxVertex(fWidth/2.0f, -fWidth/2.0f, fWidth/2.0f, 0.0f, 1.0f);
//前面
pVertices[16] = SkyBoxVertex(-fWidth/2.0f, fWidth/2.0f, fWidth/2.0f, 0.0f, 0.0f);
pVertices[17] = SkyBoxVertex(fWidth/2.0f, fWidth/2.0f, fWidth/2.0f, 1.0f, 0.0f);
pVertices[18] = SkyBoxVertex(fWidth/2.0f, -fWidth/2.0f, fWidth/2.0f, 1.0f, 1.0f);
pVertices[19] = SkyBoxVertex(-fWidth/2.0f, -fWidth/2.0f, fWidth/2.0f, 0.0f, 1.0f);
//后面
pVertices[20] = SkyBoxVertex(fWidth/2.0f, fWidth/2.0f, -fWidth/2.0f, 0.0f, 0.0f);
pVertices[21] = SkyBoxVertex(-fWidth/2.0f, fWidth/2.0f, -fWidth/2.0f, 1.0f, 0.0f);
pVertices[22] = SkyBoxVertex(-fWidth/2.0f, -fWidth/2.0f, -fWidth/2.0f, 1.0f, 1.0f);
pVertices[23] = SkyBoxVertex(fWidth/2.0f, -fWidth/2.0f, -fWidth/2.0f, 0.0f, 1.0f);
m_pVB->Unlock();
if (FAILED(m_pDevice->CreateIndexBuffer(36 * sizeof(DWORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX32, D3DPOOL_MANAGED, &m_pIB, NULL)))
{
return false;
}
DWORD* pIndices = NULL;
if (FAILED(m_pIB->Lock(0, 0, (void**)&pIndices, D3DLOCK_DISCARD)))
{
return false;
}
for (int idx = 0; idx < 6; idx++)
{
pIndices[idx * 6] = idx * 4;
pIndices[idx * 6 + 1] = idx * 4 + 1;
pIndices[idx * 6 + 2] = idx * 4 + 2;
pIndices[idx * 6 + 3] = idx * 4;
pIndices[idx * 6 + 4] = idx * 4 + 2;
pIndices[idx * 6 + 5] = idx * 4 + 3;
}
m_pIB->Unlock();
return true;
}
bool SkyBox::LoadTextures(vector<string> szFiles)
{
for (int idx = 0; idx < 6; idx++)
{
if (FAILED(D3DXCreateTextureFromFileA(m_pDevice, szFiles[idx].c_str(), &m_pTextures[idx])))
{
return false;
}
}
return true;
}
void SkyBox::Render(void)
{
D3DXMATRIX matWorld;
D3DXMatrixRotationY(&matWorld, timeGetTime()/1800.0f);
m_pDevice->SetTransform(D3DTS_WORLD, &matWorld);
D3DXMATRIX matView;
D3DXVECTOR3 eye(-400.0, 0.0f, 0.0f);
D3DXVECTOR3 at(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&matView, &eye, &at, &up);
m_pDevice->SetTransform(D3DTS_VIEW, &matView);
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4.0f, 1.0f, 0.0f, 1000.0f);
m_pDevice->SetTransform(D3DTS_PROJECTION, &matProj);
D3DVIEWPORT9 viewPort;
ZeroMemory(&viewPort, sizeof(viewPort));
viewPort.X = 0;
viewPort.Y = 0;
viewPort.Width = 800;
viewPort.Height = 600;
viewPort.MinZ = 0;
viewPort.MaxZ = 1;
m_pDevice->SetViewport(&viewPort);
D3DMATERIAL9 mtrl;
mtrl.Ambient = mtrl.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
mtrl.Emissive = mtrl.Specular = D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f);
m_pDevice->SetMaterial(&mtrl);
D3DLIGHT9 light;
light.Ambient = light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
light.Specular = D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f);
light.Type = D3DLIGHT_DIRECTIONAL;
light.Direction = D3DXVECTOR3(0.0f, -1.0f, 1.0f);
m_pDevice->SetLight(0, &light);
m_pDevice->LightEnable(0, TRUE);
m_pDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255, 255, 255));
m_pDevice->SetStreamSource(0, m_pVB, 0, sizeof(SkyBoxVertex));
m_pDevice->SetFVF(eSkyBoxFVF);
m_pDevice->SetIndices(m_pIB);
for (int idx = 0; idx < 6; idx++)
{
m_pDevice->SetTexture(0, m_pTextures[idx]);
m_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, idx * 4, idx * 6, 4, 0, 2);
}
}
void SkyBox::Release(void)
{
for (int idx = 0; idx < 6; idx++)
{
if (m_pTextures[idx])
{
m_pTextures[idx]->Release();
m_pTextures[idx] = NULL;
}
}
if (m_pIB)
{
m_pIB->Release();
m_pIB = NULL;
}
if (m_pVB)
{
m_pVB->Release();
m_pVB = NULL;
}
m_pDevice = NULL;
}
恩 也是非常简单的代码 或许是写的人觉得简单吧。我学习的时候也是捉摸半天,学过了也就简单了。这个东西还是需要练习。
再来一张图片吧 显得咱这博客内容充实
这个东西技术性倒是不是很难。感觉还是练习顶点和索引缓冲,当然 有摄像机的话 还得根据摄像机的位置来更新天空盒子的位置。
回忆一下的话 这个程序最主要的地方还是理解渲染流水线和一个绘制索引缓冲的函数。固定渲染管线貌似有了点基础。以后还得学习可编程渲染管线了。
一些个裁切设置和各种测试理解还不是很透彻。有点心虚撒~
好了,就如此吧。天空盒子,某也写出来啦~