From bb7a6a3ec4662a8e3cb3ab12a4a1e8cfb25ebdae Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 20 Aug 2014 20:24:13 +0000 Subject: [PATCH] Fix broken convergence distance calculation, adding a configuration variable to restore the old behavior if needed. --- panda/src/gobj/config_gobj.cxx | 14 ++++++++-- panda/src/gobj/config_gobj.h | 1 + panda/src/gobj/lens.I | 42 +++++++++++++++++++----------- panda/src/gobj/perspectiveLens.cxx | 13 ++++++--- 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index c60c75fb95..9357816d67 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/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"; diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index c6e34fafa5..eed2ef4010 100644 --- a/panda/src/gobj/config_gobj.h +++ b/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; diff --git a/panda/src/gobj/lens.I b/panda/src/gobj/lens.I index cf1c2e4d09..efb1600bea 100644 --- a/panda/src/gobj/lens.I +++ b/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) { diff --git a/panda/src/gobj/perspectiveLens.cxx b/panda/src/gobj/perspectiveLens.cxx index 9f32caa26f..b1fdb0ab6e 100644 --- a/panda/src/gobj/perspectiveLens.cxx +++ b/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); }