Dx11--用dx11绘制棱台,并用键盘和鼠标进行旋转缩放操作

2023-11-11

目录

一、索引缓冲区:

前言:

创建缓冲区:

缓冲区的描述:

二、常量缓冲区:

前言:

准备工作:

正式初始化:

 画面更新及其效果:

画面更新:

效果:

三、键盘和鼠标的创建:

1.鼠标的创建:

2.键盘的创建:

 3.更新画面:

4.消息回调函数(处理键盘鼠标信息):

效果:


一、索引缓冲区:

前言:

当我们要绘制如下图所示的立体图形棱台时,如果我们用顶点缓冲区来绘制的话,那我们需要绘制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代码中你可能会遇到诸如PosWPosH这样带字母后缀的变量名,那么它们有什么含义呢?这些字母表明了当前点或向量所处的空间:

字母后缀 含义
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有兴趣的同学,可以看键鼠类的内部实现

 Raw Input内部实现-----msdn文档

 更新画面:

键鼠要通过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文章。里面也有相应的代码哦!


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Dx11--用dx11绘制棱台,并用键盘和鼠标进行旋转缩放操作 的相关文章

  • 3D 图形批处理

    很多网站 文章都说 批量 批 批 有人可以解释一下着色器中的 批处理 代表什么吗 即 是否 改变纹理 更改任意着色器变量 意味着某些东西不能 批处理 最简单的总结方法就是尝试尽可能少地调用 API 来绘制您需要绘制的内容 使用顶点数组或 V
  • 自定义波特率,redux

    我遇到的问题详述如下自定义波特率 https stackoverflow com questions 7714060 custom baud rate SetCommState 波特率 921600 失败 但波特率 115200 成功 尽管
  • 如何使用来自 Microsoft-Windows-NDIS-PacketCapture 提供程序的实时 ETW 事件?

    更大的问题是一般如何使用实时 ETW 网络堆栈事件 但我特别感兴趣Microsoft Windows NDIS PacketCapture 提供程序 所有其他网络堆栈提供程序都部分工作 但 NDIS PacketCapture NDIS P
  • Qt 支持 Windows 蓝牙 API 吗?

    谁能告诉我 Qt 是否支持 Windows 蓝牙 API 如果是这样 您能否分享一些有关如何使用它的信息 自上次答复以来 这个问题的答案发生了一些变化 Qt 5 2 版为 Linux BlueZ 和 BlackBerry 设备实现了蓝牙 A
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • 在哪里可以找到 Windows 7 UX 指南中推荐的图标/动画?

    Windows 7 UX 指南有很好的插图和图标示例 但我在 SDK 中确实找不到它们 他们藏在某个地方 还是找不到 如果您谈论的是常见的 UI 图标 那么您应该以编程方式获取它们 例如 您可以使用 var errIcon HICON be
  • 非托管 C++ 中的默认打印机

    我正在寻找一种使用非托管 C 查找 Windows 默认打印机名称的方法 找到了大量 NET 示例 但非托管没有成功 谢谢 以下是如何获取当前打印机和默认打印机的列表 如果有一台设置为默认打印机 另请注意 如果用户没有打印机或未将打印机名称
  • Tensorflow 导入错误:没有名为“tensorflow”的模块

    我在 Windows Python 3 5 Anaconda 环境中安装了 TensorFlow 验证成功 有警告 tensorflow C gt python Python 3 5 3 英特尔公司 默认 2017 年 4 月 27 日 1
  • 在 Win7 登录屏幕上运行应用程序[重复]

    这个问题在这里已经有答案了 我想通过服务在 Windows 7 的登录屏幕上运行应用程序 我对此进行了长期研究并尝试了不同的方法 但不幸的是到目前为止还没有完全成功 我设法在当前登录用户的锁定屏幕上运行该应用程序 起初我认为这就是我基本上试
  • DirectX Vertex 中的 THE 是什么

    我知道 RHW 是倒数同质 W 但有人可以解释一下它的使用方法和作用吗 gamedev论坛上的说明post http www gamedev net topic 440283 reciprocal of homogeneous w and
  • 用于创建计划任务的 VBScript

    我正在尝试创建一个 VBScript 它创建一个批处理文件 然后创建一个计划任务来运行该批处理文件 到目前为止 我尝试过的所有操作都创建了批处理文件 但没有创建计划任务 并且我没有收到任何错误 这是我到目前为止所拥有的 Option Exp
  • Windows 中的蓝牙 AVRCP 命令会触发哪些事件

    可以这么说 只是在做一些高级侦察 对于我的潘多拉客户 Elpis http elpis adamhaile net 我支持全局媒体键 键盘上的 MediaPlayPause MediaNext 等 并且我希望能够支持AVRCP http e
  • Windows 10 上的 LibPNG 构建问题

    我试图在 Windows 10 上构建 libpng 以获取 win32 二进制文件 但我认为有一个与 awk 解析带有 CRLF 行结尾的文件相关的问题 我尝试使用 dos2unix 命令转换文件 但没有成功 结果相同 在 make 命令
  • 如何迭代所有注册表项?

    我正在尝试迭代所有注册表项以查找 包含 并删除 jre1 5 0 14 值 有办法做到吗 下面的代码只是在特定键下找到jre1 5 0 14 我确实想迭代所有的键 顺便说一句 if 子句获取是否等于 jre1 5 0 14 但如果它包含 j
  • 使用管理员权限打开cmd(Windows 10)

    我有自己的 python 脚本来管理我的计算机上的 IP 地址 它主要在命令行 Windows 10 中执行netsh命令 您必须具有管理员权限 这是我自己的计算机 我是管理员 运行脚本时我已经使用管理员类型的用户 Adrian 登录 我无
  • 为什么 Git Bash 无法运行我的可执行文件?

    I am on git for windows https github com git for windows 吉特 巴什 我无法在命令行上运行可执行文件 Pedr Abc 07 MINGW64 c dev ls sqlite3 exe
  • npm package.json bin 无法在 Windows 上运行

    我正在尝试通过 package json 启动我的 cli 工具bin财产 我有以下内容 name mycli bin bin mycli 当我在包路径中打开 cmd 并输入 mycli 时 它表示该命令无法识别 我应该运行 npm 命令吗
  • Windows:更改与文件类型关联的应用程序的名称/图标

    我想将 Windows 中的文件类型与特定应用程序相关联 但我需要这样做 以便当用户打开 打开方式 菜单时 列表中应用程序的名称和图标是针对该文件类型自定义的 即 不仅仅是可执行文件的名称和图标 这是因为该二进制文件是一个通用二进制文件 可
  • Windows 上最快的屏幕捕获方法

    我想为Windows平台编写一个截屏程序 但不确定如何捕获屏幕 我知道的唯一方法是使用 GDI 但我很好奇是否还有其他方法可以实现此目的 如果有的话 哪种方法产生的开销最小 速度是首要任务 截屏程序将用于录制游戏镜头 不过 如果这确实缩小了
  • 如果我使用客户端计算机上未安装的字体,会发生什么情况?

    有人可以告诉我 如果我在 WinForms 应用程序中使用目标计算机上不可用的字体 会发生什么情况 它是否使用同一系列的字体 只是 Sans Serif 还是其他字体 您的应用程序将回退到 Segoe UI Tahoma 然后是 MS Sa

随机推荐

  • 子序列(组合数学)

    子序列 题目描述 给出一个长度为 n n n的序列 你需要计算出所有长度为 k k k的子序列中 除最大最小数之外所有数的乘积相乘的结果 输入描述 第一行一个整数
  • maven学习笔记(五)maven全局配置文件settings.xml详解

    目录 setting文件简介 settings xml的作用 settings xml文件位置 配置的优先级 settings xml元素详解 顶级元素概览 LocalRepository InteractiveMode UsePlugin
  • Shiro权限框架-Springboot集成Shiro(5)

    1 技术栈 主框架 springboot 响应层 springMVC 持久层 mybatis 事务控制 jta 前端技术 easyui 2 数据库设计 1 数据库图解 sh user 用户表 一个用户可以有多个角色 sh role 角色表
  • python arima predict end无效_样本外预测的ARMA.predict不适用于浮点?

    在我开发了用于样本分析的小ARMAX预测模型之后 我想预测一些样本外的数据 我用于预测计算的时间序列从2013 01 01开始 到2013 12 31结束 以下是我正在处理的数据 hr np loadtxt Data 2013 17 txt
  • 《深入浅出数据分析》R语言实用教程

    深入浅出数据分析 R语言实用教程 1年前的R语言笔记 跟着 深浅 学习 当时用的版本是R i386 4 0 3 因为先学了MySQL再学的R 所以会夹带一些在借助MySQL来理解 1 基本处理 先加载程序包 程序包 加载程序包 加载xlsx
  • (二)、edtFTPj FileTransferClient

    edtFTPj的FileTransferClient类简单易用 而且下载的组件包中文档丰富 参考使用 完全能满足自己需要 下载地址为 http www enterprisedt com index html 废话不多说 上代码 Java代码
  • 监督学习,无监督学习,半监督学习,主动学习的概念

    1 监督学习 supervised learning 训练数据既有特征 feature 又有标签 label 通过训练 让机器可以自己找到特征和标签之间的联系 在面对只有特征没有标签的数据时 可以判断出标签 即生成合适的函数将输入映射到输出
  • 高斯噪声与高斯滤波

    噪声 噪声表现形式 噪声在图像上常表现为一引起较强视觉效果的孤立像素点或像素块 一般 噪声信号与要研究的对象不相关 它以无用的信息形式出现 扰乱图像的可观测信息 通俗的说就是噪声让图像不清楚 噪声对数字图像的影响 对于数字图像信号 噪声表为
  • 深度优先查找和广度优先查找

    深度优先查找和广度优先查找 在人工智能和运筹学的领域中求解与图有关的许多应用中 这两个算法被 证明是非常有用的 并且 如需高效地研究图的基本性质 例如图的连通性以及图是否存 在环 这些算法也是必不可少的 深度优先查找 深度优先查找可以从任意
  • python之cv2与图像的载入、显示和保存

    本文是OpenCV 2 Computer Vision Application Programming Cookbook读书笔记的第一篇 在笔记中将以Python语言改写每章的代码 PythonOpenCV的配置这里就不介绍了 注意 现在O
  • shell-if语句详解

    if 条件 then Command else Command fi 别忘了这个结尾 If语句忘了结尾fi test sh line 14 syntax error unexpected end of fi if 的三种条件表达式 if c
  • navigator.geolocation.getCurrentPosition在谷歌浏览器不执行的问题

    在React 中使用navigator geolocation getCurrentPosition去获取定位信息时 获取地理位置信息 navigator geolocation getCurrentPosition position gt
  • 初识SQL workbench

    一 workbench 下载地址 https dev mysql com downloads workbench 二 环境变量配置 双击安装包 点击 Next 进行安装 重要提醒 请截图保留安装界面中 见下图 红色框起来的地址 图1 记住安
  • 3打包生成dist文件夹并发布到服务器

    打包生成dist文件夹并发布到服务器 打包生成dist文件夹 npm run build 发布1 使用静态服务器工具包 安装serve npm install g serve serve dist 访问 http localhost 500
  • mac下搭建编译chromium的开发环境

    本篇为 mac 下搭建编译chromium的方法 windows篇 windows下搭建编译chromium的开发环境 二七 CSDN博客 linux篇 linux 搭建和编译 chromium 环境 二七 CSDN博客 系统环境 mac
  • 如何实现自定义MVC框架(最终版本)

    目录 一 将MVC框架源码导成jar包 1 1优化的思路 1 2具体步骤 二 创建需要的工具包 分析思路 具体的代码 三 总结 前言 我们通过框架的形式实现一个具有增删改查的网页 一 将MVC框架源码导成jar包 1 1优化的思路 相比我们
  • Selenium自动化测试简介

    IT赶路人专注分享跟IT相关的各种知识 希望我们一起学习 共同成长 Selenium自动化测试 很早就想跟大家分享 在15年开始 我们的团队就在使用这个工具 最初 我们使用的语言是Java和SQL的结合 随后 随着最近几年Python语言的
  • Leetcode 219. Contains Duplicate II (hashmap 和 sliding window)

    Contains Duplicate II Easy Given an integer array nums and an integer k return true if there are two distinct indices i
  • ElasticSearch 绑定IP地址

    https blog csdn net yelllowcong article details 78740237
  • Dx11--用dx11绘制棱台,并用键盘和鼠标进行旋转缩放操作

    目录 一 索引缓冲区 前言 创建缓冲区 缓冲区的描述 二 常量缓冲区 前言 准备工作 正式初始化 画面更新及其效果 画面更新 效果 三 键盘和鼠标的创建 1 鼠标的创建 2 键盘的创建 3 更新画面 4 消息回调函数 处理键盘鼠标信息 效果