注意点
- 需要安装dx9.0和vs2019设置,可以参考这个https://www.cnblogs.com/Thermo/p/15779136.html
- 顶点缓存6个面中后面和下面是以左下角坐标逆时针写的,其他面都是顺时针的,这样导致画每个面的三角形按照顶点的渲染方式不一样,为什么后面和下面这样去渲染呢?如果6个面按照同样的方式就会有显示错误。
代码
- Vertex.h
struct Vertex
{
Vertex() {}
Vertex(float x, float y, float z, float nx, float ny, float nz, float u, float v)
{
_x = x; _y = y; _z = z;
_nx = nx; _ny = ny; _nz = nz;
_u = u; _v = v;
}
float _x, _y, _z;
float _nx, _ny, _nz;
float _u, _v;
};
#define FVF_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
- Cube.h
#include <d3dx9.h>
class Cube
{
public:
Cube(IDirect3DDevice9* device);
~Cube();
bool draw(D3DXMATRIX* world, D3DMATERIAL9* mtrl, IDirect3DTexture9* tex);
private:
IDirect3DDevice9* _device;
IDirect3DVertexBuffer9* _vb;
IDirect3DIndexBuffer9* _ib;
};
- Cube.cpp
#include "Cube.h"
#include "d3dUtility.h"
#include "Vertex.h"
Cube::Cube(IDirect3DDevice9* device)
{
_device = device;
//创建顶点缓存
device->CreateVertexBuffer(24 * sizeof(Vertex), D3DUSAGE_WRITEONLY, FVF_VERTEX, D3DPOOL_MANAGED, &_vb, nullptr);
Vertex* v;
_vb->Lock(0, 0, (void**)&v, 0);
//前面
v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[1] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[2] = Vertex(1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
v[3] = Vertex(1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
//后面
v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
v[5] = Vertex(1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
v[6] = Vertex(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
v[7] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);
//左面
v[8] = Vertex(-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[9] = Vertex(-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[10] = Vertex(-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
v[11] = Vertex(-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
//右面
v[12] = Vertex(1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[13] = Vertex(1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[14] = Vertex(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
v[15] = Vertex(1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
//上面
v[16] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
v[17] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
v[18] = Vertex(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f);
v[19] = Vertex(1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
//下面
v[20] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f);
v[21] = Vertex(1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f);
v[22] = Vertex(1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f);
v[23] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);
_vb->Unlock();
//创建索引缓存
_device->CreateIndexBuffer(36 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &_ib, nullptr);
WORD* i;
_ib->Lock(0, 0, (void**)&i, 0);
//前面
i[0] = 0; i[1] = 1; i[2] = 2;
i[3] = 0; i[4] = 2; i[5] = 3;
//后面
i[6] = 4; i[7] = 5; i[8] = 6;
i[9] = 4; i[10] = 6; i[11] = 7;
//左边
i[12] = 8; i[13] = 9; i[14] = 10;
i[15] = 8; i[16] = 10; i[17] = 11;
//右边
i[18] = 12; i[19] = 13; i[20] = 14;
i[21] = 12; i[22] = 14; i[23] = 15;
//上面
i[24] = 16; i[25] = 17; i[26] = 18;
i[27] = 16; i[28] = 18; i[29] = 19;
//下面
i[30] = 20; i[31] = 21; i[32] = 22;
i[33] = 20; i[34] = 22; i[35] = 23;
_ib->Unlock();
}
Cube::~Cube()
{
d3d::Release<IDirect3DVertexBuffer9*>(_vb);
d3d::Release<IDirect3DIndexBuffer9*>(_ib);
}
bool Cube::draw(D3DXMATRIX* world, D3DMATERIAL9* mtrl, IDirect3DTexture9* tex)
{
//设置世界坐标
if (world)
_device->SetTransform(D3DTS_WORLD, world);
//设置物体材质
if (mtrl)
_device->SetMaterial(mtrl);
//设置纹理
if (tex)
_device->SetTexture(0, tex);
_device->BeginScene();
_device->SetStreamSource(0, _vb, 0, sizeof(Vertex));
_device->SetFVF(FVF_VERTEX);
_device->SetIndices(_ib);
_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 36);
_device->EndScene();
return true;
}
- texCube.cpp
#include "d3dUtility.h"
#include "Cube.h"
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "winmm.lib")
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#define KEY_DOWN(vk_code) (GetAsyncKeyState(vk_code) & 0x8000 ? 1 : 0)
IDirect3DDevice9* device = nullptr;
Cube* box = nullptr;
D3DMATERIAL9 mtrl;
IDirect3DTexture9* tex = nullptr;
bool Setup()
{
box = new Cube(device);
//材质
mtrl = d3d::WHITE_MTRL;
//灯光
D3DLIGHT9 light;
ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Ambient = D3DXCOLOR(0.8f, 0.8f, 0.8f, 1.0f);
light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
light.Specular = D3DXCOLOR(0.2f, 0.2f, 0.2f, 1.0f);
light.Direction = D3DXVECTOR3(1.0f, -1.0f, 0.0f);
device->SetLight(0, &light);
device->LightEnable(0, true);
//设置渲染灯光可用
//device->SetRenderState(D3DRS_LIGHTING, true);
//设置法线从新规范化
device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
//设置镜面高光可用
device->SetRenderState(D3DRS_SPECULARENABLE, true);
//纹理
D3DXCreateTextureFromFile(device, TEXT("crate.jpg"), &tex);
//设置过滤器
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
//投影窗口
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI * 0.5f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 1.0f, 1000.0f);
device->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
bool Display(float timeDetla)
{
if (device)
{
static float angle = (3.0f * D3DX_PI) / 2.0f;
static float height = 2.0f;
if (KEY_DOWN(VK_LEFT))
angle += 0.5f * timeDetla;
if (KEY_DOWN(VK_RIGHT))
angle -= 0.5f * timeDetla;
if (KEY_DOWN(VK_UP))
height += 5.0f * timeDetla;
if (KEY_DOWN(VK_DOWN))
height -= 5.0f * timeDetla;
D3DXVECTOR3 position(cosf(angle) * 3.0f, height, sinf(angle) * 3.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &up);
device->SetTransform(D3DTS_VIEW, &V);
device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
box->draw(nullptr, &mtrl, tex);
device->Present(nullptr, nullptr, nullptr, nullptr);
}
return true;
}
bool Cleanup()
{
d3d::Delete<Cube*>(box);
d3d::Release<IDirect3DTexture9*>(tex);
return true;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
if (!d3d::InitD3D(hInstance, WINDOW_WIDTH, WINDOW_HEIGHT, true, D3DDEVTYPE_HAL, &device))
{
MessageBox(nullptr, TEXT("InitD3D() - FAILED"), TEXT("ERROR"), MB_ICONERROR);
return 0;
}
if (!Setup())
{
MessageBox(nullptr, TEXT("Setup() - FAILED"), TEXT("ERROR"), MB_ICONERROR);
return 0;
}
d3d::EnterMsgLoop(Display);
Cleanup();
device->Release();
return 1;
}
- d3dUtility.h
#include <d3d9.h>
#include <d3dx9math.h>
namespace d3d
{
bool InitD3D(HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** 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 = nullptr;
}
}
template<class T> void Delete(T t)
{
if (t)
{
delete t;
t = nullptr;
}
}
const D3DXCOLOR WHITE(D3DCOLOR_XRGB(255, 255, 255));
const D3DXCOLOR BLACK(D3DCOLOR_XRGB(0, 0, 0));
const D3DXCOLOR RED(D3DCOLOR_XRGB(255, 0, 0));
const D3DXCOLOR GREEN(D3DCOLOR_XRGB(0, 255, 0));
const D3DXCOLOR BLUE(D3DCOLOR_XRGB(0, 0, 255));
const D3DXCOLOR YELLOW(D3DCOLOR_XRGB(255, 255, 0));
const D3DXCOLOR CYAN(D3DCOLOR_XRGB(0, 255, 255));
const D3DXCOLOR MAGENTA(D3DCOLOR_XRGB(255, 0, 255));
//材质
D3DMATERIAL9 InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p);
const D3DMATERIAL9 WHITE_MTRL = InitMtrl(WHITE, WHITE, WHITE, BLACK, 8.0f);
const D3DMATERIAL9 RED_MTRL = InitMtrl(RED, RED, RED, BLACK, 8.0f);
const D3DMATERIAL9 GREEN_MTRL = InitMtrl(GREEN, GREEN, GREEN, BLACK, 8.0f);
const D3DMATERIAL9 BLUE_MTRL = InitMtrl(BLUE, BLUE, BLUE, BLACK, 8.0f);
const D3DMATERIAL9 YELLOW_MTRL = InitMtrl(YELLOW, YELLOW, YELLOW, BLACK, 8.0f);
//光源
D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color);
//D3DLIGHT9 InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color);
//D3DLIGHT9 InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color);
}
- d3dUtility.cpp
#include "d3dUtility.h"
bool d3d::InitD3D(HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device)
{
//注册wndclass
WNDCLASS wndclass;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(nullptr, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = nullptr;
wndclass.lpszClassName = TEXT("d3d");
if (!RegisterClass(&wndclass))
{
MessageBox(nullptr, TEXT("RegisterClass() - FAILED"), TEXT("ERROR"), MB_ICONERROR);
return false;
}
//创建窗口
HWND hwnd = CreateWindow(TEXT("d3d"), TEXT("d3d window"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, width, height,
nullptr, nullptr, hInstance, nullptr);
//设备列举和创建IDirect3DDevice9对象
IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
//检测硬件顶点处理
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; //不支持
D3DDISPLAYMODE d3ddm;
if (FAILED(d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
return false;
//填充D3DPRESENT_PARAMETERS结构
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
//d3dpp.BackBufferFormat = D3DFMT_A8B8G8R8;//像素格式
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = windowed;//full screen
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//depth format
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
//创建IDirect3DDevice9对象
HRESULT hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, device);
if (FAILED(hr))
{
MessageBox(nullptr, TEXT("CraeteDevice() - FAILED"), TEXT("ERROR"), MB_ICONERROR);
return false;
}
d3d9->Release();
return true;
}
int d3d::EnterMsgLoop(bool(*ptr_display)(float timeDelta))
{
MSG msg;
memset(&msg, 0, sizeof(msg));
static float lastTime = (float)timeGetTime();
while (true)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
float currTime = (float)timeGetTime();
float timeDelta = (currTime - lastTime)*0.001f;
ptr_display(timeDelta);
lastTime = currTime;
}
}
return msg.wParam;
}
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);
}
D3DMATERIAL9 d3d::InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p)
{
D3DMATERIAL9 mtrl;
mtrl.Ambient = a; //环境光
mtrl.Diffuse = d; //漫反射
mtrl.Specular = s; //镜面反射
mtrl.Emissive = e; //表面添加颜色
mtrl.Power = p; //镜面高光
return mtrl;
}
D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color)
{
D3DLIGHT9 light;
ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse = *color;
light.Ambient = *color * 0.3f;
light.Specular = *color * 0.6f;
light.Direction = *direction;
return light;
}
效果