From 166c1f428292912d0fc1d7e6db26a18e45aaf2a8 Mon Sep 17 00:00:00 2001 From: Jens Koenen <koenen@vr.rwth-aachen.de> Date: Fri, 14 Jul 2023 23:17:12 +0200 Subject: [PATCH] Improved scene loading as well as several smaller bug fixes and improvements --- src/encoder/encoder.cpp | 2 + src/encoder/nvidia_encoder.cpp | 3 +- src/headset/emulated_headset.cpp | 2 +- src/headset/remote_headset.cpp | 8 ++-- src/scene.cpp | 82 ++++++++++++++++++++------------ src/scene.hpp | 5 +- src/utility/frame_capture.cpp | 23 +++++++-- src/utility/statistic.cpp | 32 +++++++++---- src/utility/statistic.hpp | 5 +- src/vr_application.cpp | 30 ++++++++++-- 10 files changed, 135 insertions(+), 57 deletions(-) diff --git a/src/encoder/encoder.cpp b/src/encoder/encoder.cpp index 99f7d1aa..43b29bf0 100644 --- a/src/encoder/encoder.cpp +++ b/src/encoder/encoder.cpp @@ -95,8 +95,10 @@ bool shutdown_encoder(EncoderType encoder_type) { case ENCODER_TYPE_VULKAN: shutdown_vulkan_encoder(); + break; case ENCODER_TYPE_NVIDIA: shutdown_nvidia_encoder(); + break; default: lava::log()->error("Unkown encoder type!"); return false; diff --git a/src/encoder/nvidia_encoder.cpp b/src/encoder/nvidia_encoder.cpp index f75b0202..29ec2ae8 100644 --- a/src/encoder/nvidia_encoder.cpp +++ b/src/encoder/nvidia_encoder.cpp @@ -1158,7 +1158,8 @@ bool NvidiaEncoder::create_semaphore(NvidiaEncoderFrame::Ptr frame, lava::device #error "Not implemented for this platform!" #endif semaphore_description.flags = 0; - + memset(semaphore_description.reserved, 0, sizeof(semaphore_description.reserved)); + if (cuImportExternalSemaphore(&frame->cuda_external_semaphore, &semaphore_description) != CUDA_SUCCESS) { lava::log()->error("Nvidia Encoder: Can't import semaphore!"); diff --git a/src/headset/emulated_headset.cpp b/src/headset/emulated_headset.cpp index 30925cbf..35a8b299 100644 --- a/src/headset/emulated_headset.cpp +++ b/src/headset/emulated_headset.cpp @@ -93,7 +93,7 @@ void EmulatedHeadset::submit_frame(VkCommandBuffer command_buffer, VkImageLayout image_barriers.push_back(frame_barrier); } - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, image_barriers.size(), image_barriers.data()); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, image_barriers.size(), image_barriers.data()); VkImageSubresourceLayers subresource_layers; subresource_layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; diff --git a/src/headset/remote_headset.cpp b/src/headset/remote_headset.cpp index 30eb43b2..aa5702dd 100644 --- a/src/headset/remote_headset.cpp +++ b/src/headset/remote_headset.cpp @@ -145,11 +145,11 @@ bool RemoteHeadset::on_interface() } } - ImGui::SliderInt("Input-Rate (Fps)", (int32_t*) &this->encoder_input_rate, 1, 180); + ImGui::SliderInt("Input-Rate [Frames/s]", (int32_t*) &this->encoder_input_rate, 1, 180); if (encoder->is_supported(ENCODER_SETTING_KEY_RATE)) { - if (ImGui::SliderInt("Key-Rate (Frames)", (int32_t*) &this->encoder_key_rate, 1, 180)) + if (ImGui::SliderInt("Key-Rate [Frames]", (int32_t*) &this->encoder_key_rate, 1, 180)) { for (Encoder::Ptr encoder : this->encoders) { @@ -162,7 +162,7 @@ bool RemoteHeadset::on_interface() { if (encoder->is_supported(ENCODER_SETTING_BITRATE)) { - if (ImGui::SliderFloat("Bit-Rate (Mbps)", &this->encoder_bit_rate, 0.1f, 100.0f)) + if (ImGui::SliderFloat("Bit-Rate [Mbit/s]", &this->encoder_bit_rate, 0.1f, 100.0f)) { for (Encoder::Ptr encoder : this->encoders) { @@ -173,7 +173,7 @@ bool RemoteHeadset::on_interface() if (encoder->is_supported(ENCODER_SETTING_FRAME_RATE)) { - if (ImGui::SliderInt("Frame-Rate (Fps)", (int32_t*) &this->encoder_frame_rate, 1, 180)) + if (ImGui::SliderInt("Frame-Rate [Frames/s]", (int32_t*) &this->encoder_frame_rate, 1, 180)) { for (Encoder::Ptr encoder : this->encoders) { diff --git a/src/scene.cpp b/src/scene.cpp index ac4e400f..11404f12 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -236,7 +236,7 @@ bool Scene::update(lava::delta delta_time, Headset::Ptr headset) if (this->animation_active && !this->animations.empty()) { const SceneAnimation& active_animation = this->animations[this->animation_index]; - this->animation_time += delta_time * active_animation.ticks_per_second * this->animation_playback_speed; + this->animation_time += delta_time * this->animation_playback_speed; if (this->animation_loop) { @@ -985,7 +985,7 @@ bool Scene::load_sky_sphere(const std::string& file_name, uint32_t ring_count, u { lava::log()->info("Loading sky-sphere file '{}'", file_name.c_str()); - if (!this->load_texture(file_name, device, true, false, this->sky_emissive_texture)) + if (!this->load_texture(file_name, device, true, false, false, this->sky_emissive_texture)) { lava::log()->error("Faild to load sky-sphere '{}'", file_name.c_str()); @@ -1174,8 +1174,7 @@ bool Scene::load_animations(const aiScene* scene, float scale, const std::map<st SceneAnimation& scene_animation = this->animations.emplace_back(); scene_animation.name = animation->mName.C_Str(); - scene_animation.duration = animation->mDuration; - scene_animation.ticks_per_second = animation->mTicksPerSecond; + scene_animation.duration = animation->mDuration / animation->mTicksPerSecond; scene_animation.channels.resize(animation->mNumChannels); for (uint32_t channel_index = 0; channel_index < animation->mNumChannels; channel_index++) @@ -1198,19 +1197,19 @@ bool Scene::load_animations(const aiScene* scene, float scale, const std::map<st for (uint32_t frame_index = 0; frame_index < channel->mNumPositionKeys; frame_index++) { const aiVectorKey key = channel->mPositionKeys[frame_index]; - scene_channel.position_frames[frame_index] = std::make_pair((float)key.mTime, glm::make_vec3(&key.mValue.x) * scale); + scene_channel.position_frames[frame_index] = std::make_pair((float)key.mTime / animation->mTicksPerSecond, glm::make_vec3(&key.mValue.x) * scale); } for (uint32_t frame_index = 0; frame_index < channel->mNumRotationKeys; frame_index++) { const aiQuatKey key = channel->mRotationKeys[frame_index]; - scene_channel.rotation_frames[frame_index] = std::make_pair((float)key.mTime, key.mValue); + scene_channel.rotation_frames[frame_index] = std::make_pair((float)key.mTime / animation->mTicksPerSecond, key.mValue); } for (uint32_t frame_index = 0; frame_index < channel->mNumScalingKeys; frame_index++) { const aiVectorKey key = channel->mScalingKeys[frame_index]; - scene_channel.scaling_frames[frame_index] = std::make_pair((float)key.mTime, glm::make_vec3(&key.mValue.x)); + scene_channel.scaling_frames[frame_index] = std::make_pair((float)key.mTime / animation->mTicksPerSecond, glm::make_vec3(&key.mValue.x)); } } } @@ -1231,15 +1230,6 @@ bool Scene::load_lights(const aiScene* scene, float scale, const std::map<std::s return false; } - float light_scale = 1.0; - - if (light->mType == aiLightSource_DIRECTIONAL) - { - //NOTE: If the scene is in centimeters assume that directional light intensity is given as watt / cm^2. - // In this case the intensity has to be converted into watt / meter^2 - light_scale = glm::pow(scale, 1); //It should be a 2 instead of a 1 - } - glm::vec3 color = glm::make_vec3(&light->mColorDiffuse.r); glm::vec3 position = glm::make_vec3(&light->mPosition.x); glm::vec3 direction = glm::make_vec3(&light->mDirection.x); @@ -1257,7 +1247,7 @@ bool Scene::load_lights(const aiScene* scene, float scale, const std::map<std::s glsl::LightData& light_data = scene_light.data; light_data.position = scene_light.initial_position; - light_data.color = color * light_scale; + light_data.color = color; light_data.outer_angle = light->mAngleOuterCone; light_data.direction = scene_light.initial_direction; light_data.inner_angle = light->mAngleInnerCone; @@ -1360,7 +1350,6 @@ bool Scene::load_materials(const aiScene* scene, const std::string& base_name, l { const aiMaterial* material = scene->mMaterials[index]; SceneMaterial& scene_material = this->materials.emplace_back(); - scene_material.emissive = this->dummy_emissive_texture; aiColor3D diffuse_color = aiColor3D(0.0f, 0.0f, 0.0f); material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse_color); @@ -1380,16 +1369,16 @@ bool Scene::load_materials(const aiScene* scene, const std::string& base_name, l glsl::MaterialData& material_data = scene_material.material_data; material_data.base_color = glm::vec3(1.0f); material_data.opacity = 1.0f; - material_data.emissive = glm::make_vec3(&emissive_color.r); + material_data.emissive = glm::vec3(1.0f); material_data.roughness = 1.0f; material_data.padding1 = glm::uvec3(0); - material_data.metallic = 0.0f; + material_data.metallic = 1.0f; material_data.padding2 = glm::uvec4(0); material_data.padding3 = glm::mat4(0); material_data.padding4 = glm::mat4(0); material_data.padding5 = glm::mat4(0); - if (!this->load_texture(material, base_name, aiTextureType_DIFFUSE, device, scene_material.diffuse)) + if (!this->load_texture(material, base_name, aiTextureType_DIFFUSE, true, device, scene_material.diffuse)) { scene_material.diffuse = this->dummy_diffuse_texture; @@ -1397,7 +1386,7 @@ bool Scene::load_materials(const aiScene* scene, const std::string& base_name, l material_data.opacity = glm::clamp(opacity, 0.0f, 1.0f); } - if (!this->load_texture(material, base_name, aiTextureType_SPECULAR, device, scene_material.specular)) + if (!this->load_texture(material, base_name, aiTextureType_SPECULAR, false, device, scene_material.specular)) { scene_material.specular = this->dummy_specular_texture; @@ -1405,16 +1394,23 @@ bool Scene::load_materials(const aiScene* scene, const std::string& base_name, l material_data.metallic = glm::clamp(reflectivity, 0.0f, 1.0f); } - if (!this->load_texture(material, base_name, aiTextureType_NORMALS, device, scene_material.normal)) + if (!this->load_texture(material, base_name, aiTextureType_NORMALS, false, device, scene_material.normal)) { scene_material.normal = this->dummy_normal_texture; } + + if (!this->load_texture(material, base_name, aiTextureType_EMISSIVE, false, device, scene_material.emissive)) + { + scene_material.emissive = this->dummy_emissive_texture; + + material_data.emissive = glm::make_vec3(&emissive_color.r); + } } return true; } -bool Scene::load_texture(const aiMaterial* material, const std::string& base_name, aiTextureType type, lava::device_ptr device, lava::texture::ptr& texture) +bool Scene::load_texture(const aiMaterial* material, const std::string& base_name, aiTextureType type, bool use_srgb, lava::device_ptr device, lava::texture::ptr& texture) { aiString texture_path; @@ -1436,7 +1432,7 @@ bool Scene::load_texture(const aiMaterial* material, const std::string& base_nam std::string file_name = (base_path / texture_path.C_Str()).string(); std::replace(file_name.begin(), file_name.end(), '\\', '/'); - if (!this->load_texture(file_name, device, false, true, texture)) + if (!this->load_texture(file_name, device, false, true, use_srgb, texture)) { lava::log()->warn("Faild to load texture file '{}'. Using dummy texture instead.", file_name.c_str()); @@ -1446,7 +1442,7 @@ bool Scene::load_texture(const aiMaterial* material, const std::string& base_nam return true; } -bool Scene::load_texture(const std::string& file_name, lava::device_ptr device, bool use_float, bool use_mipmaps, lava::texture::ptr& texture) +bool Scene::load_texture(const std::string& file_name, lava::device_ptr device, bool use_float, bool use_mipmaps, bool use_srgb, lava::texture::ptr& texture) { for (const SceneTexture& scene_texture : this->textures) { @@ -1509,11 +1505,29 @@ bool Scene::load_texture(const std::string& file_name, lava::device_ptr device, switch (texture.format()) { + case gli::FORMAT_RGBA_DXT1_SRGB_BLOCK8: case gli::FORMAT_RGBA_DXT1_UNORM_BLOCK8: - format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + if (use_srgb) + { + format = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; + } + + else + { + format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + } break; + case gli::FORMAT_RGBA_DXT5_SRGB_BLOCK16: case gli::FORMAT_RGBA_DXT5_UNORM_BLOCK16: - format = VK_FORMAT_BC3_UNORM_BLOCK; + if (use_srgb) + { + format = VK_FORMAT_BC3_SRGB_BLOCK; + } + + else + { + format = VK_FORMAT_BC3_UNORM_BLOCK; + } break; case gli::FORMAT_RG_ATI2N_UNORM_BLOCK16: format = VK_FORMAT_BC5_UNORM_BLOCK; @@ -1562,7 +1576,15 @@ bool Scene::load_texture(const std::string& file_name, lava::device_ptr device, else { - format = VK_FORMAT_R8G8B8A8_SRGB; + if (use_srgb) + { + format = VK_FORMAT_R8G8B8A8_SRGB; + } + + else + { + format = VK_FORMAT_R8G8B8A8_UNORM; + } data_pointer = (uint8_t*) stbi_load_from_memory((const stbi_uc*) image_data.ptr, image_data.size, &width, &height, nullptr, STBI_rgb_alpha); data_bitdepth = 4 * sizeof(uint8_t); @@ -2117,7 +2139,7 @@ void Scene::apply_transforms() const SceneNode& node = this->nodes[camera.node_index]; glm::vec3 global_location = node.current_global_transform * glm::vec4(camera.local_position, 1.0f); - glm::vec3 global_look_at = node.current_global_transform * glm::vec4(camera.local_look_at, 0.0f); + glm::vec3 global_look_at = node.current_global_transform * glm::vec4(camera.local_look_at, 1.0f); glm::vec3 global_up = node.current_global_transform * glm::vec4(camera.local_up, 0.0f); camera.view_matrix = glm::lookAt(global_location, global_look_at, global_up); diff --git a/src/scene.hpp b/src/scene.hpp index ad9cb9fe..32ea34cc 100644 --- a/src/scene.hpp +++ b/src/scene.hpp @@ -145,7 +145,6 @@ struct SceneAnimation { std::string name; float duration = 0.0f; - float ticks_per_second = 0.0f; std::vector<SceneAnimationChannel> channels; }; @@ -216,8 +215,8 @@ private: bool load_lights(const aiScene* scene, float scale, const std::map<std::string, SceneNodeIndex>& node_indices); bool load_meshes(const aiScene* scene, float scale, uint32_t base_material, bool scene_bounds, lava::device_ptr device); bool load_materials(const aiScene* scene, const std::string& base_name, lava::device_ptr device); - bool load_texture(const aiMaterial* material, const std::string& base_name, aiTextureType type, lava::device_ptr device, lava::texture::ptr& texture); - bool load_texture(const std::string& file_name, lava::device_ptr device, bool use_float, bool use_mipmaps, lava::texture::ptr& texture); + bool load_texture(const aiMaterial* material, const std::string& base_name, aiTextureType type, bool use_srgb, lava::device_ptr device, lava::texture::ptr& texture); + bool load_texture(const std::string& file_name, lava::device_ptr device, bool use_float, bool use_mipmaps, bool use_srgb, lava::texture::ptr& texture); bool stage_textures(lava::device_ptr device); diff --git a/src/utility/frame_capture.cpp b/src/utility/frame_capture.cpp index 5c8680b5..2ff93093 100644 --- a/src/utility/frame_capture.cpp +++ b/src/utility/frame_capture.cpp @@ -211,13 +211,28 @@ bool FrameCapture::write_to_file(const ImageCapture& image_capture, const uint8_ std::filesystem::create_directory(directory_path); } - std::vector<uint8_t> converted_content = this->convert_content(image_content, image_capture.size, image_capture.format); + if (image_capture.format == VK_FORMAT_R8G8B8_UNORM || image_capture.format == VK_FORMAT_R8G8B8_SRGB || image_capture.format == VK_FORMAT_R8G8B8A8_UNORM || image_capture.format == VK_FORMAT_R8G8B8A8_SRGB) + { + uint32_t component_count = this->get_component_count(image_capture.format); + + if (stbi_write_png(file_name.c_str(), image_capture.size.x, image_capture.size.y, component_count, image_content, image_capture.size.x * component_count * sizeof(uint8_t)) == 0) + { + lava::log()->error("Can't store image '" + image_capture.name + "'"); + + return false; + } + } - if (stbi_write_png(file_name.c_str(), image_capture.size.x, image_capture.size.y, 4, converted_content.data(), image_capture.size.x * 4 * sizeof(uint8_t)) == 0) + else { - lava::log()->error("can't store image '" + image_capture.name + "'"); + std::vector<uint8_t> converted_content = this->convert_content(image_content, image_capture.size, image_capture.format); - return false; + if (stbi_write_png(file_name.c_str(), image_capture.size.x, image_capture.size.y, 4, converted_content.data(), image_capture.size.x * 4 * sizeof(uint8_t)) == 0) + { + lava::log()->error("can't store image '" + image_capture.name + "'"); + + return false; + } } return true; diff --git a/src/utility/statistic.cpp b/src/utility/statistic.cpp index 045edc98..6b0da71c 100644 --- a/src/utility/statistic.cpp +++ b/src/utility/statistic.cpp @@ -60,6 +60,7 @@ void Statistic::add_sample(float value) { StatisticSample sample; sample.value = value; + sample.time_point = std::chrono::high_resolution_clock::now(); this->samples.push_back(sample); } @@ -258,6 +259,11 @@ bool Statistic::is_log_only() const return this->log_only; } +StatisticLog::StatisticLog() +{ + this->time_origin = std::chrono::high_resolution_clock::now(); +} + bool StatisticLog::write(const std::string& directory) { if (!std::filesystem::exists(directory)) @@ -287,18 +293,22 @@ bool StatisticLog::write(const std::string& directory) { for (const StatisticSample& sample : statistic->get_samples()) { - std::string label; + std::string label_value; + std::string label_time; if (sample.frame_id.has_value()) { - label = statistic->get_name() + "_" + std::to_string(sample.frame_id.value()) + " [" + statistic->get_unit_name() + "]"; + label_value = statistic->get_name() + "_" + std::to_string(sample.frame_id.value()) + " [" + statistic->get_unit_name() + "]"; + label_time = statistic->get_name() + "_" + std::to_string(sample.frame_id.value()) + "_time [ms]"; } else { - label = statistic->get_name() + " [" + statistic->get_unit_name() + "]"; + label_value = statistic->get_name() + " [" + statistic->get_unit_name() + "]"; + label_time = statistic->get_name() + "_time [ms]"; } + double sample_time = std::chrono::duration_cast<std::chrono::duration<double, std::chrono::milliseconds::period>>(sample.time_point - this->time_origin).count(); bool ordered = sample.frame_number.has_value() || sample.transform_id.has_value(); if (ordered) @@ -312,7 +322,7 @@ bool StatisticLog::write(const std::string& directory) for (uint32_t index = 0; index < ordered_sample_labels.size(); index++) { - if (ordered_sample_labels[index] == label) + if (ordered_sample_labels[index] == label_value) { column_index = index; column_found = true; @@ -324,17 +334,19 @@ bool StatisticLog::write(const std::string& directory) if (!column_found) { column_index = ordered_sample_labels.size(); - ordered_sample_labels.push_back(label); + ordered_sample_labels.push_back(label_value); + ordered_sample_labels.push_back(label_time); } std::vector<std::optional<double>>& row = ordered_samples[key]; if (row.size() <= column_index) { - row.resize(column_index + 1); + row.resize(column_index + 2); } row[column_index] = sample.value; + row[column_index + 1] = sample_time; } else @@ -344,7 +356,7 @@ bool StatisticLog::write(const std::string& directory) for (uint32_t index = 0; index < unordered_sample_labels.size(); index++) { - if (unordered_sample_labels[index] == label) + if (unordered_sample_labels[index] == label_value) { column_index = index; column_found = true; @@ -356,15 +368,17 @@ bool StatisticLog::write(const std::string& directory) if (!column_found) { column_index = unordered_sample_labels.size(); - unordered_sample_labels.push_back(label); + unordered_sample_labels.push_back(label_value); + unordered_sample_labels.push_back(label_time); } if (unordered_samples.size() <= column_index) { - unordered_samples.resize(column_index + 1); + unordered_samples.resize(column_index + 2); } unordered_samples[column_index].push_back(sample.value); + unordered_samples[column_index + 1].push_back(sample_time); } } } diff --git a/src/utility/statistic.hpp b/src/utility/statistic.hpp index f8883be7..84c73ac7 100644 --- a/src/utility/statistic.hpp +++ b/src/utility/statistic.hpp @@ -14,6 +14,7 @@ */ #pragma once +#include <chrono> #include <memory> #include <string> #include <vector> @@ -25,6 +26,7 @@ struct StatisticSample { double value; + std::chrono::high_resolution_clock::time_point time_point; std::optional<FrameNumber> frame_number; std::optional<FrameId> frame_id; @@ -89,7 +91,7 @@ public: typedef std::shared_ptr<StatisticLog> Ptr; public: - StatisticLog() = default; + StatisticLog(); bool write(const std::string& directory); @@ -100,6 +102,7 @@ private: private: std::vector<Statistic::Ptr> statistic_list; + std::chrono::high_resolution_clock::time_point time_origin; }; Statistic::Ptr make_statistic(const std::string& name, Unit unit, bool log_only = false); diff --git a/src/vr_application.cpp b/src/vr_application.cpp index 56adfede..8ddde89a 100644 --- a/src/vr_application.cpp +++ b/src/vr_application.cpp @@ -331,10 +331,13 @@ bool VRApplication::on_create() if (!this->command_parser.should_benchmark()) { - config.controller_left_file = std::string(RESOURCE_FOLDER) + "/dpr-controller/ObjModelViveFocus3ControllerLeft.fbx"; + std::string left_controller_file = "/dpr-controller/ObjModelViveFocus3ControllerLeft.fbx"; + std::string right_controller_file = "/dpr-controller/ObjModelViveFocus3ControllerRight.fbx"; + + config.controller_left_file = lava::file_system::get_real_dir(right_controller_file.c_str()) + left_controller_file; config.controller_left_unit = SCENE_UNIT_CENTIMETERS; - config.controller_right_file = std::string(RESOURCE_FOLDER) + "/dpr-controller/ObjModelViveFocus3ControllerRight.fbx"; + config.controller_right_file = lava::file_system::get_real_dir(right_controller_file.c_str()) + right_controller_file; config.controller_right_unit = SCENE_UNIT_CENTIMETERS; } @@ -528,9 +531,12 @@ void VRApplication::on_destroy() this->scene->destroy(); } - if (!this->statistic_log->write("statistics")) + if (this->statistic_log != nullptr) { - lava::log()->error("Can't write statistic!"); + if (!this->statistic_log->write("statistics")) + { + lava::log()->error("Can't write statistic!"); + } } } @@ -562,6 +568,8 @@ bool VRApplication::on_interface() if (ImGui::CollapsingHeader("Scene", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::PushID("SceneInterface"); + if (!this->scene->interface()) { lava::log()->error("Error during scene interface!"); @@ -569,10 +577,14 @@ bool VRApplication::on_interface() return false; } + + ImGui::PopID(); } if (ImGui::CollapsingHeader("Headset", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::PushID("HeadsetInterface"); + if (!this->headset->on_interface()) { lava::log()->error("Error during headset interface!"); @@ -580,10 +592,14 @@ bool VRApplication::on_interface() return false; } + + ImGui::PopID(); } if (ImGui::CollapsingHeader("Strategy", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::PushID("StrategyInterface"); + std::vector<const char*> strategy_names; for (StereoStrategy::Ptr strategy : this->strategies) @@ -605,10 +621,14 @@ bool VRApplication::on_interface() return false; } + + ImGui::PopID(); } if (ImGui::CollapsingHeader("Debug")) { + ImGui::PushID("DebugInterface"); + bool companion_enabled = this->companion_window->is_enabled(); ImGui::Checkbox("Companion Window", &companion_enabled); this->companion_window->set_enabled(companion_enabled); @@ -621,6 +641,8 @@ bool VRApplication::on_interface() this->pass_timer->interface(); this->app->draw_about(true); + + ImGui::PopID(); } ImGui::End(); -- GitLab