diff --git a/modules/gfx/pymod/__init__.py b/modules/gfx/pymod/__init__.py index 11fb994719d9243b29256afa445a0f5b488a82b5..23dced4ecc5dde872ac4a63574a38b7437563acc 100644 --- a/modules/gfx/pymod/__init__.py +++ b/modules/gfx/pymod/__init__.py @@ -62,8 +62,8 @@ def Stereo(mode,flip=None,alg=None): _gfx.Scene().SetStereoFlip(flip) if(alg): _gfx.Scene().SetStereoAlg(alg) - if(mode): - _gfx.Scene().SetStereoMode(mode) + + _gfx.Scene().SetStereoMode(mode) def FitToScreen(gfx_ent, width=None, height=None, margin=0.01): """ diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc index eb9ffe8401cad5560b59e4d34e3ed330d18b4ec7..c3acaddc618d1ce7a394a04fce3349cb0c379195 100644 --- a/modules/gfx/src/scene.cc +++ b/modules/gfx/src/scene.cc @@ -111,6 +111,8 @@ Scene::Scene(): fog_flag_(true), fog_color_(0.0,0.0,0.0,0.0), auto_autoslab_(true), + do_autoslab_(true), + do_autoslab_fast_(true), offscreen_flag_(false), main_offscreen_buffer_(0), old_vp_(), @@ -127,8 +129,8 @@ Scene::Scene(): stereo_alg_(0), stereo_inverted_(false), stereo_eye_(0), - stereo_iod_(40.0), - stereo_distance_(100.0), + stereo_iod_(4.0), + stereo_distance_(0.0), scene_left_tex_(), scene_right_tex_() { @@ -633,7 +635,10 @@ void draw_lightdir(const Vec3& ldir, const mol::Transform& tf) void Scene::RenderGL() { - if(auto_autoslab_) Autoslab(false, false); + if(auto_autoslab_ || do_autoslab_) { + do_autoslab(); + do_autoslab_=false; + } prep_blur(); @@ -762,6 +767,7 @@ void Scene::Add(const GfxNodeP& n, bool redraw) if(go) { SetCenter(go->GetCenter()); } + do_autoslab_=true; } root_node_->Add(n); @@ -1310,7 +1316,7 @@ void Scene::SetStereoView(int m) RequestRedraw(); } -void Scene::SetStereoIOD(float d) +void Scene::SetStereoIOD(Real d) { stereo_iod_=d; if(stereo_mode_>0) { @@ -1318,7 +1324,7 @@ void Scene::SetStereoIOD(float d) } } -void Scene::SetStereoDistance(float d) +void Scene::SetStereoDistance(Real d) { stereo_distance_=d; if(stereo_mode_>0) { @@ -1329,6 +1335,9 @@ void Scene::SetStereoDistance(float d) void Scene::SetStereoAlg(unsigned int a) { stereo_alg_=a; + if(stereo_alg_<0 || stereo_alg_>1) { + stereo_alg_=0; + } if(stereo_mode_>0) { RequestRedraw(); } @@ -1592,37 +1601,10 @@ public: } // anon ns -void Scene::Autoslab(bool fast, bool update) +void Scene::Autoslab(bool fast, bool) { - if(fast) { - geom::AlignedCuboid bb =this->GetBoundingBox(transform_); - // necessary code duplication due to awkward slab limit impl - znear_=-(bb.GetMax()[2]-1.0); - zfar_=-(bb.GetMin()[2]+1.0); - set_near(-(bb.GetMax()[2]-1.0)); - set_far(-(bb.GetMin()[2]+1.0)); - ResetProjection(); - } else { - LimCalc limcalc; - limcalc.transform=transform_; - limcalc.minc = Vec3(std::numeric_limits<float>::max(), - std::numeric_limits<float>::max(), - std::numeric_limits<float>::max()); - limcalc.maxc = Vec3(-std::numeric_limits<float>::max(), - -std::numeric_limits<float>::max(), - -std::numeric_limits<float>::max()); - this->Apply(limcalc); - float mynear=std::max(float(0.0), std::min(float(-limcalc.minc[2]),float(-limcalc.maxc[2])))-float(2.0); - float myfar=std::max(float(-limcalc.minc[2]),float(-limcalc.maxc[2]))+float(2.0); - znear_=mynear; - zfar_=myfar; - set_near(znear_); - set_far(zfar_); - ResetProjection(); - } - if (update) { - this->RequestRedraw(); - } + do_autoslab_=true; + do_autoslab_fast_=fast; } void Scene::AutoslabMax() @@ -1827,38 +1809,47 @@ void Scene::stereo_projection(int view) glLoadIdentity(); Real zn=std::max<Real>(1.0,znear_); - Real zf=std::max<Real>(1.1,zfar_); - + Real zf=std::max<Real>(1.2,zfar_); Real top = zn * std::tan(fov_*M_PI/360.0); Real bot = -top; - Real right = top*aspect_ratio_; - Real left = -right; - - glFrustum(left,right,bot,top,zn,zf); - + Real left = -top*aspect_ratio_; + Real right = -left; + if(view!=0) { - Real ff=(view<0 ? 1.0 : -1.0); - if(stereo_alg_==2 || stereo_alg_==3 || stereo_alg_==4) { - // physically precise stereo with skew, does - // not handle z translation well - // the 100.0 comes from visual matching with mode 0 at a reasonable distance - Real dist = -transform_.GetTrans()[2]; - if(stereo_alg_==3) dist=znear_; - else if(stereo_alg_==4) dist=stereo_distance_; - - Real iod2=100.0/stereo_iod_; - geom::Mat4 skew=geom::Transpose(geom::Mat4(1.0,0.0,ff*iod2/dist,ff*iod2, - 0.0,1.0,0.0,0.0, - 0.0,0.0,1.0,0.0, - 0.0,0.0,0.0,1.0)); - glMultMatrix(skew.Data()); - } else { - // default, dino style stereo, less physically precise but visually more pleasing - Real dist = stereo_alg_==1 ? znear_ : -transform_.GetTrans()[2]; + + Real ff=(view<0 ? -1.0 : 1.0); + Real iod=std::max<Real>(0.1,stereo_iod_); + + if(stereo_alg_==1) { + // Toe-in method, easy but wrong + glFrustum(left,right,bot,top,zn,zf); + Real dist = -transform_.GetTrans()[2]+stereo_distance_; glTranslated(0.0,0.0,-dist); - glRotated(180.0/M_PI*atan(ff/stereo_iod_),0.0,1.0,0.0); + glRotated(180.0/M_PI*atan(0.1*ff/iod),0.0,1.0,0.0); glTranslated(0.0,0.0,dist); + } else { + // correct off-axis frustims + + Real fo=-transform_.GetTrans()[2]+stereo_distance_; + + // correction of near clipping plane to avoid extreme drifting + // of left and right view + if(iod*zn/fo<2.0) { + zn=2.0*fo/iod; + zf=std::max(zn+Real(0.2),zf); + } + + Real sd = -ff*0.5*iod*zn/fo; + left+=sd; + right+=sd; + + glFrustum(left,right,bot,top,zn,zf); + glTranslated(-ff*iod*0.5,0.0,0.0); } + + } else { // view==0 + // standard viewing frustum + glFrustum(left,right,bot,top,zn,zf); } } @@ -1993,4 +1984,34 @@ void Scene::render_stereo() #endif } +void Scene::do_autoslab() +{ + if(do_autoslab_fast_) { + geom::AlignedCuboid bb =this->GetBoundingBox(transform_); + // necessary code duplication due to awkward slab limit impl + znear_=-(bb.GetMax()[2]-1.0); + zfar_=-(bb.GetMin()[2]+1.0); + set_near(-(bb.GetMax()[2]-1.0)); + set_far(-(bb.GetMin()[2]+1.0)); + ResetProjection(); + } else { + LimCalc limcalc; + limcalc.transform=transform_; + limcalc.minc = Vec3(std::numeric_limits<float>::max(), + std::numeric_limits<float>::max(), + std::numeric_limits<float>::max()); + limcalc.maxc = Vec3(-std::numeric_limits<float>::max(), + -std::numeric_limits<float>::max(), + -std::numeric_limits<float>::max()); + this->Apply(limcalc); + float mynear=std::max(float(0.0), std::min(float(-limcalc.minc[2]),float(-limcalc.maxc[2])))-float(2.0); + float myfar=std::max(float(-limcalc.minc[2]),float(-limcalc.maxc[2]))+float(2.0); + znear_=mynear; + zfar_=myfar; + set_near(znear_); + set_far(zfar_); + ResetProjection(); + } +} + }} // ns diff --git a/modules/gfx/src/scene.hh b/modules/gfx/src/scene.hh index 0756aa3d9e5a78b69a268783cb5c0912277e1c53..7df5ee56cd5704234f5d99595044e2d28fa2ccd2 100644 --- a/modules/gfx/src/scene.hh +++ b/modules/gfx/src/scene.hh @@ -201,14 +201,14 @@ class DLLEXPORT_OST_GFX Scene { int GetStereoView() const {return stereo_eye_;} /// \brief set stereo eye distance - void SetStereoIOD(float); + void SetStereoIOD(Real); /// \brief return current stereo eye distance - float GetStereoIOD() const {return stereo_distance_;} + Real GetStereoIOD() const {return stereo_iod_;} - /// \brief set stereo distance - void SetStereoDistance(float); - /// \brief return current stereo distance - float GetStereoDistance() const {return stereo_distance_;} + /// \brief set stereo distance offset from COR + void SetStereoDistance(Real); + /// \brief return current stereo distance offset from COR + Real GetStereoDistance() const {return stereo_distance_;} /// \brief set stereo algorithm /// one of 0 or 1 @@ -461,6 +461,7 @@ private: bool fog_flag_; Color fog_color_; bool auto_autoslab_; + bool do_autoslab_,do_autoslab_fast_; bool offscreen_flag_; // a simple indicator whether in offscreen mode or not OffscreenBuffer* main_offscreen_buffer_; // not null if a main offscreen buffer is present @@ -478,11 +479,12 @@ private: uint blur_count_; std::vector<boost::shared_array<unsigned char> > blur_buffer_; + unsigned int stereo_mode_; unsigned int stereo_alg_; bool stereo_inverted_; unsigned int stereo_eye_; - float stereo_iod_,stereo_distance_; + Real stereo_iod_,stereo_distance_; unsigned int scene_left_tex_; unsigned int scene_right_tex_; @@ -496,6 +498,7 @@ private: void render_scene(); void render_glow(); void render_stereo(); + void do_autoslab(); bool IsNameAvailable(String name); };