B-5 VulkanSceneGraph(VSG)+imgui和动态调整

B-5 2024/6/12

VulkanSceneGraph(VSG)+imgui和动态调整

  • 用imgui和vulkan实现一些简单的功能
  • 如何在渲染循环里动态的去修改物体的状态和管线的状态
  • 可以用动态数组等方式去修改,vsgexamples里也有例子,如下两个,尤其是第一个例子也提供了imgui的界面

vsgdynamicstate

vsgdynamicvertex

  • 在第二个例子里,实现了平移茶壶,而我借用这个例子实现了颜色的修改,关键代码如下:
 void apply(vsg::BindVertexBuffers& bvd)
    {
        if (bvd.arrays.empty()) return;
        bvd.arrays[2]->data->accept(*this);
        bufferInfoSet.insert(bvd.arrays[2]);
    }
std::vector<vsg::ref_ptr<vsg::vec4Value>> getColorList()
{
        std::vector<vsg::ref_ptr<vsg::vec4Value>> colorList(colorSet.size());

        auto color_itr = colorList.begin();
        for (auto& color : colorSet)
        {
            (*color_itr++) = const_cast<vsg::vec4Value*>(color);
        }

        return colorList;
}
std::set<vsg::vec4Value*> colorSet;
std::set<vsg::vec3Array*> verticesSet;
std::set<vsg::ref_ptr<vsg::BufferInfo>> bufferInfoSet;
  • 这段代码在class FindVertexData : public vsg::Visitor里面
  • 把0换成了2,因为0是位置,1是法向,2是颜色。(可能是我没有绑定texture的缘故,所以2变成了颜色)
  • 下面是在渲染循环里做的修改
    while (viewer->advanceToNextFrame())
    {

        if (gui->selectID == 666) {

            for (auto& color : colorList)
            {
                color->value() = vsg::vec4{ 0.3, 0.0, 0.9, 1.0 };
                color->dirty();
            }
        }else for(auto& color : colorList)
        {

            color->value() = vsg::vec4{ 0.3, 0.8, 0.3, 1.0 };

            color->dirty();
        }

        viewer->handleEvents();

        viewer->update();

        viewer->recordAndSubmit();

        viewer->present();
    }
  • 如何修改管线的状态呢,就要用到第一个例子了。但是第一个例子只提供了修改线宽的接口
  • 想要实现修改其他渲染模式,我进行了尝试没有成功
  • 因为在调用vulkan底层函数的时候,找不到调用的那个函数,只能找到vkCmdSetLineWidth,其他的在vulkan_core.h里的函数却找不到,可能是要修改Extensions.h和Extensions.cpp文件,添加改函数,然后重新编译vsg。有点麻烦,大家可以去尝试尝试。

gif

  • 下面是实现imgui的代码
  • 外面用了一个Params结构体来放置MyGui的变量。这是因为,MyGui是静态类,所以所有的变量都是静态变量不可改,所以放外面
  • 或者在前面加mutable关键字也可以,就像这样。这样子就可以把静态类里面的成员变量变成可修改的
private: mutable bool stepoutput;
#include <vsg/all.h>
#include <vsgImGui/RenderImGui.h>
#include <vsgImGui/SendEventsToImGui.h>
#include <vsgImGui/imgui.h>
struct Params : public vsg::Inherit<vsg::Object, Params>
{
    bool showGui = true; // you can toggle this with your own EventHandler and key
    bool showDemoWindow = false;
    bool showSecondWindow = false;
    bool showImPlotDemoWindow = false;
    bool showLogoWindow = true;
    bool showImagesWindow = false;
    float clearColor[3]{0.2f, 0.2f, 0.4f}; // Unfortunately, this doesn't change dynamically in vsg
    uint32_t counter = 0;
    float dist = 0.f;
};

class MyGui : public vsg::Inherit<vsg::Command, MyGui>
{
public:
    vsg::ref_ptr<vsgImGui::Texture> texture;
    vsg::ref_ptr<Params> params;

    MyGui(vsg::ref_ptr<Params> in_params, vsg::ref_ptr<vsg::Options> options = {}) :
        params(in_params)
    {
        auto texData = vsg::read_cast<vsg::Data>("textures/VSGlogo.png", options);
        texture = vsgImGui::Texture::create_if(texData, texData);
    }

    // we need to compile textures before we can use them for rendering
    void compile(vsg::Context& context) override
    {
        if (texture) texture->compile(context);
    }

    // Example here taken from the Dear imgui comments (mostly)
    void record(vsg::CommandBuffer& cb) const override
    {
        // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
        if (params->showGui)
        {
            ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.

            ImGui::Text("Some useful message here.");                // Display some text (you can use format strings too)
            ImGui::Checkbox("Demo Window", &params->showDemoWindow); // Edit bools storing our window open/close state
            ImGui::Checkbox("Another Window", &params->showSecondWindow);
            ImGui::Checkbox("ImPlot Demo Window", &params->showImPlotDemoWindow);
            if (texture)
            {
                ImGui::Checkbox("Images Window", &params->showImagesWindow);
            }

            ImGui::SliderFloat("float", &params->dist, 0.0f, 1.0f);        // Edit 1 float using a slider from 0.0f to 1.0f
            ImGui::ColorEdit3("clear color", (float*)&params->clearColor); // Edit 3 floats representing a color

            if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
                params->counter++;

            ImGui::SameLine();
            ImGui::Text("counter = %d", params->counter);

            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
            ImGui::End();
        }

        // 3. Show another simple window.
        if (params->showSecondWindow)
        {
            ImGui::Begin("Another Window", &params->showSecondWindow); // Pass a pointer to our bool variable (the window will have a close button that will clear the bool when clicked)
            ImGui::Text("Hello from another window!");
            if (ImGui::Button("Close Me"))
                params->showSecondWindow = false;
            ImGui::End();
        }

        if (params->showDemoWindow)
        {
            ImGui::ShowDemoWindow(&params->showDemoWindow);
        }

        if (params->showImPlotDemoWindow)
        {
            ImPlot::ShowDemoWindow(&params->showImPlotDemoWindow);
        }

        // UV for a square in the logo texture
        if (texture)
        {
            ImVec2 squareUV(static_cast<float>(texture->height) / texture->width, 1.0f);

            if (params->showLogoWindow)
            {
                // Copied from imgui_demo.cpp simple overlay
                ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
                const float PAD = 10.0f;
                const ImGuiViewport* viewport = ImGui::GetMainViewport();
                ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
                ImVec2 work_size = viewport->WorkSize;
                ImVec2 window_pos, window_pos_pivot;
                window_pos.x = work_pos.x + PAD;
                window_pos.y = work_pos.y + work_size.y - PAD;
                window_pos_pivot.x = 0.0f;
                window_pos_pivot.y = 1.0f;
                ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
                window_flags |= ImGuiWindowFlags_NoMove;
                ImGui::SetNextWindowBgAlpha(0.0f); // Transparent background
                ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
                ImGui::Begin("vsgCS UI", nullptr, window_flags);

                // Display a square from the VSG logo
                const float size = 128.0f;
                ImGui::Image(texture->id(cb.deviceID), ImVec2(size, size), ImVec2(0.0f, 0.0f), squareUV);

                ImGui::End();
                ImGui::PopStyleVar();
            }

            if (params->showImagesWindow)
            {
                ImGui::Begin("Image Window", &params->showImagesWindow);
                ImGui::Text("An texture:");
                // The logo texture is big, show it at half size

                ImGui::Image(texture->id(cb.deviceID), ImVec2(texture->width / 2.0f, texture->height / 2.0f));

                // We could make another component class for ImageButton, but we will take a short cut
                // and reuse the descriptor set from our existing texture.
                //
                // Make a small square button
                if (ImGui::ImageButton("Button", texture->id(cb.deviceID),
                                       ImVec2(32.0f, 32.0f),
                                       ImVec2(0.0f, 0.0f),
                                       squareUV))
                    params->counter++;

                ImGui::SameLine();
                ImGui::Text("counter = %d", params->counter);
                ImGui::End();
            }
        }
    }
};

int main(int argc, char** argv)
{
    auto options = vsg::Options::create();
    options->sharedObjects = vsg::SharedObjects::create();
    options->fileCache = vsg::getEnv("VSG_FILE_CACHE");
    options->paths = vsg::getEnvPaths("VSG_FILE_PATH");
#ifdef vsgXchange_all
    // add vsgXchange's support for reading and writing 3rd party file formats
    options->add(vsgXchange::all::create());
#endif

    auto windowTraits = vsg::WindowTraits::create();
    windowTraits->windowTitle = "vsgimgui";

    // set up defaults and read command line arguments to override them
    vsg::CommandLine arguments(&argc, argv);
    arguments.read(options);

    auto event_read_filename = arguments.value(std::string(""), "-i");
    auto event_output_filename = arguments.value(std::string(""), "-o");

    windowTraits->debugLayer = arguments.read({"--debug", "-d"});
    windowTraits->apiDumpLayer = arguments.read({"--api", "-a"});
    arguments.read("--screen", windowTraits->screenNum);
    arguments.read("--display", windowTraits->display);
    arguments.read("--samples", windowTraits->samples);
    auto numFrames = arguments.value(-1, "-f");
    auto fontFile = arguments.value<vsg::Path>({}, "--font");
    auto fontSize = arguments.value<float>(30.0f, "--font-size");

    if (arguments.errors()) return arguments.writeErrorMessages(std::cerr);

    try
    {
        auto vsg_scene = vsg::Group::create();
        vsg::ref_ptr<vsg::EllipsoidModel> ellipsoidModel;

        if (argc > 1)
        {
            vsg::Path filename = arguments[1];
            if (auto node = vsg::read_cast<vsg::Node>(filename, options); node)
            {
                vsg_scene->addChild(node);

                ellipsoidModel = node->getRefObject<vsg::EllipsoidModel>("EllipsoidModel");
            }
        }

        // create the viewer and assign window(s) to it
        auto viewer = vsg::Viewer::create();

        vsg::ref_ptr<vsg::Window> window(vsg::Window::create(windowTraits));
        if (!window)
        {
            std::cout << "Could not create window." << std::endl;
            return 1;
        }

        viewer->addWindow(window);

        // compute the bounds of the scene graph to help position camera
        vsg::ComputeBounds computeBounds;
        vsg_scene->accept(computeBounds);
        vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max) * 0.5;
        double radius = vsg::length(computeBounds.bounds.max - computeBounds.bounds.min) * 0.6;

        // These are set statically because the geometry in the class is expanded in the shader
        double nearFarRatio = 0.01;

        // set up the camera
        auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(0.0, -radius * 3.5, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0));

        vsg::ref_ptr<vsg::ProjectionMatrix> perspective;
        if (ellipsoidModel)
        {
            perspective = vsg::EllipsoidPerspective::create(lookAt, ellipsoidModel, 30.0, static_cast<double>(window->extent2D().width) / static_cast<double>(window->extent2D().height), nearFarRatio, 0.0);
        }
        else
        {
            perspective = vsg::Perspective::create(30.0, static_cast<double>(window->extent2D().width) / static_cast<double>(window->extent2D().height), nearFarRatio * radius, radius * 400.5);
        }

        auto camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(window->extent2D()));

        // The commandGraph will contain a 2 stage renderGraph: 1) 3D scene 2) ImGui (by default also includes clearing of depth buffers)
        auto commandGraph = vsg::CommandGraph::create(window);
        auto renderGraph = vsg::RenderGraph::create(window);
        commandGraph->addChild(renderGraph);

        // create the normal 3D view of the scene
        auto view = vsg::View::create(camera);
        view->addChild(vsg::createHeadlight());
        view->addChild(vsg_scene);

        renderGraph->addChild(view);

        if (fontFile)
        {
            auto foundFontFile = vsg::findFile(fontFile, options);
            if (foundFontFile)
            {
                // convert native filename to UTF8 string that is compatible with ImGui.
                std::string c_fontFile = foundFontFile.string();

                // initialize ImGui
                ImGui::CreateContext();

                // read the font via ImGui, which will then be current when vsgImGui::RenderImGui initializes the rest of ImGui/Vulkan below
                ImGuiIO& io = ImGui::GetIO();
                auto imguiFont = io.Fonts->AddFontFromFileTTF(c_fontFile.c_str(), fontSize);
                if (!imguiFont)
                {
                    std::cout << "Failed to load font: " << c_fontFile << std::endl;
                    return 0;
                }
            }
        }

        // Create the ImGui node and add it to the renderGraph
        auto params = Params::create();
        auto renderImGui = vsgImGui::RenderImGui::create(window, MyGui::create(params, options));
        renderGraph->addChild(renderImGui);

        // Add the ImGui event handler first to handle events early
        viewer->addEventHandler(vsgImGui::SendEventsToImGui::create());

        // add close handler to respond to the close window button and pressing escape
        viewer->addEventHandler(vsg::CloseHandler::create(viewer));

        viewer->addEventHandler(vsg::Trackball::create(camera, ellipsoidModel));

        viewer->assignRecordAndSubmitTaskAndPresentation({commandGraph});

        viewer->compile();

        vsg::ref_ptr<vsg::RecordEvents> recordEvents;
        if (!event_output_filename.empty())
        {
            recordEvents = vsg::RecordEvents::create();
            viewer->addEventHandler(recordEvents);
        }

        vsg::ref_ptr<vsg::PlayEvents> playEvents;
        if (!event_read_filename.empty())
        {
            auto read_events = vsg::read(event_read_filename);
            if (read_events)
            {
                playEvents = vsg::PlayEvents::create(read_events, viewer->start_point().time_since_epoch());
            }
        }

        // rendering main loop
        while (viewer->advanceToNextFrame() && (numFrames < 0 || (numFrames--) > 0))
        {
       

            viewer->handleEvents();

            viewer->update();

            viewer->recordAndSubmit();

            viewer->present();
        }

   
    }
    catch (const vsg::Exception& ve)
    {
        std::cerr << "[Exception] - " << ve.message << std::endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值