Browse Source

Fix broken convergence distance calculation, adding a configuration variable to restore the old behavior if needed.

rdb 11 years ago
parent
commit
bb7a6a3ec4

+ 12 - 2
panda/src/gobj/config_gobj.cxx

@@ -510,6 +510,16 @@ ConfigVariableInt lens_geom_segments
           "lens; for a normal perspective or orthographic lens, the "
           "wireframe is not subdivided."));
 
+ConfigVariableBool stereo_lens_old_convergence
+("stereo-lens-old-convergence", false,
+ PRC_DESC("In Panda3D 1.8 and below, when using a stereo lens, Panda "
+          "generate an incorrect frustum skew for a given convergence "
+          "distance, meaning that the left-right images wouldn't "
+          "overlap at the configured distance.  This calculation has "
+          "since been corrected, but if your application relies on the "
+          "old, incorrect behavior, this may be set to 'true' to switch "
+          "back to the old calculation."));
+
 ConfigVariableString cg_glsl_version
 ("cg-glsl-version", "",
  PRC_DESC("If this is set, it forces the Cg compiler to generate GLSL "
@@ -604,10 +614,10 @@ operator << (ostream &out, ShaderUtilization sgc) {
   switch (sgc) {
   case SUT_none:
     return out << "none";
-   
+
   case SUT_basic:
     return out << "basic";
-    
+
   case SUT_advanced:
     return out << "advanced";
 

+ 1 - 0
panda/src/gobj/config_gobj.h

@@ -98,6 +98,7 @@ extern EXPCL_PANDA_GOBJ ConfigVariableDouble adaptive_lru_weight;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt adaptive_lru_max_updates_per_frame;
 extern EXPCL_PANDA_GOBJ ConfigVariableDouble async_load_delay;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt lens_geom_segments;
+extern EXPCL_PANDA_GOBJ ConfigVariableBool stereo_lens_old_convergence;
 
 extern EXPCL_PANDA_GOBJ ConfigVariableString cg_glsl_version;
 

+ 27 - 15
panda/src/gobj/lens.I

@@ -608,14 +608,26 @@ get_interocular_distance() const {
 //               PerspectiveLens.
 //
 //               This parameter must be greater than 0, but may be as
-//               large as you like.  It controls the amount to which
-//               the two eyes are directed inwards towards each other,
-//               which is a normal property of stereo vision.  It is a
-//               distance, not an angle; normally this should be set
-//               to the distance from the camera to the area of
-//               interest in your scene.  If you want to simulate
-//               parallel stereo, set this value to a very large
-//               number.
+//               large as you like.  It controls the distance at
+//               which the two stereo images will appear to converge,
+//               which is a normal property of stereo vision.  Normally
+//               this should be set to the distance from the camera to
+//               the area of interest in your scene.  Anything beyond
+//               this distance will appear to go into the screen, and
+//               anything closer will appear to come out of the screen.
+//               If you want to simulate parallel stereo, set this
+//               to infinity.
+//
+//               Note that this creates an off-axis frustum, which
+//               means that the lenses are still pointing in the
+//               same direction, which is usually more desirable
+//               than the more naive toe-in approach, where the
+//               two lenses are simply tilted toward each other.
+//
+//               Prior to Panda3D 1.9.0, the convergence was being
+//               calculated incorrectly.  It has since been corrected.
+//               To restore the legacy behavior you can set the
+//               stereo-lens-old-convergence variable to true.
 //
 //               Also see set_interocular_distance(), which relates.
 ////////////////////////////////////////////////////////////////////
@@ -807,7 +819,7 @@ do_adjust_comp_flags(CData *cdata, int clear_flags, int set_flags) {
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::do_set_film_offset
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE void Lens::
 do_set_film_offset(CData *cdata, const LVecBase2 &film_offset) {
@@ -819,7 +831,7 @@ do_set_film_offset(CData *cdata, const LVecBase2 &film_offset) {
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::do_get_film_offset
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE const LVector2 &Lens::
 do_get_film_offset(const CData *cdata) const {
@@ -829,7 +841,7 @@ do_get_film_offset(const CData *cdata) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::do_set_near
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE void Lens::
 do_set_near(CData *cdata, PN_stdfloat near_distance) {
@@ -841,7 +853,7 @@ do_set_near(CData *cdata, PN_stdfloat near_distance) {
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::do_get_near
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE PN_stdfloat Lens::
 do_get_near(const CData *cdata) const {
@@ -851,7 +863,7 @@ do_get_near(const CData *cdata) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::do_set_far
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE void Lens::
 do_set_far(CData *cdata, PN_stdfloat far_distance) {
@@ -863,7 +875,7 @@ do_set_far(CData *cdata, PN_stdfloat far_distance) {
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::do_get_far
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE PN_stdfloat Lens::
 do_get_far(const CData *cdata) const {
@@ -873,7 +885,7 @@ do_get_far(const CData *cdata) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::do_set_near_far
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE void Lens::
 do_set_near_far(CData *cdata, PN_stdfloat near_distance, PN_stdfloat far_distance) {

+ 10 - 3
panda/src/gobj/perspectiveLens.cxx

@@ -137,10 +137,17 @@ do_compute_projection_mat(Lens::CData *lens_cdata) {
     LVector3 iod = lens_cdata->_interocular_distance * 0.5f * LVector3::left(lens_cdata->_cs);
     lens_cdata->_projection_mat_left = do_get_lens_mat_inv(lens_cdata) * LMatrix4::translate_mat(-iod) * canonical * do_get_film_mat(lens_cdata);
     lens_cdata->_projection_mat_right = do_get_lens_mat_inv(lens_cdata) * LMatrix4::translate_mat(iod) * canonical * do_get_film_mat(lens_cdata);
-    
-    if (lens_cdata->_user_flags & UF_convergence_distance) {
+
+    if ((lens_cdata->_user_flags & UF_convergence_distance) != 0 &&
+        !cinf(lens_cdata->_convergence_distance)) {
       nassertv(lens_cdata->_convergence_distance != 0.0f);
-      LVector3 cd = (0.25f / lens_cdata->_convergence_distance) * LVector3::left(lens_cdata->_cs);
+      LVector3 cd;
+      if (stereo_lens_old_convergence) { // The old, incorrect calculation was requested.
+        cd = (0.25f / lens_cdata->_convergence_distance) * LVector3::left(lens_cdata->_cs);
+      } else {
+        const LVecBase2 &fov = do_get_fov(lens_cdata);
+        cd = (2.0f / fov_to_film(fov[0], lens_cdata->_convergence_distance, true)) * iod;
+      }
       lens_cdata->_projection_mat_left *= LMatrix4::translate_mat(cd);
       lens_cdata->_projection_mat_right *= LMatrix4::translate_mat(-cd);
     }