00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "Util_Render_Stereo.h"
00017
00018 namespace OVR { namespace Util { namespace Render {
00019
00020
00021
00022
00023
00024 float DistortionConfig::DistortionFnInverse(float r)
00025 {
00026 OVR_ASSERT((r <= 10.0f));
00027
00028 float s, d;
00029 float delta = r * 0.25f;
00030
00031 s = r * 0.5f;
00032 d = fabs(r - DistortionFn(s));
00033
00034 for (int i = 0; i < 20; i++)
00035 {
00036 float sUp = s + delta;
00037 float sDown = s - delta;
00038 float dUp = fabs(r - DistortionFn(sUp));
00039 float dDown = fabs(r - DistortionFn(sDown));
00040
00041 if (dUp < d)
00042 {
00043 s = sUp;
00044 d = dUp;
00045 }
00046 else if (dDown < d)
00047 {
00048 s = sDown;
00049 d = dDown;
00050 }
00051 else
00052 {
00053 delta *= 0.5f;
00054 }
00055 }
00056
00057 return s;
00058 }
00059
00060
00061
00062
00063
00064 StereoConfig::StereoConfig(StereoMode mode, const Viewport& vp)
00065 : Mode(mode),
00066 InterpupillaryDistance(0.064f), AspectMultiplier(1.0f),
00067 FullView(vp), DirtyFlag(true), IPDOverride(false),
00068 YFov(0), Aspect(vp.w / float(vp.h)), ProjectionCenterOffset(0),
00069 OrthoPixelOffset(0)
00070 {
00071
00072 Distortion.SetCoefficients(1.0f, 0.22f, 0.24f);
00073 Distortion.Scale = 1.0f;
00074
00075
00076 DistortionFitX = -1.0f;
00077 DistortionFitY = 0.0f;
00078
00079
00080
00081 HMD.HResolution = 1280;
00082 HMD.VResolution = 800;
00083 HMD.HScreenSize = 0.14976f;
00084 HMD.VScreenSize = HMD.HScreenSize / (1280.0f / 800.0f);
00085 HMD.InterpupillaryDistance = InterpupillaryDistance;
00086 HMD.LensSeparationDistance = 0.0635f;
00087 HMD.EyeToScreenDistance = 0.041f;
00088 HMD.DistortionK[0] = Distortion.K[0];
00089 HMD.DistortionK[1] = Distortion.K[1];
00090 HMD.DistortionK[2] = Distortion.K[2];
00091 HMD.DistortionK[3] = 0;
00092
00093 Set2DAreaFov(DegreeToRad(85.0f));
00094 }
00095
00096 void StereoConfig::SetFullViewport(const Viewport& vp)
00097 {
00098 if (vp != FullView)
00099 {
00100 FullView = vp;
00101 DirtyFlag = true;
00102 }
00103 }
00104
00105 void StereoConfig::SetHMDInfo(const HMDInfo& hmd)
00106 {
00107 HMD = hmd;
00108 Distortion.K[0] = hmd.DistortionK[0];
00109 Distortion.K[1] = hmd.DistortionK[1];
00110 Distortion.K[2] = hmd.DistortionK[2];
00111 Distortion.K[3] = hmd.DistortionK[3];
00112
00113 Distortion.SetChromaticAberration(hmd.ChromaAbCorrection[0], hmd.ChromaAbCorrection[1],
00114 hmd.ChromaAbCorrection[2], hmd.ChromaAbCorrection[3]);
00115
00116 if (!IPDOverride)
00117 InterpupillaryDistance = HMD.InterpupillaryDistance;
00118
00119 DirtyFlag = true;
00120 }
00121
00122 void StereoConfig::SetDistortionFitPointVP(float x, float y)
00123 {
00124 DistortionFitX = x;
00125 DistortionFitY = y;
00126 DirtyFlag = true;
00127 }
00128
00129 void StereoConfig::SetDistortionFitPointPixels(float x, float y)
00130 {
00131 DistortionFitX = (4 * x / float(FullView.w)) - 1.0f;
00132 DistortionFitY = (2 * y / float(FullView.h)) - 1.0f;
00133 DirtyFlag = true;
00134 }
00135
00136 void StereoConfig::Set2DAreaFov(float fovRadians)
00137 {
00138 Area2DFov = fovRadians;
00139 DirtyFlag = true;
00140 }
00141
00142
00143 const StereoEyeParams& StereoConfig::GetEyeRenderParams(StereoEye eye)
00144 {
00145 static const UByte eyeParamIndices[3] = { 0, 0, 1 };
00146
00147 updateIfDirty();
00148 OVR_ASSERT(eye < sizeof(eyeParamIndices));
00149 return EyeRenderParams[eyeParamIndices[eye]];
00150 }
00151
00152
00153 void StereoConfig::updateComputedState()
00154 {
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164 Aspect = float(FullView.w) / float(FullView.h);
00165 Aspect *= (Mode == Stereo_None) ? 1.0f : 0.5f;
00166 Aspect *= AspectMultiplier;
00167
00168 updateDistortionOffsetAndScale();
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 if (Mode == Stereo_None)
00188 {
00189 YFov = DegreeToRad(80.0f);
00190 }
00191 else
00192 {
00193 float percievedHalfRTDistance = (HMD.VScreenSize / 2) * Distortion.Scale;
00194 YFov = 2.0f * atan(percievedHalfRTDistance/HMD.EyeToScreenDistance);
00195 }
00196
00197 updateProjectionOffset();
00198 update2D();
00199 updateEyeParams();
00200
00201 DirtyFlag = false;
00202 }
00203
00204 void StereoConfig::updateDistortionOffsetAndScale()
00205 {
00206
00207
00208 float lensOffset = HMD.LensSeparationDistance * 0.5f;
00209 float lensShift = HMD.HScreenSize * 0.25f - lensOffset;
00210 float lensViewportShift = 4.0f * lensShift / HMD.HScreenSize;
00211 Distortion.XCenterOffset= lensViewportShift;
00212
00213
00214
00215 if ((fabs(DistortionFitX) < 0.0001f) && (fabs(DistortionFitY) < 0.0001f))
00216 {
00217 Distortion.Scale = 1.0f;
00218 }
00219 else
00220 {
00221
00222
00223 float stereoAspect = 0.5f * float(FullView.w) / float(FullView.h);
00224 float dx = DistortionFitX - Distortion.XCenterOffset;
00225 float dy = DistortionFitY / stereoAspect;
00226 float fitRadius = sqrt(dx * dx + dy * dy);
00227 Distortion.Scale = Distortion.DistortionFn(fitRadius)/fitRadius;
00228 }
00229 }
00230
00231 void StereoConfig::updateProjectionOffset()
00232 {
00233
00234
00235
00236
00237
00238
00239 float viewCenter = HMD.HScreenSize * 0.25f;
00240 float eyeProjectionShift = viewCenter - HMD.LensSeparationDistance*0.5f;
00241 ProjectionCenterOffset = 4.0f * eyeProjectionShift / HMD.HScreenSize;
00242 }
00243
00244 void StereoConfig::update2D()
00245 {
00246
00247
00248
00249
00250
00251 float metersToPixels = (HMD.HResolution / HMD.HScreenSize);
00252 float lensDistanceScreenPixels= metersToPixels * HMD.LensSeparationDistance;
00253 float eyeDistanceScreenPixels = metersToPixels * InterpupillaryDistance;
00254 float offCenterShiftPixels = (HMD.EyeToScreenDistance / 0.8f) * eyeDistanceScreenPixels;
00255 float leftPixelCenter = (HMD.HResolution / 2) - lensDistanceScreenPixels * 0.5f;
00256 float rightPixelCenter = lensDistanceScreenPixels * 0.5f;
00257 float pixelDifference = leftPixelCenter - rightPixelCenter;
00258
00259
00260
00261 float percievedHalfScreenDistance = tan(Area2DFov * 0.5f) * HMD.EyeToScreenDistance;
00262 float vfovSize = 2.0f * percievedHalfScreenDistance / Distortion.Scale;
00263 FovPixels = HMD.VResolution * vfovSize / HMD.VScreenSize;
00264
00265
00266 Matrix4f& m = OrthoCenter;
00267 m.SetIdentity();
00268 m.M[0][0] = FovPixels / (FullView.w * 0.5f);
00269 m.M[1][1] = -FovPixels / FullView.h;
00270 m.M[0][3] = 0;
00271 m.M[1][3] = 0;
00272 m.M[2][2] = 0;
00273
00274 float orthoPixelOffset = (pixelDifference + offCenterShiftPixels/Distortion.Scale) * 0.5f;
00275 OrthoPixelOffset = orthoPixelOffset * 2.0f / FovPixels;
00276 }
00277
00278 void StereoConfig::updateEyeParams()
00279 {
00280
00281 Matrix4f projCenter = Matrix4f::PerspectiveRH(YFov, Aspect, 0.01f, 1000.0f);
00282
00283 switch(Mode)
00284 {
00285 case Stereo_None:
00286 {
00287 EyeRenderParams[0].Init(StereoEye_Center, FullView, 0, projCenter, OrthoCenter);
00288 }
00289 break;
00290
00291 case Stereo_LeftRight_Multipass:
00292 {
00293 Matrix4f projLeft = Matrix4f::Translation(ProjectionCenterOffset, 0, 0) * projCenter,
00294 projRight = Matrix4f::Translation(-ProjectionCenterOffset, 0, 0) * projCenter;
00295
00296 EyeRenderParams[0].Init(StereoEye_Left,
00297 Viewport(FullView.x, FullView.y, FullView.w/2, FullView.h),
00298 +InterpupillaryDistance * 0.5f,
00299 projLeft, OrthoCenter * Matrix4f::Translation(OrthoPixelOffset, 0, 0),
00300 &Distortion);
00301 EyeRenderParams[1].Init(StereoEye_Right,
00302 Viewport(FullView.x + FullView.w/2, FullView.y, FullView.w/2, FullView.h),
00303 -InterpupillaryDistance * 0.5f,
00304 projRight, OrthoCenter * Matrix4f::Translation(-OrthoPixelOffset, 0, 0),
00305 &Distortion);
00306 }
00307 break;
00308 }
00309
00310 }
00311
00312
00313 }}}
00314