用DX11绘画底面为五角星的棱锥以及鼠标键盘对该棱锥控制的实现过程
一.五角星棱锥的实现:
1.原理实现:通过LINELIST的图元类型将五角星的十个顶点连接起来,再取五角星的五个点与上方的顶点连接起来
图元类型: D3D11_PRIMITIVE_TOPOLOGY_LINELIST
2.代码改动:
1)设置好顶点的位置,十个顶点的在二维直角坐标系下的坐标如下
用代码设置好顶点的位置
VertexPosColor vertices[] =
{
{ XMFLOAT3(0.0f, 1.0f, 0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{ XMFLOAT3(0.0f,-(1 + tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) / (3 - tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)), -0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{ XMFLOAT3(cos(18.0 / 180.0 * XM_PI), sin(18.0 / 180.0 * XM_PI), 0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{ XMFLOAT3(-(1 + tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) / (3 - tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) * cos(18.0 / 180.0 * XM_PI), -(1 + tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) / (3 - tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) * sin(18.0 / 180.0 * XM_PI), 0.0f),XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{ XMFLOAT3(cos(54.0 / 180.0 * XM_PI), -sin(54.0 / 180.0 * XM_PI), 0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{XMFLOAT3(-(1 + tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) / (3 - tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) * cos(54.0 / 180.0 * XM_PI),-(1 + tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) / (3 - tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) * -sin(54.0 / 180.0 * XM_PI), 0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{ XMFLOAT3(-cos(54.0 / 180.0 * XM_PI), -sin(54.0 / 180.0 * XM_PI), 0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{ XMFLOAT3(-(1 + tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) / (3 - tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) * -cos(54.0 / 180.0 * XM_PI),-(1 + tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) / (3 - tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) * -sin(54.0 / 180.0 * XM_PI), 0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{ XMFLOAT3(-cos(18.0 / 180.0 * XM_PI), sin(18.0 / 180.0 * XM_PI), 0.0f),XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{ XMFLOAT3(-(1 + tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) / (3 - tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) * -cos(18.0 / 180.0 * XM_PI), -(1 + tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) / (3 - tan(18.0 / 180.0 * XM_PI) * tan(18.0 / 180.0 * XM_PI)) * sin(18.0 / 180.0 * XM_PI),0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
{ XMFLOAT3(0.0f, 0.0f, 1.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
};
2)设置好顶点的连接顺序,通过索引数组指定连接顺序
DWORD indices[] = {
//画出五角星的底面
0,7,7,
2,2,9,
9,4,4,
1,1,6,
6,3,3,
8,8,5,
5,0,
//连接顶点
0,10,10,8,
8,10,10,6,
6,10,10,4,
4,10,10,2,
2,10,10,0,
};
3)修改打印顶点的个数
// 绘制立方体
m_pd3dImmediateContext->DrawIndexed(40, 0, 0);//修改为40个
4)效果图
二.实现鼠标和键盘对该锥体的控制
1)代码改动如下:
d3dApp.h
#include "Mouse.h" //加入两行头文件
#include "Keyboard.h"
//在protected中加入对鼠标键盘以及鼠标键盘状态追踪器
protected:
HINSTANCE m_hAppInst; // 应用实例句柄
HWND m_hMainWnd; // 主窗口句柄
bool m_AppPaused; // 应用是否暂停
bool m_Minimized; // 应用是否最小化
bool m_Maximized; // 应用是否最大化
bool m_Resizing; // 窗口大小是否变化
bool m_Enable4xMsaa; // 是否开启4倍多重采样
UINT m_4xMsaaQuality; // MSAA支持的质量等级
GameTimer m_Timer; // 计时器
// 使用模板别名(C++11)简化类型名
template <class T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
// Direct3D 11
ComPtr<ID3D11Device> m_pd3dDevice; // D3D11设备
ComPtr<ID3D11DeviceContext> m_pd3dImmediateContext; // D3D11设备上下文
ComPtr<IDXGISwapChain> m_pSwapChain; // D3D11交换链
// Direct3D 11.1
ComPtr<ID3D11Device1> m_pd3dDevice1; // D3D11.1设备
ComPtr<ID3D11DeviceContext1> m_pd3dImmediateContext1; // D3D11.1设备上下文
ComPtr<IDXGISwapChain1> m_pSwapChain1; // D3D11.1交换链
// 常用资源
ComPtr<ID3D11Texture2D> m_pDepthStencilBuffer; // 深度模板缓冲区
ComPtr<ID3D11RenderTargetView> m_pRenderTargetView; // 渲染目标视图
ComPtr<ID3D11DepthStencilView> m_pDepthStencilView; // 深度模板视图
D3D11_VIEWPORT m_ScreenViewport; // 视口
std::unique_ptr<DirectX::Mouse> m_pMouse; // 鼠标
DirectX::Mouse::ButtonStateTracker m_MouseTracker; // 鼠标状态追踪器
std::unique_ptr<DirectX::Keyboard> m_pKeyboard; // 键盘
DirectX::Keyboard::KeyboardStateTracker m_KeyboardTracker;
// 派生类应该在构造函数设置好这些自定义的初始参数
std::wstring m_MainWndCaption; // 主窗口标题
int m_ClientWidth; // 视口宽度
int m_ClientHeight; // 视口高度
};
GameApp.cpp
bool GameApp::Init()
{
if (!D3DApp::Init())
return false;
if (!InitEffect())
return false;
if (!InitResource())
return false;
// 初始化鼠标,键盘不需要
m_pMouse->SetWindow(m_hMainWnd);
m_pMouse->SetMode(DirectX::Mouse::MODE_ABSOLUTE);
return true;
}
void GameApp::UpdateScene(float dt)
{
static float cubePhi = 0.0f, cubeTheta = 0.0f;
// 获取鼠标状态
Mouse::State mouseState = m_pMouse->GetState();
Mouse::State lastMouseState = m_MouseTracker.GetLastState();
// 获取键盘状态
Keyboard::State keyState = m_pKeyboard->GetState();
Keyboard::State lastKeyState = m_KeyboardTracker.GetLastState();
// 更新鼠标按钮状态跟踪器,仅当鼠标按住的情况下才进行移动
m_MouseTracker.Update(mouseState);
m_KeyboardTracker.Update(keyState);
if (mouseState.leftButton == true && m_MouseTracker.leftButton == m_MouseTracker.HELD)
{
cubeTheta -= (mouseState.x - lastMouseState.x) * 0.01f;
cubePhi -= (mouseState.y - lastMouseState.y) * 0.01f;
}
if (keyState.IsKeyDown(Keyboard::W))
cubePhi += dt * 2;
if (keyState.IsKeyDown(Keyboard::S))
cubePhi -= dt * 2;
if (keyState.IsKeyDown(Keyboard::A))
cubeTheta += dt * 2;
if (keyState.IsKeyDown(Keyboard::D))
cubeTheta -= dt * 2;
m_CBuffer.world = XMMatrixTranspose(XMMatrixRotationY(cubeTheta) * XMMatrixRotationX(cubePhi));
// 更新常量缓冲区,让立方体转起来
D3D11_MAPPED_SUBRESOURCE mappedData;
HR(m_pd3dImmediateContext->Map(m_pConstantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
memcpy_s(mappedData.pData, sizeof(m_CBuffer), &m_CBuffer, sizeof(m_CBuffer));
m_pd3dImmediateContext->Unmap(m_pConstantBuffer.Get(), 0);
}
void GameApp::DrawScene()
{
assert(m_pd3dImmediateContext);
assert(m_pSwapChain);
static float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // RGBA = (0,0,0,255)
m_pd3dImmediateContext->ClearRenderTargetView(m_pRenderTargetView.Get(), reinterpret_cast<const float*>(&black));
m_pd3dImmediateContext->ClearDepthStencilView(m_pDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
// 绘制立方体
m_pd3dImmediateContext->DrawIndexed40, 0, 0);
HR(m_pSwapChain->Present(0, 0));
}
d3dApp.h
LRESULT D3DApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// 省略原有的部分...
// 监测这些键盘/鼠标事件
case WM_INPUT:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_XBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
case WM_XBUTTONUP:
case WM_MOUSEWHEEL:
case WM_MOUSEHOVER:
case WM_MOUSEMOVE:
m_pMouse->ProcessMessage(msg, wParam, lParam);
return 0;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
m_pKeyboard->ProcessMessage(msg, wParam, lParam);
return 0;
case WM_ACTIVATEAPP:
m_pMouse->ProcessMessage(msg, wParam, lParam);
m_pKeyboard->ProcessMessage(msg, wParam, lParam);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
- 效果图如下