DX11鼠标拾取的实现和鼠标操作放置,销毁方块

文章介绍了如何在3D场景中实现鼠标拾取物体,通过获取鼠标输入,生成射线并进行射线检测来判断是否与物体相交。同时,详细阐述了鼠标左键点击生成方块以及右键点击销毁方块的功能,涉及模型创建、材质设置及绘制过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.鼠标拾取的实现

首先我们需要获取鼠标输入,并且要能够生成射线,使用基于射线检测的方法来实现鼠标拾取,注:鼠标拾取代码写在GameApp::UpdateScene函数中

1)第一步:获取鼠标输入和生成射线

 //拾取检测并生成物体
    //获取键鼠输入
    ImGuiIO& io = ImGui::GetIO();
    //获取鼠标在屏幕上位置,并限制范围
    ImVec2 mousePos = ImGui::GetMousePos();
    mousePos.x = std::clamp(mousePos.x, 0.0f, m_ClientWidth - 1.0f);
    mousePos.y = std::clamp(mousePos.y, 0.0f, m_ClientHeight - 1.0f);
    //生成射线
    Ray mouseRay = Ray::ScreenToRay(*m_pCamera, mousePos.x, mousePos.y);

2)第二步:进行射线检测

    bool isHit = false;//记录射线是否与物体相交
    std::string pickedObjStr = "None";
    if (mouseRay.Hit(m_Sphere.GetBoundingOrientedBox()))
    {
        pickedObjStr = "Sphere";
        isHit = true;
    }
    else if (mouseRay.Hit(m_Ground.GetBoundingOrientedBox()))
    {
        pickedObjStr = "Ground";
        isHit = true;
    }
    else if (mouseRay.Hit(m_Cylinder.GetBoundingOrientedBox()))
    {
        pickedObjStr = "Cylinder";
        isHit = true;
    }

接着再imgui里加入这样一条代码显示当前拾取物体

ImGui::Text("Current Object: %s", pickedObjStr.c_str());

下面是射线类(Ray)的定义,这里我们用到了ScreenToRay方法来将鼠标的屏幕坐标转换为一条射线,并在射线检测时使用Hit方法判断射线是否与物体的包围盒相交

struct Ray
{
	Ray();
	Ray(const DirectX::XMFLOAT3& origin, const DirectX::XMFLOAT3& direction);

	static Ray ScreenToRay(const Camera& camera, float screenX, float screenY);

	bool Hit(const DirectX::BoundingBox& box, float* pOutDist = nullptr, float maxDist = FLT_MAX);
	bool Hit(const DirectX::BoundingOrientedBox& box, float* pOutDist = nullptr, float maxDist = FLT_MAX);
	bool Hit(const DirectX::BoundingSphere& sphere, float* pOutDist = nullptr, float maxDist = FLT_MAX);
	bool XM_CALLCONV Hit(DirectX::FXMVECTOR V0, DirectX::FXMVECTOR V1, DirectX::FXMVECTOR V2, float* pOutDist = nullptr, float maxDist = FLT_MAX);

	DirectX::XMFLOAT3 origin;		// 射线原点
	DirectX::XMFLOAT3 direction;	// 单位方向向量
};

2.鼠标操作放置方块

再在GameApp::UpdateScene中添加按下鼠标左键实现在摄像机前生成方块功能

 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
    {
        // 点击鼠标左键生成立方体
        XMFLOAT3 putPos = m_pCamera->GetPosition();
        XMFLOAT3 putDir = m_pCamera->GetLookAxis();
        Model* pModel = m_ModelManager.CreateFromGeometry("Cube", Geometry::CreateBox(),false);
        pModel->SetDebugObjectName("Cube");
        m_TextureManager.CreateFromFile("..\\Texture\\stone.dds");
        pModel->materials[0].Set<std::string>("$Diffuse", "..\\Texture\\stone.dds");
        pModel->materials[0].Set<XMFLOAT4>("$AmbientColor", XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f));
        pModel->materials[0].Set<XMFLOAT4>("$DiffuseColor", XMFLOAT4(0.6f, 0.6f, 0.6f, 1.0f));
        pModel->materials[0].Set<XMFLOAT4>("$SpecularColor", XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f));
        pModel->materials[0].Set<float>("$SpecularPower", 16.0f);
        pModel->materials[0].Set<XMFLOAT4>("$ReflectColor", XMFLOAT4());     
        m_Cube[i].SetModel(pModel);
        m_Cube[i].GetTransform().SetPosition(putDir.x * 6.0f + putPos.x, putDir.y * 6.0f + putPos.y, putDir.z * 6.0f + putPos.z);
        i++;
        if (i >= 100)//判断是否超出最大值
            i = 0;
    }

这里我设置i为全局变量,将立方体的最大生成数设为100个

还需要在GameApp::DrawScene函数中用Draw方法绘制生成的立方体

 for (int j = 0;j < i;j++)
    {
        m_Cube[j].Draw(m_pd3dImmediateContext.Get(), m_BasicEffect);
    }

现在就可以补充鼠标拾取生成的方块的代码了

for (int m = 0;m < i;m++)
    {
        if (mouseRay.Hit(m_Cube[m].GetBoundingOrientedBox()))
        {
            pickedObjStr = "Cube";
            isHit = true;
        }
    }

3.鼠标操作销毁方块

这里我采取的方式是通过修改m_Cube数组使得在调用GameApp::DrawScene函数时,函数内部的Draw函数不会绘制销毁的方块。

在GameApp::UpdateScene中加上按下鼠标右键销毁方块功能

if (ImGui::IsMouseClicked(ImGuiMouseButton_Right))
    {
        for (int k = 0;k < i;k++)
        {
            if (mouseRay.Hit(m_Cube[k].GetBoundingOrientedBox())&& k!=i )
            {
                m_Cube[k] = m_Cube[k + 1];//修改m_Cube数组
                i--;
            }
        }
    }

4.效果展示

1)鼠标拾取:
在这里插入图片描述

2)方块生成与销毁:

在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hunnybub

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值