Hazel游戏引擎(088)Tranform组件UI

文章描述了如何在Unity项目中使用ImGui库来创建一个用户界面,展示和控制Entity的Transform组件(包括位置、旋转和缩放)。代码展示了如何构造Transform矩阵以及创建带有颜色的可复位按钮来调整这些属性。

文中若有代码、术语等错误,欢迎指正

前言

  • 此节目的

    点击实体,在属性面板显示实体的Transform组件的位置、缩放、旋转属性。

    对UI有要求

    1. 文字需在左边,属性按钮在右边
    2. x不是label,而是按钮且带有颜色,且点击按钮可以复原值。
  • 如何实现

    照样087那样,点击实体,检测是否有Transform组件,再将值传入ImGUi上绘制

代码

  • Components.h

    struct TransformComponent { // 不用继承Component
        glm::vec3 Translation = { 0.0f, 0.0f, 0.0f };
        glm::vec3 Rotation = { 0.0f, 0.0f,0.0f };
        glm::vec3 Scale = { 1.0f, 1.0f, 1.0f };
        TransformComponent() = default;
        TransformComponent(const TransformComponent&) = default; // 复制构造函数
        TransformComponent(const glm::vec3& translation)          // 转换构造函数
            : Translation(translation) {}
        glm::mat4 GetTransform()const {
            glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), Rotation.x, { 1,0,0 })
                * glm::rotate(glm::mat4(1.0f), Rotation.y, { 0, 1, 0 })
                * glm::rotate(glm::mat4(1.0f), Rotation.z, { 0, 0, 1 });
    
            return glm::translate(glm::mat4(1.0f), Translation)
                * rotation
                * glm::scale(glm::mat4(1.0f), Scale);
        }
    };
    
  • SceneHierarchyPanel.cpp

    static void DrawVec3Control(const std::string& label, glm::vec3& values, float resetValue = 0.0f, float columnWidth = 100.0f) {
        // ImGUi push多少 要pop多少,不然会报错
        ImGui::PushID(label.c_str()); // 每一行用label做ID,3行ID不同互不干扰
    
        // 设置一行两列
        ImGui::Columns(2);
        // 第一列
        ImGui::SetColumnWidth(0, columnWidth);// 设置第1列宽100
        ImGui::Text(label.c_str());
        ImGui::NextColumn();		
    
        // 第二列
        // 放入3个item的宽
        ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{ 0,0 });
    
        float lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;// 设置行高
        ImVec2 buttonSize = { lineHeight + 3.0f, lineHeight };// 按钮大小
    
        ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
        ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.9f, 0.2f, 0.2f, 1.0f });
        ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
        if (ImGui::Button("X", buttonSize) ){
            values.x = resetValue;
        }
        ImGui::PopStyleColor(3);
    
        // 因为DragFloat button会换行,所以设置SameLine将不换行
        ImGui::SameLine();
        // ##X将分配一个id,且##x不会在UI界面显示出来。
        // #X 将显示在文本框的右边
        // X  将与上面的BUtton同名 同id,操作的话会报错
        ImGui::DragFloat("##X", &values.x, 0.1f, 0.0f, 0.0f, "%.2f");
        ImGui::PopItemWidth();
    
        ImGui::SameLine();
        ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
        ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.3f, 0.8f, 0.3f, 1.0f });
        ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
        if (ImGui::Button("Y", buttonSize)) {
            values.y = resetValue;
        }
        ImGui::PopStyleColor(3);
    
        ImGui::SameLine();
        ImGui::DragFloat("##Y", &values.y, 0.1f, 0.0f, 0.0f, "%.2f");// 0.1速度,0 - 0 最小最大无限制
        ImGui::PopItemWidth();
    
        ImGui::SameLine();
        ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.1f, 0.25f, 0.8f, 1.0f });
        ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.2f, 0.35f, 0.9f, 1.0f });
        ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.1f, 0.25f, 0.8f, 1.0f });
        if (ImGui::Button("Z", buttonSize)) {
            values.z = resetValue;
        }
        ImGui::PopStyleColor(3);
    
        ImGui::SameLine();
        ImGui::DragFloat("##Z", &values.z, 0.1f, 0.0f, 0.0f, "%.2f");
        ImGui::PopItemWidth();
    
        ImGui::PopStyleVar();
    
        // 恢复成一行一列
        ImGui::Columns(1);
    
        ImGui::PopID();
    }
    
    // 实体transform组件
    void SceneHierarchyPanel::DrawComponents(Entity entity)
    {
        ...
        // 实体transform组件
        if (entity.HasComponent<TransformComponent>()) {
            if (ImGui::TreeNodeEx((void*)typeid(TransformComponent).hash_code(), ImGuiTreeNodeFlags_DefaultOpen, "Transform")) {
                auto& tfc = entity.GetComponent<TransformComponent>();
                DrawVec3Control("Translation", tfc.Translation);
                glm::vec3 rotation = glm::degrees(tfc.Rotation);
                DrawVec3Control("Rotation", rotation); // 界面显示角度
                tfc.Rotation = glm::radians(rotation);
                DrawVec3Control("Scale", tfc.Scale, 1.0f);
    
                // 展开树节点
                ImGui::TreePop();
            }
        }
    }
    

关键代码

  • ImGui

    • 水平放置

      // 因为DragFloat button会换行,所以设置SameLine将不换行
      ImGui::SameLine();
      
    • ##X

      // ##X将分配一个id,且##x不会在UI界面显示出来。
      // #X 将显示在文本框的右边
      // X  将与上面的BUtton同名 同id,操作的话会报错
      ImGui::DragFloat("##X", &values.x, 0.1f, 0.0f, 0.0f, "%.2f");
      ImGui::PopItemWidth();
      
    • 颜色按钮

      ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
      ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.9f, 0.2f, 0.2f, 1.0f });
      ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
      if (ImGui::Button("X", buttonSize) ){
          values.x = resetValue;
      }
      ImGui::PopStyleColor(3);
      
  • 变换矩阵拆分3个vec3如何组合成Transform变换矩阵

    glm::vec3 Translation = { 0.0f, 0.0f, 0.0f };
    glm::vec3 Rotation = { 0.0f, 0.0f,0.0f };
    glm::vec3 Scale = { 1.0f, 1.0f, 1.0f };
    glm::mat4 GetTransform()const {
        glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), Rotation.x, { 1,0,0 })
            * glm::rotate(glm::mat4(1.0f), Rotation.y, { 0, 1, 0 })
            * glm::rotate(glm::mat4(1.0f), Rotation.z, { 0, 0, 1 });
    
        return glm::translate(glm::mat4(1.0f), Translation)
            * rotation
            * glm::scale(glm::mat4(1.0f), Scale);
    }
    

效果

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

刘建杰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值