前两天写了天空盒,感觉可以写一个天空穹。其实就是索引缓存的利用,没有什么优化,可是就是有一个隐藏的问题。现在也没有办法解决。实在不想搞了。先放着吧~
效果就是这个效果~
真的心里好难受,如果面设置的少了就会少画一些面。感觉太诡异了。
算了 把代码贴这里,等过些时间等我修养深了。再回来看看吧~
照样 windows dx框架代码
// skysphere.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "skysphere.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_SKYSPHERE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SKYSPHERE));
// 主消息循环:
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_SKYSPHERE));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_SKYSPHERE);
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;
}
这个是windows创建的程序 直接搭建的框架,还算比较好的感觉 呵呵 ,自我感觉良好
然后主要app类
#include "stdafx.h"
#include "GameApp.h"
GameApp::GameApp(void)
{
m_pD3D = NULL;
m_pDevice = NULL;
m_pSky = 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;
if (FAILED(m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps)))
{
return false;
}
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.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, vp, &d3dpp, &m_pDevice)))
{
return false;
}
m_pSky = new Sky();
if (!m_pSky->Init(m_pDevice, 900.0f))
{
return false;
}
if (!m_pSky->LoadTexture("sp.jpg"))
{
return false;
}
return true;
}
void GameApp::Update(void)
{
D3DXMATRIX matView;
D3DXVECTOR3 eye(0.0f, 100.0f, -50.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXVECTOR3 at(0.0f, 110.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);
D3DLIGHT9 light;
ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Direction = D3DXVECTOR3(0.0f, 1.0f, 1.0f);
light.Ambient = light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
light.Specular = D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f);
m_pDevice->SetLight(0, &light);
m_pDevice->LightEnable(0, TRUE);
m_pDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255, 255, 255));
D3DVIEWPORT9 viewPort;
viewPort.X = 0;
viewPort.Y = 0;
viewPort.Width = 800;
viewPort.Height = 600;
viewPort.MinZ = 0.0f;
viewPort.MaxZ = 1.0f;
m_pDevice->SetViewport(&viewPort);
m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, D3DCOLOR_XRGB(0, 0, 50), 1.0f, 0);
if (SUCCEEDED(m_pDevice->BeginScene()))
{
m_pSky->Render();
m_pDevice->EndScene();
m_pDevice->Present(NULL, NULL, NULL, NULL);
}
}
void GameApp::Release(void)
{
if (m_pSky)
{
delete m_pSky;
m_pSky = NULL;
}
if (m_pDevice)
{
m_pDevice->Release();
m_pDevice = NULL;
}
if (m_pD3D)
{
m_pD3D->Release();
m_pD3D = NULL;
}
}
头文件可以有实现文件推理出来。我也就不在这嘚瑟了。
然后是天空穹实现文件 其实就是球面坐标的转换。纯属练习
#include "stdafx.h"
#include "Sky.h"
#include "mmsystem.h"
Sky::Sky(void)
{
m_pDevice = NULL;
m_fRedius = 0.0f;
m_pVB = NULL;
m_pIB = NULL;
m_pTexture = NULL;
}
Sky::~Sky(void)
{
Release();
}
bool Sky::Init(LPDIRECT3DDEVICE9 pDevice, float redius)
{
m_pDevice = pDevice;
m_fRedius = redius;
if (FAILED(m_pDevice->CreateVertexBuffer((SKYLNUM * SKYHNUM + 1) * sizeof(Vertex),D3DUSAGE_WRITEONLY, SKYFVF, D3DPOOL_MANAGED, &m_pVB, NULL)))
{
return false;
}
Vertex* pVertices = NULL;
if (FAILED(m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD)))
{
return false;
}
D3DXVECTOR3 begin(0.0f, m_fRedius, 0.0f);
D3DXVECTOR3 cur(0.0f, 0.0f, 0.0f);
int curIdx = 0;
pVertices[curIdx++] = Vertex(begin, D3DXVECTOR2(0.5f, 0.5f));
float vBase = D3DX_PI/2.0f/(SKYHNUM * 1.0f);
float hBase = D3DX_PI*2.0f/(SKYLNUM * 1.0f);
D3DXMATRIX matRotatez;
D3DXMATRIX matRotatey;
D3DXMATRIX matRotate;
for (int h = 1; h <= SKYHNUM; h++)
{
D3DXVECTOR2 uv(vBase * (h * 1.0f)/D3DX_PI, 0.0f);
D3DXVECTOR2 cur_uv(0.0f, 0.0f);
for (int l = 0; l < SKYLNUM; l++)
{
D3DXMatrixRotationYawPitchRoll(&matRotate, hBase * (l * 1.0f), 0, -vBase * (h * 1.0f));
D3DXVec3TransformCoord(&cur, &begin, &matRotate);
D3DXMatrixRotationZ(&matRotatez, hBase * (l * 1.0f));
D3DXVec2TransformCoord(&cur_uv, &uv, &matRotatez);
pVertices[curIdx++] = Vertex(cur, D3DXVECTOR2(0.5f + cur_uv.x, 0.5f + cur_uv.y));
}
}
m_pVB->Unlock();
if (FAILED(m_pDevice->CreateIndexBuffer((SKYLNUM * 3 + ((SKYHNUM - 1) * SKYLNUM) * 6) * 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;
}
curIdx = 0;
for (int l = 0; l < SKYLNUM; l++)
{
if (l < SKYLNUM - 1)
{
pIndices[curIdx++] = 0;
pIndices[curIdx++] = l + 2;
pIndices[curIdx++] = l + 1;
}
else
{
pIndices[curIdx++] = 0;
pIndices[curIdx++] = 1;
pIndices[curIdx++] = l + 1;
}
}
for (int h = 0; h < SKYHNUM - 1; h++)
{
for (int l = 0; l < SKYLNUM; l++)
{
if (l < SKYLNUM - 1)
{
pIndices[curIdx++] = 1 + SKYLNUM * h + l;
pIndices[curIdx++] = 1 + SKYLNUM * h + l + 1;
pIndices[curIdx++] = 1 + SKYLNUM * (h + 1) + l + 1;
pIndices[curIdx++] = 1 + SKYLNUM * h + l;
pIndices[curIdx++] = 1 + SKYLNUM * (h + 1) + l + 1;
pIndices[curIdx++] = 1 + SKYLNUM * (h + 1) + l;
}
else
{
pIndices[curIdx++] = 1 + SKYLNUM * h + l;
pIndices[curIdx++] = 1 + SKYLNUM * h;
pIndices[curIdx++] = 1 + SKYLNUM * (h + 1);
pIndices[curIdx++] = 1 + SKYLNUM * h + l;
pIndices[curIdx++] = 1 + SKYLNUM * (h + 1);
pIndices[curIdx++] = 1 + SKYLNUM * (h + 1) + l;
}
}
}
m_pIB->Unlock();
return true;
}
bool Sky::LoadTexture(string szFile)
{
if (FAILED(D3DXCreateTextureFromFileA(m_pDevice, szFile.c_str(), &m_pTexture)))
{
return false;
}
return true;
}
void Sky::Render(void)
{
D3DXMATRIX worldMat;
D3DXMatrixRotationY(&worldMat, timeGetTime()/1800.0f);
m_pDevice->SetTransform(D3DTS_WORLD, &worldMat);
D3DMATERIAL9 mtrl;
ZeroMemory(&mtrl, sizeof(mtrl));
mtrl.Ambient = mtrl.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
mtrl.Specular = mtrl.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f);
m_pDevice->SetMaterial(&mtrl);
m_pDevice->SetStreamSource(0, m_pVB,0, sizeof(Vertex));
m_pDevice->SetFVF(SKYFVF);
m_pDevice->SetIndices(m_pIB);
m_pDevice->SetTexture(0, m_pTexture);
m_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 1, SKYLNUM * 3, SKYLNUM * (SKYHNUM - 1) * 6,SKYLNUM * 3, SKYLNUM * (SKYHNUM - 1) * 2);
}
void Sky::Release(void)
{
m_pDevice = NULL;
m_fRedius = 0.0f;
if (m_pTexture)
{
m_pTexture->Release();
m_pTexture = NULL;
}
if (m_pIB)
{
m_pIB->Release();
m_pIB = NULL;
}
if (m_pVB)
{
m_pVB->Release();
m_pVB = NULL;
}
}
恩实现的就是这样子了。然后再来一个图吧,显得图文并茂。
总结一下:
还是顶点缓存和索引感觉不是很实在,数据都对竟然显示不正确
数学转换 d3d提供的api没有熟悉,一开始我是各种三角函数转换,可是发现繁琐死了,api也不熟悉更是悲剧
最后这个程序没有任何优化 就是为了显示而显示 可取之处聊胜于无,不过,我就是这样一点一点的练习。