Skip to content

Quad layer pose in view space and change texture filtering#82

Open
Giulero wants to merge 2 commits intogbionics:mainfrom
Giulero:native_quad_layer_pose
Open

Quad layer pose in view space and change texture filtering#82
Giulero wants to merge 2 commits intogbionics:mainfrom
Giulero:native_quad_layer_pose

Conversation

@Giulero
Copy link
Copy Markdown

@Giulero Giulero commented Mar 23, 2026

When projecting an image in the headset, I noticed a continuous jitter. Some investigations with Claude led to this PR.

So, this PR introduces the following:

  • Change quad layer pose computation when using native quad layers (--use_native_quad_layers): When using native quad layers, layers are created in VIEW space, where poses are inherently head-relative. The old code multiplied the desired pose by the current head pose on every frame, introducing frame-to-frame jitter from head-tracking noise. The fix skips this multiplication when the layer space is VIEW space.
  • Switch texture blit filtering from GL_NEAREST to GL_LINEAR in both ImagePortToQuadLayer and OpenGLQuadLayer to avoid pixelation when the image is scaled to the layer size. Also add explicit min/mag filter parameters to the intermediate texture setup.

How to test: Run the device with --use_native_quad_layers and verify that overlays are stable and correctly positioned without jittering.

@Giulero Giulero requested a review from S-Dafarra as a code owner March 23, 2026 09:30
@S-Dafarra
Copy link
Copy Markdown
Collaborator

Could you do one test with main using only the flag --use_native_quad_layers?

The reason I am asking is because the change in OpenXrInterface.cpp in theory should not be needed. The reason is that the mid view pose is computed according to the choice of the render space. See

XrViewLocateInfo view_locate_info = {.type = XR_TYPE_VIEW_LOCATE_INFO,
.next = NULL,
.viewConfigurationType =
XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
.displayTime = m_pimpl->frame_state.predictedDisplayTime,
.space = m_pimpl->renderInPlaySpace ? m_pimpl->play_space : m_pimpl->view_space };
uint32_t output_viewCount = static_cast<uint32_t>(m_pimpl->views.size());
XrResult result = xrLocateViews(m_pimpl->session, &view_locate_info, &(m_pimpl->view_state),
static_cast<uint32_t>(m_pimpl->views.size()), &output_viewCount, m_pimpl->views.data());
if (!m_pimpl->checkXrOutput(result, "Failed to locate the views!"))
{
m_pimpl->view_state.viewStateFlags = 0; //Set to zero all the valid/tracked flags
}
m_pimpl->mid_views_pose = m_pimpl->views[0].pose;
for (size_t i = 1; i < m_pimpl->views.size(); ++i)
{
m_pimpl->mid_views_pose.position = toXr(Eigen::Vector3f(toEigen(m_pimpl->mid_views_pose.position) + toEigen(m_pimpl->views[i].pose.position)));
}
m_pimpl->mid_views_pose.position = toXr(Eigen::Vector3f(toEigen(m_pimpl->mid_views_pose.position)/static_cast<float>(m_pimpl->views.size())));
m_pimpl->mid_views_pose_inverted.orientation = toXr(toEigen(m_pimpl->mid_views_pose.orientation).inverse());
m_pimpl->mid_views_pose_inverted.position = toXr(toEigen(m_pimpl->mid_views_pose_inverted.orientation) * -toEigen(m_pimpl->mid_views_pose.position));

Hence, I am expecting m_pimpl->mid_views_pose to be the identity when rendering in the view space (default case). If it is not the case, then the modification would totally make sense, but it would be also interesting to understand why this happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants