void OculusWorldDemoApp::RenderGrid(ovrEyeType eye, Recti renderViewport) { // Draw actual pixel grid on the RT. // 1:1 mapping to screen pixels, origin in top-left. Matrix4f ortho; ortho.SetIdentity(); ortho.M[0][0] = 2.0f / (renderViewport.w); // X scale ortho.M[0][3] = -1.0f; // X offset ortho.M[1][1] = -2.0f / (renderViewport.h); // Y scale (for Y=down) ortho.M[1][3] = 1.0f; // Y offset (Y=down) ortho.M[2][2] = 0; pRender->SetProjection(ortho); pRender->SetViewport(renderViewport); pRender->SetDepthMode(false, false); Color cNormal ( 0, 255, 0 ); // Green is the least-smeared color from CA. Color cSpacer ( 255, 255, 0 ); Color cMid ( 0, 128, 255 ); int lineStep = 1; int midX = 0; int midY = 0; int limitX = 0; int limitY = 0; switch ( GridMode ) { case Grid_Rendertarget4: lineStep = 4; midX = renderViewport.w / 2; midY = renderViewport.h / 2; limitX = renderViewport.w / 2; limitY = renderViewport.h / 2; break; case Grid_Rendertarget16: lineStep = 16; midX = renderViewport.w / 2; midY = renderViewport.h / 2; limitX = renderViewport.w / 2; limitY = renderViewport.h / 2; break; case Grid_Lens: { lineStep = 48; Vector2f rendertargetNDC = FovPort(EyeRenderDesc[eye].Fov).TanAngleToRendertargetNDC(Vector2f(0.0f)); midX = (int)( ( rendertargetNDC.x * 0.5f + 0.5f ) * (float)renderViewport.w + 0.5f ); midY = (int)( ( rendertargetNDC.y * 0.5f + 0.5f ) * (float)renderViewport.h + 0.5f ); limitX = Alg::Max ( renderViewport.w - midX, midX ); limitY = Alg::Max ( renderViewport.h - midY, midY ); } break; default: OVR_ASSERT ( false ); break; } int spacerMask = (lineStep<<2)-1; for ( int xp = 0; xp < limitX; xp += lineStep ) { float x[4]; float y[4]; x[0] = (float)( midX + xp ); y[0] = (float)0; x[1] = (float)( midX + xp ); y[1] = (float)renderViewport.h; x[2] = (float)( midX - xp ); y[2] = (float)0; x[3] = (float)( midX - xp ); y[3] = (float)renderViewport.h; if ( xp == 0 ) { pRender->RenderLines ( 1, cMid, x, y ); } else if ( ( xp & spacerMask ) == 0 ) { pRender->RenderLines ( 2, cSpacer, x, y ); } else { pRender->RenderLines ( 2, cNormal, x, y ); } } for ( int yp = 0; yp < limitY; yp += lineStep ) { float x[4]; float y[4]; x[0] = (float)0; y[0] = (float)( midY + yp ); x[1] = (float)renderViewport.w; y[1] = (float)( midY + yp ); x[2] = (float)0; y[2] = (float)( midY - yp ); x[3] = (float)renderViewport.w; y[3] = (float)( midY - yp ); if ( yp == 0 ) { pRender->RenderLines ( 1, cMid, x, y ); } else if ( ( yp & spacerMask ) == 0 ) { pRender->RenderLines ( 2, cSpacer, x, y ); } else { pRender->RenderLines ( 2, cNormal, x, y ); } } // Draw diagonal lines { float x[2]; float y[2]; x[0] = (float)(midX - renderViewport.w); x[1] = (float)(midX + renderViewport.w); y[0] = (float)(midY - renderViewport.w); y[1] = (float)(midY + renderViewport.w); pRender->RenderLines(1, cNormal, x, y); } { float x[2]; float y[2]; x[0] = (float)(midX + renderViewport.w); x[1] = (float)(midX - renderViewport.w); y[0] = (float)(midY - renderViewport.w); y[1] = (float)(midY + renderViewport.w); pRender->RenderLines(1, cNormal, x, y); } }
void OculusWorldDemoApp::CalculateHmdValues() { // Initialize eye rendering information for ovrHmd_Configure. // The viewport sizes are re-computed in case RenderTargetSize changed due to HW limitations. ovrFovPort eyeFov[2]; eyeFov[0] = HmdDesc.DefaultEyeFov[0]; eyeFov[1] = HmdDesc.DefaultEyeFov[1]; // Clamp Fov based on our dynamically adjustable FovSideTanMax. // Most apps should use the default, but reducing Fov does reduce rendering cost. eyeFov[0] = FovPort::Min(eyeFov[0], FovPort(FovSideTanMax)); eyeFov[1] = FovPort::Min(eyeFov[1], FovPort(FovSideTanMax)); if (ForceZeroIpd) { // ForceZeroIpd does three things: // 1) Sets FOV to maximum symmetrical FOV based on both eyes // 2) Sets eye ViewAdjust values to 0.0 (effective IPD == 0) // 3) Uses only the Left texture for rendering. eyeFov[0] = FovPort::Max(eyeFov[0], eyeFov[1]); eyeFov[1] = eyeFov[0]; Sizei recommenedTexSize = ovrHmd_GetFovTextureSize(Hmd, ovrEye_Left, eyeFov[0], DesiredPixelDensity); Sizei textureSize = EnsureRendertargetAtLeastThisBig(Rendertarget_Left, recommenedTexSize); EyeRenderSize[0] = Sizei::Min(textureSize, recommenedTexSize); EyeRenderSize[1] = EyeRenderSize[0]; // Store texture pointers that will be passed for rendering. EyeTexture[0] = RenderTargets[Rendertarget_Left].Tex; EyeTexture[0].Header.TextureSize = textureSize; EyeTexture[0].Header.RenderViewport = Recti(EyeRenderSize[0]); // Right eye is the same. EyeTexture[1] = EyeTexture[0]; } else { // Configure Stereo settings. Default pixel density is 1.0f. Sizei recommenedTex0Size = ovrHmd_GetFovTextureSize(Hmd, ovrEye_Left, eyeFov[0], DesiredPixelDensity); Sizei recommenedTex1Size = ovrHmd_GetFovTextureSize(Hmd, ovrEye_Right, eyeFov[1], DesiredPixelDensity); if (RendertargetIsSharedByBothEyes) { Sizei rtSize(recommenedTex0Size.w + recommenedTex1Size.w, Alg::Max(recommenedTex0Size.h, recommenedTex1Size.h)); // Use returned size as the actual RT size may be different due to HW limits. rtSize = EnsureRendertargetAtLeastThisBig(Rendertarget_BothEyes, rtSize); // Don't draw more then recommended size; this also ensures that resolution reported // in the overlay HUD size is updated correctly for FOV/pixel density change. EyeRenderSize[0] = Sizei::Min(Sizei(rtSize.w/2, rtSize.h), recommenedTex0Size); EyeRenderSize[1] = Sizei::Min(Sizei(rtSize.w/2, rtSize.h), recommenedTex1Size); // Store texture pointers that will be passed for rendering. // Same texture is used, but with different viewports. EyeTexture[0] = RenderTargets[Rendertarget_BothEyes].Tex; EyeTexture[0].Header.TextureSize = rtSize; EyeTexture[0].Header.RenderViewport = Recti(Vector2i(0), EyeRenderSize[0]); EyeTexture[1] = RenderTargets[Rendertarget_BothEyes].Tex; EyeTexture[1].Header.TextureSize = rtSize; EyeTexture[1].Header.RenderViewport = Recti(Vector2i((rtSize.w+1)/2, 0), EyeRenderSize[1]); } else { Sizei tex0Size = EnsureRendertargetAtLeastThisBig(Rendertarget_Left, recommenedTex0Size); Sizei tex1Size = EnsureRendertargetAtLeastThisBig(Rendertarget_Right, recommenedTex1Size); EyeRenderSize[0] = Sizei::Min(tex0Size, recommenedTex0Size); EyeRenderSize[1] = Sizei::Min(tex1Size, recommenedTex1Size); // Store texture pointers and viewports that will be passed for rendering. EyeTexture[0] = RenderTargets[Rendertarget_Left].Tex; EyeTexture[0].Header.TextureSize = tex0Size; EyeTexture[0].Header.RenderViewport = Recti(EyeRenderSize[0]); EyeTexture[1] = RenderTargets[Rendertarget_Right].Tex; EyeTexture[1].Header.TextureSize = tex1Size; EyeTexture[1].Header.RenderViewport = Recti(EyeRenderSize[1]); } } // Hmd caps. unsigned hmdCaps = (VsyncEnabled ? 0 : ovrHmdCap_NoVSync) | ovrHmdCap_LatencyTest; if (IsLowPersistence) hmdCaps |= ovrHmdCap_LowPersistence; if (DynamicPrediction) hmdCaps |= ovrHmdCap_DynamicPrediction; ovrHmd_SetEnabledCaps(Hmd, hmdCaps); ovrRenderAPIConfig config = pRender->Get_ovrRenderAPIConfig(); unsigned distortionCaps = ovrDistortionCap_Chromatic; if (TimewarpEnabled) distortionCaps |= ovrDistortionCap_TimeWarp; if (!ovrHmd_ConfigureRendering( Hmd, &config, distortionCaps, eyeFov, EyeRenderDesc )) { // Fail exit? TBD return; } if (ForceZeroIpd) { // Remove IPD adjust EyeRenderDesc[0].ViewAdjust = Vector3f(0); EyeRenderDesc[1].ViewAdjust = Vector3f(0); } // ovrHmdCap_LatencyTest - enables internal latency feedback unsigned sensorCaps = ovrSensorCap_Orientation|ovrSensorCap_YawCorrection; if (PositionTrackingEnabled) sensorCaps |= ovrSensorCap_Position; if (StartSensorCaps != sensorCaps) { ovrHmd_StartSensor(Hmd, sensorCaps, 0); StartSensorCaps = sensorCaps; } // Calculate projections Projection[0] = ovrMatrix4f_Projection(EyeRenderDesc[0].Fov, 0.01f, 10000.0f, true); Projection[1] = ovrMatrix4f_Projection(EyeRenderDesc[1].Fov, 0.01f, 10000.0f, true); float orthoDistance = 0.8f; // 2D is 0.8 meter from camera Vector2f orthoScale0 = Vector2f(1.0f) / Vector2f(EyeRenderDesc[0].PixelsPerTanAngleAtCenter); Vector2f orthoScale1 = Vector2f(1.0f) / Vector2f(EyeRenderDesc[1].PixelsPerTanAngleAtCenter); OrthoProjection[0] = ovrMatrix4f_OrthoSubProjection(Projection[0], orthoScale0, orthoDistance, EyeRenderDesc[0].ViewAdjust.x); OrthoProjection[1] = ovrMatrix4f_OrthoSubProjection(Projection[1], orthoScale1, orthoDistance, EyeRenderDesc[1].ViewAdjust.x); }