oculus1
diff libovr/Src/Util/Util_Render_Stereo.cpp @ 3:b069a5c27388
added a couple more stuff, fixed all the LibOVR line endings
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 15 Sep 2013 04:10:05 +0300 |
parents | e2f9e4603129 |
children |
line diff
1.1 --- a/libovr/Src/Util/Util_Render_Stereo.cpp Sat Sep 14 17:51:03 2013 +0300 1.2 +++ b/libovr/Src/Util/Util_Render_Stereo.cpp Sun Sep 15 04:10:05 2013 +0300 1.3 @@ -1,1 +1,314 @@ 1.4 -/************************************************************************************ 1.5 1.6 Filename : Util_Render_Stereo.cpp 1.7 Content : Stereo rendering configuration implementation 1.8 Created : October 22, 2012 1.9 Authors : Michael Antonov, Andrew Reisse 1.10 1.11 Copyright : Copyright 2012 Oculus, Inc. All Rights reserved. 1.12 1.13 Use of this software is subject to the terms of the Oculus Inc license 1.14 agreement provided at the time of installation or download, or which 1.15 otherwise accompanies this software in either electronic or hard copy form. 1.16 1.17 *************************************************************************************/ 1.18 1.19 #include "Util_Render_Stereo.h" 1.20 1.21 namespace OVR { namespace Util { namespace Render { 1.22 1.23 1.24 //----------------------------------------------------------------------------------- 1.25 1.26 // DistortionFnInverse computes the inverse of the distortion function on an argument. 1.27 float DistortionConfig::DistortionFnInverse(float r) 1.28 { 1.29 OVR_ASSERT((r <= 10.0f)); 1.30 1.31 float s, d; 1.32 float delta = r * 0.25f; 1.33 1.34 s = r * 0.5f; 1.35 d = fabs(r - DistortionFn(s)); 1.36 1.37 for (int i = 0; i < 20; i++) 1.38 { 1.39 float sUp = s + delta; 1.40 float sDown = s - delta; 1.41 float dUp = fabs(r - DistortionFn(sUp)); 1.42 float dDown = fabs(r - DistortionFn(sDown)); 1.43 1.44 if (dUp < d) 1.45 { 1.46 s = sUp; 1.47 d = dUp; 1.48 } 1.49 else if (dDown < d) 1.50 { 1.51 s = sDown; 1.52 d = dDown; 1.53 } 1.54 else 1.55 { 1.56 delta *= 0.5f; 1.57 } 1.58 } 1.59 1.60 return s; 1.61 } 1.62 1.63 1.64 //----------------------------------------------------------------------------------- 1.65 // **** StereoConfig Implementation 1.66 1.67 StereoConfig::StereoConfig(StereoMode mode, const Viewport& vp) 1.68 : Mode(mode), 1.69 InterpupillaryDistance(0.064f), AspectMultiplier(1.0f), 1.70 FullView(vp), DirtyFlag(true), IPDOverride(false), 1.71 YFov(0), Aspect(vp.w / float(vp.h)), ProjectionCenterOffset(0), 1.72 OrthoPixelOffset(0) 1.73 { 1.74 // And default distortion for it. 1.75 Distortion.SetCoefficients(1.0f, 0.22f, 0.24f); 1.76 Distortion.Scale = 1.0f; // Will be computed later. 1.77 1.78 // Fit left of the image. 1.79 DistortionFitX = -1.0f; 1.80 DistortionFitY = 0.0f; 1.81 1.82 // Initialize "fake" default HMD values for testing without HMD plugged in. 1.83 // These default values match those returned by the HMD. 1.84 HMD.HResolution = 1280; 1.85 HMD.VResolution = 800; 1.86 HMD.HScreenSize = 0.14976f; 1.87 HMD.VScreenSize = HMD.HScreenSize / (1280.0f / 800.0f); 1.88 HMD.InterpupillaryDistance = InterpupillaryDistance; 1.89 HMD.LensSeparationDistance = 0.0635f; 1.90 HMD.EyeToScreenDistance = 0.041f; 1.91 HMD.DistortionK[0] = Distortion.K[0]; 1.92 HMD.DistortionK[1] = Distortion.K[1]; 1.93 HMD.DistortionK[2] = Distortion.K[2]; 1.94 HMD.DistortionK[3] = 0; 1.95 1.96 Set2DAreaFov(DegreeToRad(85.0f)); 1.97 } 1.98 1.99 void StereoConfig::SetFullViewport(const Viewport& vp) 1.100 { 1.101 if (vp != FullView) 1.102 { 1.103 FullView = vp; 1.104 DirtyFlag = true; 1.105 } 1.106 } 1.107 1.108 void StereoConfig::SetHMDInfo(const HMDInfo& hmd) 1.109 { 1.110 HMD = hmd; 1.111 Distortion.K[0] = hmd.DistortionK[0]; 1.112 Distortion.K[1] = hmd.DistortionK[1]; 1.113 Distortion.K[2] = hmd.DistortionK[2]; 1.114 Distortion.K[3] = hmd.DistortionK[3]; 1.115 1.116 Distortion.SetChromaticAberration(hmd.ChromaAbCorrection[0], hmd.ChromaAbCorrection[1], 1.117 hmd.ChromaAbCorrection[2], hmd.ChromaAbCorrection[3]); 1.118 1.119 if (!IPDOverride) 1.120 InterpupillaryDistance = HMD.InterpupillaryDistance; 1.121 1.122 DirtyFlag = true; 1.123 } 1.124 1.125 void StereoConfig::SetDistortionFitPointVP(float x, float y) 1.126 { 1.127 DistortionFitX = x; 1.128 DistortionFitY = y; 1.129 DirtyFlag = true; 1.130 } 1.131 1.132 void StereoConfig::SetDistortionFitPointPixels(float x, float y) 1.133 { 1.134 DistortionFitX = (4 * x / float(FullView.w)) - 1.0f; 1.135 DistortionFitY = (2 * y / float(FullView.h)) - 1.0f; 1.136 DirtyFlag = true; 1.137 } 1.138 1.139 void StereoConfig::Set2DAreaFov(float fovRadians) 1.140 { 1.141 Area2DFov = fovRadians; 1.142 DirtyFlag = true; 1.143 } 1.144 1.145 1.146 const StereoEyeParams& StereoConfig::GetEyeRenderParams(StereoEye eye) 1.147 { 1.148 static const UByte eyeParamIndices[3] = { 0, 0, 1 }; 1.149 1.150 updateIfDirty(); 1.151 OVR_ASSERT(eye < sizeof(eyeParamIndices)); 1.152 return EyeRenderParams[eyeParamIndices[eye]]; 1.153 } 1.154 1.155 1.156 void StereoConfig::updateComputedState() 1.157 { 1.158 // Need to compute all of the following: 1.159 // - Aspect Ratio 1.160 // - FOV 1.161 // - Projection offsets for 3D 1.162 // - Distortion XCenterOffset 1.163 // - Update 2D 1.164 // - Initialize EyeRenderParams 1.165 1.166 // Compute aspect ratio. Stereo mode cuts width in half. 1.167 Aspect = float(FullView.w) / float(FullView.h); 1.168 Aspect *= (Mode == Stereo_None) ? 1.0f : 0.5f; 1.169 Aspect *= AspectMultiplier; 1.170 1.171 updateDistortionOffsetAndScale(); 1.172 1.173 // Compute Vertical FOV based on distance, distortion, etc. 1.174 // Distance from vertical center to render vertical edge perceived through the lens. 1.175 // This will be larger then normal screen size due to magnification & distortion. 1.176 // 1.177 // This percievedHalfRTDistance equation should hold as long as the render target 1.178 // and display have the same aspect ratios. What we'd like to know is where the edge 1.179 // of the render target will on the perceived screen surface. With NO LENS, 1.180 // the answer would be: 1.181 // 1.182 // halfRTDistance = (VScreenSize / 2) * aspect * 1.183 // DistortionFn_Inverse( DistortionScale / aspect ) 1.184 // 1.185 // To model the optical lens we eliminates DistortionFn_Inverse. Aspect ratios 1.186 // cancel out, so we get: 1.187 // 1.188 // halfRTDistance = (VScreenSize / 2) * DistortionScale 1.189 // 1.190 if (Mode == Stereo_None) 1.191 { 1.192 YFov = DegreeToRad(80.0f); 1.193 } 1.194 else 1.195 { 1.196 float percievedHalfRTDistance = (HMD.VScreenSize / 2) * Distortion.Scale; 1.197 YFov = 2.0f * atan(percievedHalfRTDistance/HMD.EyeToScreenDistance); 1.198 } 1.199 1.200 updateProjectionOffset(); 1.201 update2D(); 1.202 updateEyeParams(); 1.203 1.204 DirtyFlag = false; 1.205 } 1.206 1.207 void StereoConfig::updateDistortionOffsetAndScale() 1.208 { 1.209 // Distortion center shift is stored separately, since it isn't affected 1.210 // by the eye distance. 1.211 float lensOffset = HMD.LensSeparationDistance * 0.5f; 1.212 float lensShift = HMD.HScreenSize * 0.25f - lensOffset; 1.213 float lensViewportShift = 4.0f * lensShift / HMD.HScreenSize; 1.214 Distortion.XCenterOffset= lensViewportShift; 1.215 1.216 // Compute distortion scale from DistortionFitX & DistortionFitY. 1.217 // Fit value of 0.0 means "no fit". 1.218 if ((fabs(DistortionFitX) < 0.0001f) && (fabs(DistortionFitY) < 0.0001f)) 1.219 { 1.220 Distortion.Scale = 1.0f; 1.221 } 1.222 else 1.223 { 1.224 // Convert fit value to distortion-centered coordinates before fit radius 1.225 // calculation. 1.226 float stereoAspect = 0.5f * float(FullView.w) / float(FullView.h); 1.227 float dx = DistortionFitX - Distortion.XCenterOffset; 1.228 float dy = DistortionFitY / stereoAspect; 1.229 float fitRadius = sqrt(dx * dx + dy * dy); 1.230 Distortion.Scale = Distortion.DistortionFn(fitRadius)/fitRadius; 1.231 } 1.232 } 1.233 1.234 void StereoConfig::updateProjectionOffset() 1.235 { 1.236 // Post-projection viewport coordinates range from (-1.0, 1.0), with the 1.237 // center of the left viewport falling at (1/4) of horizontal screen size. 1.238 // We need to shift this projection center to match with the lens center; 1.239 // note that we don't use the IPD here due to collimated light property of the lens. 1.240 // We compute this shift in physical units (meters) to 1.241 // correct for different screen sizes and then rescale to viewport coordinates. 1.242 float viewCenter = HMD.HScreenSize * 0.25f; 1.243 float eyeProjectionShift = viewCenter - HMD.LensSeparationDistance*0.5f; 1.244 ProjectionCenterOffset = 4.0f * eyeProjectionShift / HMD.HScreenSize; 1.245 } 1.246 1.247 void StereoConfig::update2D() 1.248 { 1.249 // Orthographic projection fakes a screen at a distance of 0.8m from the 1.250 // eye, where hmd screen projection surface is at 0.05m distance. 1.251 // This introduces an extra off-center pixel projection shift based on eye distance. 1.252 // This offCenterShift is the pixel offset of the other camera's center 1.253 // in your reference camera based on surface distance. 1.254 float metersToPixels = (HMD.HResolution / HMD.HScreenSize); 1.255 float lensDistanceScreenPixels= metersToPixels * HMD.LensSeparationDistance; 1.256 float eyeDistanceScreenPixels = metersToPixels * InterpupillaryDistance; 1.257 float offCenterShiftPixels = (HMD.EyeToScreenDistance / 0.8f) * eyeDistanceScreenPixels; 1.258 float leftPixelCenter = (HMD.HResolution / 2) - lensDistanceScreenPixels * 0.5f; 1.259 float rightPixelCenter = lensDistanceScreenPixels * 0.5f; 1.260 float pixelDifference = leftPixelCenter - rightPixelCenter; 1.261 1.262 // This computes the number of pixels that fit within specified 2D FOV (assuming 1.263 // distortion scaling will be done). 1.264 float percievedHalfScreenDistance = tan(Area2DFov * 0.5f) * HMD.EyeToScreenDistance; 1.265 float vfovSize = 2.0f * percievedHalfScreenDistance / Distortion.Scale; 1.266 FovPixels = HMD.VResolution * vfovSize / HMD.VScreenSize; 1.267 1.268 // Create orthographic matrix. 1.269 Matrix4f& m = OrthoCenter; 1.270 m.SetIdentity(); 1.271 m.M[0][0] = FovPixels / (FullView.w * 0.5f); 1.272 m.M[1][1] = -FovPixels / FullView.h; 1.273 m.M[0][3] = 0; 1.274 m.M[1][3] = 0; 1.275 m.M[2][2] = 0; 1.276 1.277 float orthoPixelOffset = (pixelDifference + offCenterShiftPixels/Distortion.Scale) * 0.5f; 1.278 OrthoPixelOffset = orthoPixelOffset * 2.0f / FovPixels; 1.279 } 1.280 1.281 void StereoConfig::updateEyeParams() 1.282 { 1.283 // Projection matrix for the center eye, which the left/right matrices are based on. 1.284 Matrix4f projCenter = Matrix4f::PerspectiveRH(YFov, Aspect, 0.01f, 2000.0f); 1.285 1.286 switch(Mode) 1.287 { 1.288 case Stereo_None: 1.289 { 1.290 EyeRenderParams[0].Init(StereoEye_Center, FullView, 0, projCenter, OrthoCenter); 1.291 } 1.292 break; 1.293 1.294 case Stereo_LeftRight_Multipass: 1.295 { 1.296 Matrix4f projLeft = Matrix4f::Translation(ProjectionCenterOffset, 0, 0) * projCenter, 1.297 projRight = Matrix4f::Translation(-ProjectionCenterOffset, 0, 0) * projCenter; 1.298 1.299 EyeRenderParams[0].Init(StereoEye_Left, 1.300 Viewport(FullView.x, FullView.y, FullView.w/2, FullView.h), 1.301 +InterpupillaryDistance * 0.5f, // World view shift. 1.302 projLeft, OrthoCenter * Matrix4f::Translation(OrthoPixelOffset, 0, 0), 1.303 &Distortion); 1.304 EyeRenderParams[1].Init(StereoEye_Right, 1.305 Viewport(FullView.x + FullView.w/2, FullView.y, FullView.w/2, FullView.h), 1.306 -InterpupillaryDistance * 0.5f, 1.307 projRight, OrthoCenter * Matrix4f::Translation(-OrthoPixelOffset, 0, 0), 1.308 &Distortion); 1.309 } 1.310 break; 1.311 } 1.312 1.313 } 1.314 1.315 1.316 }}} // OVR::Util::Render 1.317 1.318 \ No newline at end of file 1.319 +/************************************************************************************ 1.320 + 1.321 +Filename : Util_Render_Stereo.cpp 1.322 +Content : Stereo rendering configuration implementation 1.323 +Created : October 22, 2012 1.324 +Authors : Michael Antonov, Andrew Reisse 1.325 + 1.326 +Copyright : Copyright 2012 Oculus, Inc. All Rights reserved. 1.327 + 1.328 +Use of this software is subject to the terms of the Oculus Inc license 1.329 +agreement provided at the time of installation or download, or which 1.330 +otherwise accompanies this software in either electronic or hard copy form. 1.331 + 1.332 +*************************************************************************************/ 1.333 + 1.334 +#include "Util_Render_Stereo.h" 1.335 + 1.336 +namespace OVR { namespace Util { namespace Render { 1.337 + 1.338 + 1.339 +//----------------------------------------------------------------------------------- 1.340 + 1.341 +// DistortionFnInverse computes the inverse of the distortion function on an argument. 1.342 +float DistortionConfig::DistortionFnInverse(float r) 1.343 +{ 1.344 + OVR_ASSERT((r <= 10.0f)); 1.345 + 1.346 + float s, d; 1.347 + float delta = r * 0.25f; 1.348 + 1.349 + s = r * 0.5f; 1.350 + d = fabs(r - DistortionFn(s)); 1.351 + 1.352 + for (int i = 0; i < 20; i++) 1.353 + { 1.354 + float sUp = s + delta; 1.355 + float sDown = s - delta; 1.356 + float dUp = fabs(r - DistortionFn(sUp)); 1.357 + float dDown = fabs(r - DistortionFn(sDown)); 1.358 + 1.359 + if (dUp < d) 1.360 + { 1.361 + s = sUp; 1.362 + d = dUp; 1.363 + } 1.364 + else if (dDown < d) 1.365 + { 1.366 + s = sDown; 1.367 + d = dDown; 1.368 + } 1.369 + else 1.370 + { 1.371 + delta *= 0.5f; 1.372 + } 1.373 + } 1.374 + 1.375 + return s; 1.376 +} 1.377 + 1.378 + 1.379 +//----------------------------------------------------------------------------------- 1.380 +// **** StereoConfig Implementation 1.381 + 1.382 +StereoConfig::StereoConfig(StereoMode mode, const Viewport& vp) 1.383 + : Mode(mode), 1.384 + InterpupillaryDistance(0.064f), AspectMultiplier(1.0f), 1.385 + FullView(vp), DirtyFlag(true), IPDOverride(false), 1.386 + YFov(0), Aspect(vp.w / float(vp.h)), ProjectionCenterOffset(0), 1.387 + OrthoPixelOffset(0) 1.388 +{ 1.389 + // And default distortion for it. 1.390 + Distortion.SetCoefficients(1.0f, 0.22f, 0.24f); 1.391 + Distortion.Scale = 1.0f; // Will be computed later. 1.392 + 1.393 + // Fit left of the image. 1.394 + DistortionFitX = -1.0f; 1.395 + DistortionFitY = 0.0f; 1.396 + 1.397 + // Initialize "fake" default HMD values for testing without HMD plugged in. 1.398 + // These default values match those returned by the HMD. 1.399 + HMD.HResolution = 1280; 1.400 + HMD.VResolution = 800; 1.401 + HMD.HScreenSize = 0.14976f; 1.402 + HMD.VScreenSize = HMD.HScreenSize / (1280.0f / 800.0f); 1.403 + HMD.InterpupillaryDistance = InterpupillaryDistance; 1.404 + HMD.LensSeparationDistance = 0.0635f; 1.405 + HMD.EyeToScreenDistance = 0.041f; 1.406 + HMD.DistortionK[0] = Distortion.K[0]; 1.407 + HMD.DistortionK[1] = Distortion.K[1]; 1.408 + HMD.DistortionK[2] = Distortion.K[2]; 1.409 + HMD.DistortionK[3] = 0; 1.410 + 1.411 + Set2DAreaFov(DegreeToRad(85.0f)); 1.412 +} 1.413 + 1.414 +void StereoConfig::SetFullViewport(const Viewport& vp) 1.415 +{ 1.416 + if (vp != FullView) 1.417 + { 1.418 + FullView = vp; 1.419 + DirtyFlag = true; 1.420 + } 1.421 +} 1.422 + 1.423 +void StereoConfig::SetHMDInfo(const HMDInfo& hmd) 1.424 +{ 1.425 + HMD = hmd; 1.426 + Distortion.K[0] = hmd.DistortionK[0]; 1.427 + Distortion.K[1] = hmd.DistortionK[1]; 1.428 + Distortion.K[2] = hmd.DistortionK[2]; 1.429 + Distortion.K[3] = hmd.DistortionK[3]; 1.430 + 1.431 + Distortion.SetChromaticAberration(hmd.ChromaAbCorrection[0], hmd.ChromaAbCorrection[1], 1.432 + hmd.ChromaAbCorrection[2], hmd.ChromaAbCorrection[3]); 1.433 + 1.434 + if (!IPDOverride) 1.435 + InterpupillaryDistance = HMD.InterpupillaryDistance; 1.436 + 1.437 + DirtyFlag = true; 1.438 +} 1.439 + 1.440 +void StereoConfig::SetDistortionFitPointVP(float x, float y) 1.441 +{ 1.442 + DistortionFitX = x; 1.443 + DistortionFitY = y; 1.444 + DirtyFlag = true; 1.445 +} 1.446 + 1.447 +void StereoConfig::SetDistortionFitPointPixels(float x, float y) 1.448 +{ 1.449 + DistortionFitX = (4 * x / float(FullView.w)) - 1.0f; 1.450 + DistortionFitY = (2 * y / float(FullView.h)) - 1.0f; 1.451 + DirtyFlag = true; 1.452 +} 1.453 + 1.454 +void StereoConfig::Set2DAreaFov(float fovRadians) 1.455 +{ 1.456 + Area2DFov = fovRadians; 1.457 + DirtyFlag = true; 1.458 +} 1.459 + 1.460 + 1.461 +const StereoEyeParams& StereoConfig::GetEyeRenderParams(StereoEye eye) 1.462 +{ 1.463 + static const UByte eyeParamIndices[3] = { 0, 0, 1 }; 1.464 + 1.465 + updateIfDirty(); 1.466 + OVR_ASSERT(eye < sizeof(eyeParamIndices)); 1.467 + return EyeRenderParams[eyeParamIndices[eye]]; 1.468 +} 1.469 + 1.470 + 1.471 +void StereoConfig::updateComputedState() 1.472 +{ 1.473 + // Need to compute all of the following: 1.474 + // - Aspect Ratio 1.475 + // - FOV 1.476 + // - Projection offsets for 3D 1.477 + // - Distortion XCenterOffset 1.478 + // - Update 2D 1.479 + // - Initialize EyeRenderParams 1.480 + 1.481 + // Compute aspect ratio. Stereo mode cuts width in half. 1.482 + Aspect = float(FullView.w) / float(FullView.h); 1.483 + Aspect *= (Mode == Stereo_None) ? 1.0f : 0.5f; 1.484 + Aspect *= AspectMultiplier; 1.485 + 1.486 + updateDistortionOffsetAndScale(); 1.487 + 1.488 + // Compute Vertical FOV based on distance, distortion, etc. 1.489 + // Distance from vertical center to render vertical edge perceived through the lens. 1.490 + // This will be larger then normal screen size due to magnification & distortion. 1.491 + // 1.492 + // This percievedHalfRTDistance equation should hold as long as the render target 1.493 + // and display have the same aspect ratios. What we'd like to know is where the edge 1.494 + // of the render target will on the perceived screen surface. With NO LENS, 1.495 + // the answer would be: 1.496 + // 1.497 + // halfRTDistance = (VScreenSize / 2) * aspect * 1.498 + // DistortionFn_Inverse( DistortionScale / aspect ) 1.499 + // 1.500 + // To model the optical lens we eliminates DistortionFn_Inverse. Aspect ratios 1.501 + // cancel out, so we get: 1.502 + // 1.503 + // halfRTDistance = (VScreenSize / 2) * DistortionScale 1.504 + // 1.505 + if (Mode == Stereo_None) 1.506 + { 1.507 + YFov = DegreeToRad(80.0f); 1.508 + } 1.509 + else 1.510 + { 1.511 + float percievedHalfRTDistance = (HMD.VScreenSize / 2) * Distortion.Scale; 1.512 + YFov = 2.0f * atan(percievedHalfRTDistance/HMD.EyeToScreenDistance); 1.513 + } 1.514 + 1.515 + updateProjectionOffset(); 1.516 + update2D(); 1.517 + updateEyeParams(); 1.518 + 1.519 + DirtyFlag = false; 1.520 +} 1.521 + 1.522 +void StereoConfig::updateDistortionOffsetAndScale() 1.523 +{ 1.524 + // Distortion center shift is stored separately, since it isn't affected 1.525 + // by the eye distance. 1.526 + float lensOffset = HMD.LensSeparationDistance * 0.5f; 1.527 + float lensShift = HMD.HScreenSize * 0.25f - lensOffset; 1.528 + float lensViewportShift = 4.0f * lensShift / HMD.HScreenSize; 1.529 + Distortion.XCenterOffset= lensViewportShift; 1.530 + 1.531 + // Compute distortion scale from DistortionFitX & DistortionFitY. 1.532 + // Fit value of 0.0 means "no fit". 1.533 + if ((fabs(DistortionFitX) < 0.0001f) && (fabs(DistortionFitY) < 0.0001f)) 1.534 + { 1.535 + Distortion.Scale = 1.0f; 1.536 + } 1.537 + else 1.538 + { 1.539 + // Convert fit value to distortion-centered coordinates before fit radius 1.540 + // calculation. 1.541 + float stereoAspect = 0.5f * float(FullView.w) / float(FullView.h); 1.542 + float dx = DistortionFitX - Distortion.XCenterOffset; 1.543 + float dy = DistortionFitY / stereoAspect; 1.544 + float fitRadius = sqrt(dx * dx + dy * dy); 1.545 + Distortion.Scale = Distortion.DistortionFn(fitRadius)/fitRadius; 1.546 + } 1.547 +} 1.548 + 1.549 +void StereoConfig::updateProjectionOffset() 1.550 +{ 1.551 + // Post-projection viewport coordinates range from (-1.0, 1.0), with the 1.552 + // center of the left viewport falling at (1/4) of horizontal screen size. 1.553 + // We need to shift this projection center to match with the lens center; 1.554 + // note that we don't use the IPD here due to collimated light property of the lens. 1.555 + // We compute this shift in physical units (meters) to 1.556 + // correct for different screen sizes and then rescale to viewport coordinates. 1.557 + float viewCenter = HMD.HScreenSize * 0.25f; 1.558 + float eyeProjectionShift = viewCenter - HMD.LensSeparationDistance*0.5f; 1.559 + ProjectionCenterOffset = 4.0f * eyeProjectionShift / HMD.HScreenSize; 1.560 +} 1.561 + 1.562 +void StereoConfig::update2D() 1.563 +{ 1.564 + // Orthographic projection fakes a screen at a distance of 0.8m from the 1.565 + // eye, where hmd screen projection surface is at 0.05m distance. 1.566 + // This introduces an extra off-center pixel projection shift based on eye distance. 1.567 + // This offCenterShift is the pixel offset of the other camera's center 1.568 + // in your reference camera based on surface distance. 1.569 + float metersToPixels = (HMD.HResolution / HMD.HScreenSize); 1.570 + float lensDistanceScreenPixels= metersToPixels * HMD.LensSeparationDistance; 1.571 + float eyeDistanceScreenPixels = metersToPixels * InterpupillaryDistance; 1.572 + float offCenterShiftPixels = (HMD.EyeToScreenDistance / 0.8f) * eyeDistanceScreenPixels; 1.573 + float leftPixelCenter = (HMD.HResolution / 2) - lensDistanceScreenPixels * 0.5f; 1.574 + float rightPixelCenter = lensDistanceScreenPixels * 0.5f; 1.575 + float pixelDifference = leftPixelCenter - rightPixelCenter; 1.576 + 1.577 + // This computes the number of pixels that fit within specified 2D FOV (assuming 1.578 + // distortion scaling will be done). 1.579 + float percievedHalfScreenDistance = tan(Area2DFov * 0.5f) * HMD.EyeToScreenDistance; 1.580 + float vfovSize = 2.0f * percievedHalfScreenDistance / Distortion.Scale; 1.581 + FovPixels = HMD.VResolution * vfovSize / HMD.VScreenSize; 1.582 + 1.583 + // Create orthographic matrix. 1.584 + Matrix4f& m = OrthoCenter; 1.585 + m.SetIdentity(); 1.586 + m.M[0][0] = FovPixels / (FullView.w * 0.5f); 1.587 + m.M[1][1] = -FovPixels / FullView.h; 1.588 + m.M[0][3] = 0; 1.589 + m.M[1][3] = 0; 1.590 + m.M[2][2] = 0; 1.591 + 1.592 + float orthoPixelOffset = (pixelDifference + offCenterShiftPixels/Distortion.Scale) * 0.5f; 1.593 + OrthoPixelOffset = orthoPixelOffset * 2.0f / FovPixels; 1.594 +} 1.595 + 1.596 +void StereoConfig::updateEyeParams() 1.597 +{ 1.598 + // Projection matrix for the center eye, which the left/right matrices are based on. 1.599 + Matrix4f projCenter = Matrix4f::PerspectiveRH(YFov, Aspect, 0.01f, 2000.0f); 1.600 + 1.601 + switch(Mode) 1.602 + { 1.603 + case Stereo_None: 1.604 + { 1.605 + EyeRenderParams[0].Init(StereoEye_Center, FullView, 0, projCenter, OrthoCenter); 1.606 + } 1.607 + break; 1.608 + 1.609 + case Stereo_LeftRight_Multipass: 1.610 + { 1.611 + Matrix4f projLeft = Matrix4f::Translation(ProjectionCenterOffset, 0, 0) * projCenter, 1.612 + projRight = Matrix4f::Translation(-ProjectionCenterOffset, 0, 0) * projCenter; 1.613 + 1.614 + EyeRenderParams[0].Init(StereoEye_Left, 1.615 + Viewport(FullView.x, FullView.y, FullView.w/2, FullView.h), 1.616 + +InterpupillaryDistance * 0.5f, // World view shift. 1.617 + projLeft, OrthoCenter * Matrix4f::Translation(OrthoPixelOffset, 0, 0), 1.618 + &Distortion); 1.619 + EyeRenderParams[1].Init(StereoEye_Right, 1.620 + Viewport(FullView.x + FullView.w/2, FullView.y, FullView.w/2, FullView.h), 1.621 + -InterpupillaryDistance * 0.5f, 1.622 + projRight, OrthoCenter * Matrix4f::Translation(-OrthoPixelOffset, 0, 0), 1.623 + &Distortion); 1.624 + } 1.625 + break; 1.626 + } 1.627 + 1.628 +} 1.629 + 1.630 + 1.631 +}}} // OVR::Util::Render 1.632 +