目录
一、索引缓冲区:
二、常量缓冲区:
一、索引缓冲区:
前言:
当我们要绘制如下图所示的立体图形棱台时,如果我们用顶点缓冲区来绘制的话,那我们需要绘制36个顶点。其中,我们知道棱台也就拥有8个顶点,这也说明了其余的28个顶点是重复的顶点。
能不能减少顶点的创建获得内存与性能的提升呢?那么,索引缓冲区的作用就来了!
1.下图是棱台的八个顶点
2.然后我们再把顶点数据放到索引数组里,我们就可以重复地利用顶点数据了,如下图所示
解释:如0,1,2就是利用第0个顶点,第1个顶点和第2个顶点绘制了一个三角形,所以这里,我们就利用了012,230六个顶点即两个三角形来绘制正面(四边形)
似乎特别容易理解,但是我们还没有创建索引缓冲区呢!我们需要索引缓冲区来和设备上下文打交道。
创建缓冲区:
//=======================================索引缓存的设置==============================================
// --------索引数组
DWORD indices[] =
{
// 正面
0, 1, 2,
2, 3, 0,
// 左面
4, 5, 1,
1, 0, 4,
// 顶面
1, 5, 6,
6, 2, 1,
// 背面
7, 6, 5,
5, 4, 7,
// 右面
3, 2, 6,
6, 7, 3,
// 底面
4, 0, 3,
3, 7, 4
};
// -------描述索引缓冲区
D3D11_BUFFER_DESC ibd;
ZeroMemory(&ibd, sizeof(ibd));
ibd.Usage = D3D11_USAGE_IMMUTABLE;
ibd.ByteWidth = sizeof indices;
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
// -------创建索引缓冲区
InitData.pSysMem = indices;
HR(m_pDevice->CreateBuffer(&ibd, &InitData, m_pIndexBuffer.GetAddressOf()));
//=======================================索引缓存的设置==============================================
设备创建缓冲区函数(和顶点缓冲区,常量缓冲区的创建是一样):CreateBuffer
参数1:缓冲区的描述
参数2:数据的来源/资源
参数3:取得缓冲区的指针
参数2中的资源,我们在前面已经分析过了,也就是把索引数组指针赋给InitData.pSysMem,再传给参数2。然后参数3用我们的成员变量m_pIndexBuffer来取得就好。这些都比较容易理解。参数1是获取缓冲区描述的指针,也就是说,我们需要对缓冲区进行描述。
缓冲区的描述:
结构原型:
typedef struct D3D11_BUFFER_DESC
{
UINT ByteWidth;
D3D11_USAGE Usage;
UINT BindFlags;
UINT CPUAccessFlags;
UINT MiscFlags;
UINT StructureByteStride;
}
D3D11_BUFFER_DESC;
1.ByteWidth:缓冲区大小
2.Usage:缓冲区的读取和写入方式,一般为D3D11_USIC_DEFAULT,这里使用D3D11_USAGE_IMMUTABLE
3.BindFlags:标识缓冲区将如何绑定到管道。
4.CPUAccessFlags:CPU访问标志,不访问CPU时,值为0
5.MiscFlags:杂项标识,未使用,则为0
6.StructureByteStride:每个元素的大小
到了这里,我们的索引缓冲区就创建成功了!
二、常量缓冲区:
前言:
一个常量缓冲区被用来向一个正在管线中执行的可编程着色器 应用程序提供常量信息。我们所说的常量,一般就是不会发生实质变化的量,那么我们就可以利用常量缓冲区进行世界矩阵,投影矩阵等变换。
//======================================常量缓冲区的设置=====================================================
// --------描述常量缓冲区
D3D11_BUFFER_DESC cbd;
ZeroMemory(&cbd, sizeof(cbd));
cbd.Usage = D3D11_USAGE_DYNAMIC;
cbd.ByteWidth = sizeof(ConstantBuffer);
cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
// --------新建常量缓冲区
HR(m_pDevice->CreateBuffer(&cbd, nullptr, m_pConstantBuffer.GetAddressOf()));
//--------- 初始化常量缓冲区
//
//返回单位矩阵
m_CBuffer.world = XMMatrixIdentity();
//因为HLSL中的矩阵按列主序,又由于world为单位阵,所以我们把view和proj进行转置
//矩阵转置
m_CBuffer.view = XMMatrixTranspose
//XMMatrixLookAtLH函数,基于左手坐标系,返回将点从世界空间转换为视图空间的视图矩阵,参1:摄像机的位置
// 参2:协调中心的位置
//参数3:相机向上的向量,表示3D坐标系中向上的坐标向量,这里表示屏幕由底向上递增的向上,这是一个规范化的坐标系
(XMMatrixLookAtLH
(
XMVectorSet(0.0f, 0.0f, -5.0f, 0.0f),
XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f),
XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f)//以世界空间的y轴作为摄像机“向上”的方向。因此(0, 1, 0)是平行于世界空间中y轴的一个单位向量
));
m_CBuffer.proj = XMMatrixTranspose(XMMatrixPerspectiveFovLH(XM_PIDIV2, AspectRatio(), 1.0f, 1000.0f));
//XMMatrixPerspectiveFovLH函数,返回透视投影矩阵,参数1:以弧度为单位的自顶向下视场角度,参数2:视宽比,参数3:距离近切飞机的距离,大于零。参数4:距离遥远的剪裁飞机,大于零
//======================================常量缓冲区的设置=====================================================
创建常量缓冲区的操作与创建索引缓冲区的操作类似,因此就不再展开。
我们来看下缓冲区的初始化。
准备工作:
1.这时候,我们就需要在HLSL头文件新增部分代码:
cbuffer
:用于声明一个常量缓冲区
matrix
:等价于 float4x4的矩阵
register(b0):
常量缓冲区位于寄存器索引为0的缓冲区
2.并改动HLSL头文件部分代码:
没错就是VertexIn结构中的变量pos变为posL,为什么要这样做呢?
在HLSL代码中你可能会遇到诸如PosW
、PosH
这样带字母后缀的变量名,那么它们有什么含义呢?这些字母表明了当前点或向量所处的空间:
字母后缀 | 含义 |
---|---|
L | 处于物体局部空间(Local Space) |
W | 处于世界空间(World Space) |
V | 处于观察空间(View Space) |
H | 处于齐次裁减空间(Homogeneous space) |
3.在C++应用层,添加对应的常量缓冲区结构体:
4.顶点着色器文件的代码改动:
因为HLSL是列主序矩阵,所以我们采用行向量左乘列主序矩阵
正式初始化:
1.因为HLSL中的矩阵按列主序(在c++这边要转置,是为了抵消HLSL那边已经转置过一次,因为转置的转置为本身嘛),又由于world为单位阵,所以我们把view和proj进行转置
矩阵的转置使用的函数是XMMatrixTranspose(),传入矩阵即可。
2.我们来看看view基于左手坐标系的XMMatrixLookAtLH函数
函数原型:
inline XMMATRIX XM_CALLCONV XMMatrixLookAtLH
(
FXMVECTOR EyePosition,
FXMVECTOR FocusPosition,
FXMVECTOR UpDirection
)
返回值:返回将点从世界空间转换为视图空间的视图矩阵
参数1:摄像机的位置
参数2:协调中心的位置
参数3:相机向上的向量,表示3D坐标系中向上的坐标向量,一般以世界空间的y轴作为摄像机“向上”的方向。因此这里的(0, 1, 0)是平行于世界空间中y轴的一个单位向量,是一个规范化的坐标系
3.再来看看proj 左手坐标系的XMMatrixPerspectiveFovLH函数
函数原型:
inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveFovLH
(
float FovAngleY,
float AspectRatio,
float NearZ,
float FarZ
)
返回值:返回透视投影矩阵
参数1:以弧度为单位的自顶向下视场角度
参数2:视宽比
参数3:距离近切飞机的距离,大于零。
参数4:距离遥远的剪裁飞机,大于零。
那么我们就完成了常量缓冲区的初始化操作了,也就完成了常量缓冲区的设置!
接下来,我们要让棱台动起来!
画面更新:
static float phi = 0.0f, theta = 0.0f;
phi += 0.0001f, theta += 0.00015f;
m_CBuffer.world = XMMatrixTranspose(XMMatrixRotationX(phi) * XMMatrixRotationY(theta));
更新常量缓冲区
XMMatrixRotationX函数:
返回值:返回旋转矩阵
参数1:围绕x轴旋转的角度,以弧度表示。当沿着旋转轴向原点看时,角度是顺时针测量的。
XMMatrixRotationY函数:与XMMatrixRotationX一样,只不过是返回y轴
// 更新常量缓冲区,让立方体转起来
D3D11_MAPPED_SUBRESOURCE mappedData;
//map函数,获取指向缓冲区中数据的指针并拒绝gpu对该缓冲区的访问,参数1:接口资源对象,参数2:缓冲区资源,参数3:枚举值,指定读写操作,参数4:填0,cpu需要等待gpu使用完毕当前缓冲区
//参数5:获取映射到缓冲区的内存
HR(m_pContext->Map(m_pConstantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
//更新//通过映射内存更新
memcpy_s(mappedData.pData, sizeof(m_CBuffer), &m_CBuffer, sizeof(m_CBuffer));
//unmap函数,让指向资源的指针无效并重新启用gpu对该资源的访问权限,参数1:接口资源对象,参数2:缓冲区资源,填0
m_pContext->Unmap(m_pConstantBuffer.Get(), 0);
1.map函数:获取指向缓冲区中数据的指针并拒绝gpu对该缓冲区的访问。
参数1:接口资源对象
参数2:缓冲区资源
参数3:枚举值,指定读写操作
参数4:填0,cpu需要等待gpu使用完毕当前缓冲区
参数5:获取映射到缓冲区的内存
2.memcpy_s函数:通过映射内存更新
3.unmap函数:让指向资源的指针无效并重新启用gpu对该资源的访问权限
参数1:接口资源对象
参数2:缓冲区资源,填0
效果:
让棱台绕x/y轴旋转
三、键盘和鼠标的创建:
鼠标的创建:
利用Get()函数获取mouse实例
然后利用SetWindow函数绑定窗口
再使用SetMode函数
设置鼠标模式
最后利用ProcessMessage函数处理鼠标信息
鼠标类的细节代码:
namespace DirectX
{
class Mouse
{
public:
Mouse() noexcept(false);
Mouse(Mouse&& moveFrom) noexcept;
Mouse& operator= (Mouse&& moveFrom) noexcept;
Mouse(Mouse const&) = delete;
Mouse& operator=(Mouse const&) = delete;
virtual ~Mouse();
//鼠标模式
enum Mode
{
MODE_ABSOLUTE = 0,// 绝对坐标模式,每次状态更新xy值为屏幕像素坐标,且鼠标可见
MODE_RELATIVE,// 相对运动模式,每次状态更新xy值为每一帧之间的像素位移量,且鼠标不可见
};
struct State
{
bool leftButton;//按下左键
bool middleButton;//按下中键,即滑轮键
bool rightButton;//按下右键
bool xButton1;//忽略
bool xButton2;//忽略
int x;//绝对/相对坐标x
int y;//绝对/相对坐标y
int scrollWheelValue;//滑轮累积值
Mode positionMode;//鼠标模式
};
//鼠标追踪类
class ButtonStateTracker
{
public:
//鼠标状态枚举
enum ButtonState
{
UP = 0, // 按钮未被按下
HELD = 1, // 按钮长按中
RELEASED = 2, // 按钮刚被放开
PRESSED = 3, // 按钮刚被按下
};
ButtonState leftButton;//左键状态
ButtonState middleButton;//滑轮//中键状态
ButtonState rightButton;//右键状态
ButtonState xButton1;//忽略
ButtonState xButton2;//忽略
#pragma prefast(suppress: 26495, "Reset() performs the initialization")
ButtonStateTracker() noexcept { Reset(); }
//更新状态
void __cdecl Update(const State& state);
//
void __cdecl Reset() noexcept;
//获取上一帧的鼠标状态
State __cdecl GetLastState() const { return lastState; }
private:
State lastState;
};
//获取每帧的鼠标运动状态
State __cdecl GetState() const;
// 清空滑轮的累计值
void __cdecl ResetScrollWheelValue();
// 设置鼠标模式
void __cdecl SetMode(Mode mode);
// 检验鼠标是否连接
bool __cdecl IsConnected() const;
// 检验鼠标是否可见
bool __cdecl IsVisible() const;
//设置鼠标是否可见
void __cdecl SetVisible(bool visible);
#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) && defined(WM_USER)
//绑定窗口
void __cdecl SetWindow(HWND window);
//处理鼠标信息
static void __cdecl ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam);
#endif
//获取mouse实例
static Mouse& __cdecl Get();
private:
class Impl;
std::unique_ptr<Impl> pImpl;
};
}
键盘的创建:
利用Get()函数获取keyboard实例
然后利用SetWindow函数绑定窗口
最后利用ProcessMessage函数处理键盘信息
键盘类的部分细节代码:
//键盘追踪类
class KeyboardStateTracker
{
public:
State released;//按键是否释放
State pressed;//按键是否按下
#pragma prefast(suppress: 26495, "Reset() performs the initialization")
KeyboardStateTracker() noexcept { Reset(); }
//更新每一帧的键盘状态
void __cdecl Update(const State& state);
void __cdecl Reset() noexcept;
//检验按键是否按下
bool __cdecl IsKeyPressed(Keys key) const { return pressed.IsKeyDown(key); }
//检验按键是否释放
bool __cdecl IsKeyReleased(Keys key) const { return released.IsKeyDown(key); }
//获取最后的键盘状态
State __cdecl GetLastState() const { return lastState; }
public:
State lastState;
};
//获取每一帧的状态
State __cdecl GetState() const;
//重置状态
void __cdecl Reset();
// 检验键盘是否连接
bool __cdecl IsConnected() const;
#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) && defined(WM_USER)
//处理键盘输入消息
static void __cdecl ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam);
#endif
//获取keyboard实例
static Keyboard& __cdecl Get();
private:
class Impl;
std::unique_ptr<Impl> pImpl;
};
//判断按键是否被按下,按下为true
bool __cdecl IsKeyDown(Keys key) const
{
if (key >= 0 && key <= 0xfe)
{
auto ptr = reinterpret_cast<const uint32_t*>(this);
unsigned int bf = 1u << (key & 0x1f);
return (ptr[(key >> 5)] & bf) != 0;
}
return false;
}
//判断按键有没有被按下,没按下为true
bool __cdecl IsKeyUp(Keys key) const
{
if (key >= 0 && key <= 0xfe)
{
auto ptr = reinterpret_cast<const uint32_t*>(this);
unsigned int bf = 1u << (key & 0x1f);
return (ptr[(key >> 5)] & bf) == 0;
}
return false;
}
在D3DAPP.h中的 初始化init函数()用智能指针初始化鼠标和键盘:
m_pMouse = std::make_unique<DirectX::Mouse>();
m_pKeyboard = std::make_unique<DirectX::Keyboard>();
对Raw Input
有兴趣的同学,可以看键鼠类的内部实现
更新画面:
键鼠要通过GetState函数和GetLastState函数获取前后状态,通过Update函数更新状态,这样就使得键鼠进行进一步的操作
因为在HLSL中转置过一次,因此world要再转置一次,其中参数的相乘表达式为变换的复合,
几何体的变换顺序通常为先缩放,后旋转,再平移
若不按照此顺序变换,几何体就产生扭曲,变形
这里的XMMatrixScaling函数是缩放函数,返回缩放矩阵,对应三个参数分别为,x,y,z的缩放比例
此处的常量缓冲区的更新与上面的一致
//XMMatrixTranspose()中参数为变换的复合,比如现在的参数为先旋转Y轴再旋转X轴
m_CBuffer.world = XMMatrixTranspose( XMMatrixRotationY(cubeTheta)* XMMatrixRotationX(cubePhi)*XMMatrixScaling(cubemid, cubemid, cubemid));
void GameApp::UpdateScene(float dt)//dt为两帧时间间隔
{
/*static float phi = 0.0f, theta = 0.0f;
phi += 0.0001f, theta += 0.00015f;
m_CBuffer.world = XMMatrixTranspose(XMMatrixRotationX(phi) * XMMatrixRotationY(theta));*/
static float cubePhi = 0.0f, cubeTheta = 0.0f,cubemid= 1.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);
//当鼠标左键长按时可进行绕Y轴或X轴的旋转
if (mouseState.leftButton == true && m_MouseTracker.leftButton == m_MouseTracker.HELD)
{
cubeTheta -= (mouseState.x - lastMouseState.x) * 0.01f;//鼠标使用像素单位
cubePhi -= (mouseState.y - lastMouseState.y) * 0.01f;//鼠标使用像素单位
}
//滑动滚轮进行放大或缩小
cubemid += (mouseState.scrollWheelValue - lastMouseState.scrollWheelValue) * 0.001f;//鼠标使用像素单位
//按W/S/A/D四个键可进行绕Y轴或X轴的旋转
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;
//按Up/Down/Left/Right四个键可进行绕Y轴或X轴的旋转
if (keyState.IsKeyDown(Keyboard::Up))
cubePhi += dt * 2;
if (keyState.IsKeyDown(Keyboard::Down))
cubePhi -= dt * 2;
if (keyState.IsKeyDown(Keyboard::Left))
cubeTheta += dt * 2;
if (keyState.IsKeyDown(Keyboard::Right))
cubeTheta -= dt * 2;
//按I/O键进行放大或缩小,I---IN,O---OUT
if (keyState.IsKeyDown(Keyboard::I))
cubemid += dt* 1;
if (keyState.IsKeyDown(Keyboard::O))
cubemid -= dt *1;
//矩阵转置
//对几何体的变换顺序通常为先缩放,后旋转,再平移
//XMMatrixTranspose()中参数为变换的复合,比如现在的参数为先旋转Y轴再旋转X轴
m_CBuffer.world = XMMatrixTranspose( XMMatrixRotationY(cubeTheta)* XMMatrixRotationX(cubePhi)*XMMatrixScaling(cubemid, cubemid, cubemid));
//XMMatrixRotationX,返回旋转矩阵,参数:围绕x轴旋转的角度,以弧度表示。当沿着旋转轴向原点看时,角度是顺时针测量的
//XMMatrixRotationY,与XMMatrixRotationX一样,只不过是返回y轴
// 更新常量缓冲区,让立方体转起来
D3D11_MAPPED_SUBRESOURCE mappedData;
//map函数,获取指向缓冲区中数据的指针并拒绝gpu对该缓冲区的访问,参数1:接口资源对象,参数2:缓冲区资源,参数3:枚举值,指定读写操作,参数4:填0,cpu需要等待gpu使用完毕当前缓冲区
//参数5:获取映射到缓冲区的内存
HR(m_pContext->Map(m_pConstantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
//更新//通过映射内存更新
memcpy_s(mappedData.pData, sizeof(m_CBuffer), &m_CBuffer, sizeof(m_CBuffer));
//unmap函数,让指向资源的指针无效并重新启用gpu对该资源的访问权限,参数1:接口资源对象,参数2:缓冲区资源,填0
m_pContext->Unmap(m_pConstantBuffer.Get(), 0);
}
这里绘制画面不再是使用draw函数,而是drawindexed函数:
// 绘制棱台
m_pContext->DrawIndexed(36,0,0);
//参数1:绘制的索引数
//参数2:绘制的索引起点
//参数3:对每个索引加上某一数值
参数1:绘制的索引数
参数2:绘制的索引起点
参数3:对每个索引加上某一数值
解释:如果我们的索引数组为{0,2,3,1,3,6},那么DrawIndexed(5,0,0)就是绘制{0,2,3,1,3}这五个顶点
如果我们的索引数组为{0,2,3,1,3,6},那么DrawIndexed(6,1,0)就是绘制{2,3,1,3,6}这几个顶点
如果我们的索引数组同样为{0,2,3,1,3,6},那么DrawIndexed(6,0,1)就是绘制{1,3,4,2,4,7}这几个顶点,即每个相应的索引加上1。
消息回调函数(处理键盘鼠标信息):
我们需要对鼠标输入的消息进行处理,因为利用回调函数可以处理鼠标在窗口操作的消息
回调函数:
参数1:窗口句柄
参数2:接收到的窗口消息
参数3:wParam为按下按键的虚拟键码,
参数4:lParam存储按键相关状态信息,当鼠标信息发出时,lParam存储鼠标的坐标,高字节HIWORD代表y坐标,低字节 LOWORD代表x坐标
细节部分看代码就很容易理解了,嘿嘿~
LRESULT D3DApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)//wParam为按下按键的虚拟键码,lParam存储按键相关状态信息,当鼠标信息发出时,lParam存储鼠标的坐标,高字节HIWORD代表y坐标,低字节 LOWORD代表x坐标
{
//当窗口被激活或失去激活状态
case WM_ACTIVATE:
if (LOWORD(wParam) == WA_INACTIVE)// WA_INACTIVE:取消窗口激活
{
m_AppPaused = true;
m_Timer.Stop();//暂停,不再累加时间
}
else
{
m_AppPaused = false;
m_Timer.Start();//开始,并开始累加时间
}
return 0;
// 改变窗口的大小
case WM_SIZE:
m_ClientWidth = LOWORD(lParam);//鼠标的x坐标
m_ClientHeight = HIWORD(lParam);//鼠标的y坐标
if (m_pDevice)
{
if (wParam == SIZE_MINIMIZED)//鼠标点到最小化
{
m_AppPaused = true;
m_Minimized = true;
m_Maximized = false;
}
else if (wParam == SIZE_MAXIMIZED)//鼠标点到最大化
{
m_AppPaused = false;
m_Minimized = false;
m_Maximized = true;
OnResize();//调整大小
}
else if (wParam == SIZE_RESTORED)//鼠标点到还原(最大化最小化窗口的那个框框)
{
if (m_Minimized)//如果原来的窗口状态是最小化
{
m_AppPaused = false;
m_Minimized = false;
OnResize();//调整大小
}
else if (m_Maximized)//如果原来的窗口状态是最大化
{
m_AppPaused = false;
m_Maximized = false;
OnResize();//调整大小
}
else if (m_Resizing)
{
}
else
{
OnResize();//调整大小
}
}
}
return 0;
//窗口进入 移动/改变大小 模式循环
case WM_ENTERSIZEMOVE:
m_AppPaused = true;
m_Resizing = true;
m_Timer.Stop();//暂停,不再累加时间
return 0;
//窗口退出 移动/改变大小 模式循环
case WM_EXITSIZEMOVE:
m_AppPaused = false;
m_Resizing = false;
m_Timer.Start();//开始,并开始累加时间
OnResize();//调整大小
return 0;
//窗口销毁
case WM_DESTROY:
PostQuitMessage(0);//退出并销毁当前窗口
return 0;
//菜单被激活且被按下某个键
case WM_MENUCHAR:
return MAKELRESULT(0, MNC_CLOSE);
//窗口改变 大小或位置
case WM_GETMINMAXINFO:
((MINMAXINFO*)lParam)->ptMinTrackSize.x = 200;
((MINMAXINFO*)lParam)->ptMinTrackSize.y = 200;
return 0;
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:
//按下alt+其他按键
case WM_SYSKEYDOWN:
//释放非系统键
case WM_KEYUP:
//释放alt+其他按键
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);
}
效果:
使用鼠标左键及滑轮 或 键盘的A/W/S/D I/U键及Up Down Left Right键对棱台进行缩放和绕X/Y轴的旋转操作
最后:
本文为学习博主X_Jun的文章后的感悟。原文章为:(2条消息) DirectX11 入门篇_X_Jun96的博客-CSDN博客
专栏的03到06文章。里面也有相应的代码哦!