diff --git a/include/neural-graphics-primitives/openxr_hmd.h b/include/neural-graphics-primitives/openxr_hmd.h index ee442ef9aa5f07abeae2c2f78a06f3d376c59916..ac6cacab5f212653baf36ecd762a9f81e0444263 100644 --- a/include/neural-graphics-primitives/openxr_hmd.h +++ b/include/neural-graphics-primitives/openxr_hmd.h @@ -47,6 +47,21 @@ NGP_NAMESPACE_BEGIN +enum class EnvironmentBlendMode { + Opaque = XR_ENVIRONMENT_BLEND_MODE_OPAQUE, + Additive = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE, + AlphaBlend = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND, +}; + +inline std::string to_string(EnvironmentBlendMode mode) { + switch (mode) { + case EnvironmentBlendMode::Opaque: return "Opaque"; + case EnvironmentBlendMode::Additive: return "Additive"; + case EnvironmentBlendMode::AlphaBlend: return "Blend"; + default: throw std::runtime_error{"Invalid blend mode."}; + } +} + class OpenXRHMD { public: enum class ControlFlow { @@ -108,6 +123,22 @@ public: // must be called for each begin_frame void end_frame(FrameInfoPtr frame_info, float znear, float zfar); + void set_environment_blend_mode(EnvironmentBlendMode mode) { + m_environment_blend_mode = mode; + } + + EnvironmentBlendMode environment_blend_mode() const { + return m_environment_blend_mode; + } + + const std::vector<EnvironmentBlendMode>& supported_environment_blend_modes() const { + return m_supported_environment_blend_modes; + } + + const std::string& supported_environment_blend_modes_string() const { + return m_supported_environment_blend_modes_string; + } + // if true call begin_frame and end_frame - does not imply visibility bool must_run_frame_loop() const { return @@ -161,8 +192,9 @@ private: XrViewConfigurationType m_view_configuration_type = {}; XrViewConfigurationProperties m_view_configuration_properties = {XR_TYPE_VIEW_CONFIGURATION_PROPERTIES}; std::vector<XrViewConfigurationView> m_view_configuration_views; - std::vector<XrEnvironmentBlendMode> m_environment_blend_modes; - XrEnvironmentBlendMode m_environment_blend_mode = {XR_ENVIRONMENT_BLEND_MODE_OPAQUE}; + std::vector<EnvironmentBlendMode> m_supported_environment_blend_modes; + std::string m_supported_environment_blend_modes_string; + EnvironmentBlendMode m_environment_blend_mode = EnvironmentBlendMode::Opaque; // actions std::array<XrPath, 2> m_hand_paths; diff --git a/src/openxr_hmd.cu b/src/openxr_hmd.cu index b7d2cd4e8e4c8bd5d4b418b7797dbd805c064991..0befdfce511a95c0fd6b2badf53dce88db4d1d38 100644 --- a/src/openxr_hmd.cu +++ b/src/openxr_hmd.cu @@ -425,34 +425,39 @@ void OpenXRHMD::init_check_for_xr_blend_mode() { // enumerate environment blend modes uint32_t size; XR_CHECK_THROW(xrEnumerateEnvironmentBlendModes(m_instance, m_system_id, m_view_configuration_type, 0, &size, nullptr)); - m_environment_blend_modes.resize(size); + std::vector<XrEnvironmentBlendMode> supported_blend_modes(size); XR_CHECK_THROW(xrEnumerateEnvironmentBlendModes( m_instance, m_system_id, m_view_configuration_type, size, &size, - m_environment_blend_modes.data() + supported_blend_modes.data() )); + if (supported_blend_modes.empty()) { + throw std::runtime_error{"No OpenXR environment blend modes found"}; + } + if (m_print_environment_blend_modes) { - tlog::info() << fmt::format("Environment Blend Modes ({}):", m_environment_blend_modes.size()); + tlog::info() << fmt::format("Environment Blend Modes ({}):", supported_blend_modes.size()); } - bool found = false; - for (const auto& m : m_environment_blend_modes) { + m_supported_environment_blend_modes.resize(size); + m_supported_environment_blend_modes_string = ""; + for (size_t i = 0; i < supported_blend_modes.size(); ++i) { if (m_print_environment_blend_modes) { - tlog::info() << fmt::format("\t{}", XrEnumStr(m)); + tlog::info() << fmt::format("\t{}", XrEnumStr(supported_blend_modes[i])); } - if (m == m_environment_blend_mode) { - found = true; - } + auto b = (EnvironmentBlendMode)supported_blend_modes[i]; + m_supported_environment_blend_modes[i] = b; + m_supported_environment_blend_modes_string += to_string(b) + "\0"; } - if (!found) { - throw std::runtime_error{fmt::format("OpenXR environment blend mode {} not found", XrEnumStr(m_environment_blend_mode))}; - } + m_supported_environment_blend_modes_string += "\0"; + + m_environment_blend_mode = m_supported_environment_blend_modes.front(); } void OpenXRHMD::init_xr_actions() { @@ -1236,7 +1241,7 @@ void OpenXRHMD::end_frame(FrameInfoPtr frame_info, float znear, float zfar) { XrFrameEndInfo frame_end_info{XR_TYPE_FRAME_END_INFO}; frame_end_info.displayTime = m_frame_state.predictedDisplayTime; - frame_end_info.environmentBlendMode = m_environment_blend_mode; + frame_end_info.environmentBlendMode = (XrEnvironmentBlendMode)m_environment_blend_mode; frame_end_info.layerCount = (uint32_t)layers.size(); frame_end_info.layers = layers.data(); XR_CHECK_THROW(xrEndFrame(m_session, &frame_end_info)); diff --git a/src/testbed.cu b/src/testbed.cu index c212f96de628af14f5f0886ae8e1f83e4eb77957..9d322d6e7f058e52e29edccf3ac0eb77b4e7bef1 100644 --- a/src/testbed.cu +++ b/src/testbed.cu @@ -925,16 +925,32 @@ void Testbed::imgui() { ImGui::OpenPopup("Error"); } } - } else if (ImGui::TreeNodeEx("VR/AR settings", ImGuiTreeNodeFlags_DefaultOpen)) { - if (m_devices.size() > 1 && m_testbed_mode == ETestbedMode::Nerf) { - ImGui::Checkbox("Multi-GPU rendering (one per eye)", &m_use_aux_devices); - } + } else { + if (ImGui::Button("Disconnect from VR/AR headset")) { + m_hmd.reset(); + m_vr_frame_info = nullptr; + m_render_transparency_as_checkerboard = false; + } else if (ImGui::TreeNodeEx("VR/AR settings", ImGuiTreeNodeFlags_DefaultOpen)) { + static int blend_mode_idx = 0; + const auto& supported_blend_modes = m_hmd->supported_environment_blend_modes(); + if (supported_blend_modes.size() > 1) { + if (ImGui::Combo("Environment blend mode", &blend_mode_idx, m_hmd->supported_environment_blend_modes_string().c_str())) { + auto b = m_hmd->supported_environment_blend_modes().at(blend_mode_idx); + m_hmd->set_environment_blend_mode(b); + m_render_transparency_as_checkerboard = (b == EnvironmentBlendMode::Opaque); + } + } - accum_reset |= ImGui::Checkbox("Foveated rendering", &m_foveated_rendering) && !m_dlss; - if (m_foveated_rendering) { - accum_reset |= ImGui::SliderFloat("Maximum foveation", &m_foveated_rendering_max_scaling, 1.0f, 16.0f, "%.01f", ImGuiSliderFlags_Logarithmic | ImGuiSliderFlags_NoRoundToFormat) && !m_dlss; + if (m_devices.size() > 1 && m_testbed_mode == ETestbedMode::Nerf) { + ImGui::Checkbox("Multi-GPU rendering (one per eye)", &m_use_aux_devices); + } + + accum_reset |= ImGui::Checkbox("Foveated rendering", &m_foveated_rendering) && !m_dlss; + if (m_foveated_rendering) { + accum_reset |= ImGui::SliderFloat("Maximum foveation", &m_foveated_rendering_max_scaling, 1.0f, 16.0f, "%.01f", ImGuiSliderFlags_Logarithmic | ImGuiSliderFlags_NoRoundToFormat) && !m_dlss; + } + ImGui::TreePop(); } - ImGui::TreePop(); } ImGui::Checkbox("Render", &m_render); @@ -3144,7 +3160,7 @@ bool Testbed::frame() { ImGui::EndFrame(); } - if (m_vr_frame_info) { + if (m_hmd && m_vr_frame_info) { // If HMD is visible to the user, splat rendered images to the HMD if (m_hmd->is_visible()) { size_t n_views = std::min(m_views.size(), m_vr_frame_info->views.size()); @@ -4186,7 +4202,7 @@ void Testbed::render_frame_epilogue( Matrix<float, 3, 4> checkerboard_transform = Matrix<float, 3, 4>::Identity(); #if NGP_GUI - if (m_vr_frame_info && !m_vr_frame_info->views.empty()) { + if (m_hmd && m_vr_frame_info && !m_vr_frame_info->views.empty()) { checkerboard_transform = m_vr_frame_info->views[0].pose; } #endif @@ -4266,7 +4282,7 @@ void Testbed::render_frame_epilogue( #if NGP_GUI // If in VR, indicate the hand position and render transparent background - if (m_vr_frame_info) { + if (m_hmd && m_vr_frame_info) { auto& hands = m_vr_frame_info->hands; auto res = render_buffer.out_resolution();