sensics / OSVR-RenderManager

Apache License 2.0
63 stars 45 forks source link

ConstructProjection function doesn't handle cop's/distance scales correctly #227

Closed emmahafermann closed 7 years ago

emmahafermann commented 7 years ago

The function below needs to normalize xCOP/yCOP by the distance scale specified in the config file. Also, if the xCOP/yCOP is not at the center of the screen, then calculating right/left/top/bottom by taking tan(fov/2) then scaling by the COP offset will introduce error.

https://github.com/sensics/OSVR-RenderManager/blob/master/osvr/RenderKit/RenderManagerBase.cpp#L1098

        double right =
            tan(osvr::util::getRadians(
                    m_params.m_displayConfiguration->getHorizontalFOV()) /
                2.0);
        double left = -right;
        double top = tan(osvr::util::getRadians(
                             m_params.m_displayConfiguration->getVerticalFOV()) /
                         2.0);
        double bottom = -top;

        // Scale the in-plane positions based on the near plane to put
        // the virtual viewing window on the near plane with the eye at the
        // origin.
        left *= nearClipDistanceMeters;
        right *= nearClipDistanceMeters;
        top *= nearClipDistanceMeters;
        bottom *= nearClipDistanceMeters;

        // Incorporate the center-of-projection information for this
        // eye, shifting so that 0.5,0.5 is in the center of the screen.
        // We need to do this before we scale the viewport to add the amount
        // needed for overfill, so we don't end up shifting past the edge of
        // the actual screen.
        double width = right - left;
        double height = top - bottom;
        double xCOP =
            m_params.m_displayConfiguration->getEyes()[whichEye].m_CenterProjX;
        double yCOP =
            m_params.m_displayConfiguration->getEyes()[whichEye].m_CenterProjY;
        double xOffset = (0.5 - xCOP) * width;
        double yOffset = (0.5 - yCOP) * height;
        left += xOffset;
        right += xOffset;
        top += yOffset;
        bottom += yOffset;
russell-taylor commented 7 years ago

This is also described in https://github.com/sensics/OSVR-RenderManager/blob/master/osvr/RenderKit/DistortionParameters.h#L98, which includes:

/// @todo Turn COP always into the range 0-1, and have it always use the
/// lower-left corner of the display, even for Direct3D.  Do the
/// conversions internally.  When this is done, also adjust the flipping
/// in the OpenGL to D3D to suit.
russell-taylor commented 7 years ago

This scaling is done in fc38e9fd2bac7634f03eafe8cbd23c6015c51341 by defining the COP in the config file to always be normalized w.r.t. the screen and now doing the D scaling inside the distortion-correction code.

The discrepancy between the actual FOV and the specified FOV for COPs not at the center of the screen is addressed in documentation in https://github.com/OSVR/OSVR-Docs/blob/russell-taylor-patch-3/Configuring/distortion.md by defining the specification of the FOV as being w.r.t a centered COP.