stereo rendering

This commit is contained in:
David Rose 2006-02-16 02:28:20 +00:00
parent 5daca17ee6
commit ffb92db022
20 changed files with 451 additions and 211 deletions

View File

@ -746,7 +746,8 @@ class ShowBase(DirectObject.DirectObject):
return aspectRatio
def makeCamera(self, win, sort = 0, scene = None,
displayRegion = (0, 1, 0, 1), aspectRatio = None,
displayRegion = (0, 1, 0, 1), stereoChannel = None,
aspectRatio = None,
lens = None, camName = 'cam'):
"""
Makes a new 3-d camera associated with the indicated window,
@ -755,6 +756,9 @@ class ShowBase(DirectObject.DirectObject):
dr = win.makeDisplayRegion(*displayRegion)
dr.setSort(sort)
if stereoChannel != None:
dr.setStereoChannel(stereoChannel)
if scene == None:
scene = self.render

View File

@ -52,6 +52,20 @@ get_sort() const {
return cdata->_sort;
}
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::get_stereo_channel
// Access: Published
// Description: Returns whether the DisplayRegion is specified as the
// left or right channel of a stereo pair, or whether it
// is a normal, monocular image. See
// set_stereo_channel().
////////////////////////////////////////////////////////////////////
INLINE Lens::StereoChannel DisplayRegion::
get_stereo_channel() {
CDReader cdata(_cycler);
return cdata->_stereo_channel;
}
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::set_cube_map_index
// Access: Published

View File

@ -75,7 +75,7 @@ operator = (const DisplayRegion&) {
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::Destructor
// Access: Public
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
DisplayRegion::
@ -305,8 +305,7 @@ set_active(bool active) {
////////////////////////////////////////////////////////////////////
void DisplayRegion::
set_sort(int sort) {
int pipeline_stage = Thread::get_current_pipeline_stage();
nassertv(pipeline_stage == 0);
nassertv(Thread::get_current_pipeline_stage() == 0);
CDReader cdata(_cycler);
if (sort != cdata->_sort) {
@ -316,6 +315,53 @@ set_sort(int sort) {
}
}
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::set_stereo_channel
// Access: Published
// Description: Specifies whether the DisplayRegion represents the
// left or right channel of a stereo pair, or whether it
// is a normal, monocular image. See
// set_stereo_channel().
//
// This controls which direction--to the left or the
// right--the view from a PerspectiveLens is shifted
// when it is used to render into this DisplayRegion.
// Also see Lens::set_interocular_distance() and
// Lens::set_convergence_distance().
//
// Normally you would create at least two DisplayRegions
// for a stereo window, one for each of the left and
// right channels. The two DisplayRegions may share the
// same camera (and thus the same lens); this parameter
// is used to control the exact properties of the lens
// when it is used to render into this DisplayRegion.
//
// When the DisplayRegion is attached to a stereo window
// (one in which FrameBufferProperties::FM_stereo is
// set), this also specifies which physical channel the
// DisplayRegion renders to.
////////////////////////////////////////////////////////////////////
void DisplayRegion::
set_stereo_channel(Lens::StereoChannel stereo_channel) {
nassertv(Thread::get_current_pipeline_stage() == 0);
CDWriter cdata(_cycler);
cdata->_stereo_channel = stereo_channel;
switch (stereo_channel) {
case Lens::SC_left:
cdata->_draw_buffer_mask = ~(RenderBuffer::T_front_right | RenderBuffer::T_back_right);
break;
case Lens::SC_right:
cdata->_draw_buffer_mask = ~(RenderBuffer::T_front_left | RenderBuffer::T_back_left);
break;
case Lens::SC_both:
cdata->_draw_buffer_mask = ~0;
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::compute_pixels
// Access: Published
@ -624,6 +670,33 @@ get_screenshot(PNMImage &image) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::get_screenshot_buffer_type
// Access: Public, Virtual
// Description: Returns the RenderBuffer that should be used for
// capturing screenshots from this particular
// DrawableRegion.
////////////////////////////////////////////////////////////////////
int DisplayRegion::
get_screenshot_buffer_type() const {
CDReader cdata(_cycler);
return _screenshot_buffer_type & cdata->_draw_buffer_mask;
}
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::get_draw_buffer_type
// Access: Public, Virtual
// Description: Returns the RenderBuffer into which the GSG should
// issue draw commands. Normally, this is the back
// buffer for double-buffered windows, and the front
// buffer for single-buffered windows.
////////////////////////////////////////////////////////////////////
int DisplayRegion::
get_draw_buffer_type() const {
CDReader cdata(_cycler);
return _draw_buffer_type & cdata->_draw_buffer_mask;
}
////////////////////////////////////////////////////////////////////
// Function: DisplayRegion::win_display_regions_changed
// Access: Private
@ -686,6 +759,8 @@ CData() :
_camera_node((Camera *)NULL),
_active(true),
_sort(0),
_stereo_channel(Lens::SC_both),
_draw_buffer_mask(~0),
_cube_map_index(-1)
{
}
@ -711,6 +786,8 @@ CData(const DisplayRegion::CData &copy) :
_camera_node(copy._camera_node),
_active(copy._active),
_sort(copy._sort),
_stereo_channel(copy._stereo_channel),
_draw_buffer_mask(copy._draw_buffer_mask),
_cube_map_index(copy._cube_map_index)
{
}

View File

@ -33,6 +33,7 @@
#include "cycleDataStageWriter.h"
#include "pipelineCycler.h"
#include "config_display.h"
#include "lens.h"
#include "plist.h"
@ -63,7 +64,7 @@ private:
void operator = (const DisplayRegion &copy);
public:
~DisplayRegion();
virtual ~DisplayRegion();
void cleanup();
INLINE bool operator < (const DisplayRegion &other) const;
@ -88,6 +89,9 @@ PUBLISHED:
void set_sort(int sort);
INLINE int get_sort() const;
void set_stereo_channel(Lens::StereoChannel stereo_channel);
INLINE Lens::StereoChannel get_stereo_channel();
INLINE void set_cube_map_index(int cube_map_index);
INLINE int get_cube_map_index() const;
@ -114,6 +118,9 @@ public:
INLINE CullResult *get_cull_result() const;
INLINE SceneSetup *get_scene_setup() const;
virtual int get_screenshot_buffer_type() const;
virtual int get_draw_buffer_type() const;
private:
class CData;
@ -155,6 +162,8 @@ private:
bool _active;
int _sort;
Lens::StereoChannel _stereo_channel;
int _draw_buffer_mask;
int _cube_map_index;
};

View File

@ -202,28 +202,3 @@ INLINE bool DrawableRegion::
is_any_clear_active() const {
return (_flags & F_clear_all) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: DrawableRegion::get_draw_buffer_type
// Access: Public
// Description: Returns the RenderBuffer into which the GSG should
// issue draw commands. Normally, this is the back
// buffer for double-buffered windows, and the front
// buffer for single-buffered windows.
////////////////////////////////////////////////////////////////////
INLINE int DrawableRegion::
get_draw_buffer_type() const {
return _draw_buffer_type;
}
////////////////////////////////////////////////////////////////////
// Function: DrawableRegion::get_screenshot_buffer_type
// Access: Public, Virtual
// Description: Returns the RenderBuffer that should be used for
// capturing screenshots from this particular
// DrawableRegion.
////////////////////////////////////////////////////////////////////
INLINE int DrawableRegion::
get_screenshot_buffer_type() const {
return _screenshot_buffer_type;
}

View File

@ -17,3 +17,38 @@
////////////////////////////////////////////////////////////////////
#include "drawableRegion.h"
////////////////////////////////////////////////////////////////////
// Function: DrawableRegion::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
DrawableRegion::
~DrawableRegion() {
}
////////////////////////////////////////////////////////////////////
// Function: DrawableRegion::get_screenshot_buffer_type
// Access: Public, Virtual
// Description: Returns the RenderBuffer that should be used for
// capturing screenshots from this particular
// DrawableRegion.
////////////////////////////////////////////////////////////////////
int DrawableRegion::
get_screenshot_buffer_type() const {
return _screenshot_buffer_type;
}
////////////////////////////////////////////////////////////////////
// Function: DrawableRegion::get_draw_buffer_type
// Access: Public, Virtual
// Description: Returns the RenderBuffer into which the GSG should
// issue draw commands. Normally, this is the back
// buffer for double-buffered windows, and the front
// buffer for single-buffered windows.
////////////////////////////////////////////////////////////////////
int DrawableRegion::
get_draw_buffer_type() const {
return _draw_buffer_type;
}

View File

@ -38,6 +38,7 @@ public:
INLINE DrawableRegion();
INLINE DrawableRegion(const DrawableRegion &copy);
INLINE void operator = (const DrawableRegion &copy);
virtual ~DrawableRegion();
INLINE void copy_clear_settings(const DrawableRegion &copy);
@ -57,8 +58,8 @@ PUBLISHED:
INLINE bool is_any_clear_active() const;
public:
INLINE int get_screenshot_buffer_type() const;
INLINE int get_draw_buffer_type() const;
virtual int get_screenshot_buffer_type() const;
virtual int get_draw_buffer_type() const;
protected:
int _screenshot_buffer_type;

View File

@ -574,7 +574,7 @@ set_scene(SceneSetup *scene_setup) {
if (_current_lens == (Lens *)NULL) {
return false;
}
return prepare_lens();
return prepare_lens(scene_setup->get_display_region()->get_stereo_channel());
}
////////////////////////////////////////////////////////////////////

View File

@ -625,7 +625,7 @@ clear(DrawableRegion *clearable) {
// false if it is not.
////////////////////////////////////////////////////////////////////
bool GraphicsStateGuardian::
prepare_lens() {
prepare_lens(Lens::StereoChannel stereo_channel) {
return false;
}

View File

@ -25,7 +25,7 @@
#include "displayRegionStack.h"
#include "lensStack.h"
#include "preparedGraphicsObjects.h"
#include "lens.h"
#include "graphicsStateGuardianBase.h"
#include "graphicsThreadingModel.h"
#include "graphicsPipe.h"
@ -161,7 +161,7 @@ public:
INLINE void clear(DisplayRegion *dr);
virtual void prepare_display_region()=0;
virtual bool prepare_lens();
virtual bool prepare_lens(Lens::StereoChannel stereo_channel);
INLINE int force_normals();
INLINE int undo_force_normals();

View File

@ -609,7 +609,7 @@ prepare_display_region() {
// false if it is not.
////////////////////////////////////////////////////////////////////
bool DXGraphicsStateGuardian8::
prepare_lens() {
prepare_lens(Lens::StereoChannel stereo_channel) {
if (_current_lens == (Lens *)NULL) {
return false;
}
@ -619,7 +619,7 @@ prepare_lens() {
}
// Start with the projection matrix from the lens.
const LMatrix4f &lens_mat = _current_lens->get_projection_mat();
const LMatrix4f &lens_mat = _current_lens->get_projection_mat(stereo_channel);
// The projection matrix must always be left-handed Y-up internally,
// to match DirectX's convention, even if our coordinate system of
@ -1301,7 +1301,8 @@ end_draw_primitives() {
if (_vertex_data->is_vertex_transformed()) {
// Restore the projection matrix that we wiped out above.
prepare_lens();
_d3d_device->SetTransform(D3DTS_PROJECTION,
(D3DMATRIX*)_projection_mat.get_data());
}
GraphicsStateGuardian::end_draw_primitives();

View File

@ -67,7 +67,7 @@ public:
virtual void do_clear(const RenderBuffer &buffer);
virtual void prepare_display_region();
virtual bool prepare_lens();
virtual bool prepare_lens(Lens::StereoChannel stereo_channel);
virtual bool begin_frame();
virtual bool begin_scene();

View File

@ -826,7 +826,7 @@ prepare_display_region() {
// false if it is not.
////////////////////////////////////////////////////////////////////
bool DXGraphicsStateGuardian9::
prepare_lens() {
prepare_lens(Lens::StereoChannel stereo_channel) {
if (_current_lens == (Lens *)NULL) {
return false;
}
@ -836,7 +836,7 @@ prepare_lens() {
}
// Start with the projection matrix from the lens.
const LMatrix4f &lens_mat = _current_lens->get_projection_mat();
const LMatrix4f &lens_mat = _current_lens->get_projection_mat(stereo_channel);
// The projection matrix must always be left-handed Y-up internally,
// to match DirectX's convention, even if our coordinate system of
@ -1716,7 +1716,8 @@ end_draw_primitives() {
if (_vertex_data->is_vertex_transformed()) {
// Restore the projection matrix that we wiped out above.
prepare_lens();
_d3d_device->SetTransform(D3DTS_PROJECTION,
(D3DMATRIX*)_projection_mat.get_data());
}
GraphicsStateGuardian::end_draw_primitives();

View File

@ -103,7 +103,7 @@ public:
virtual void do_clear(const RenderBuffer &buffer);
virtual void prepare_display_region();
virtual bool prepare_lens();
virtual bool prepare_lens(Lens::StereoChannel stereo_channel);
virtual bool begin_frame();
virtual bool begin_scene();

View File

@ -794,6 +794,7 @@ reset() {
GLP(Disable)(GL_MULTISAMPLE);
}
_stereo = ((get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_stereo) != 0);
// Set up all the enabled/disabled flags to GL's known initial
// values: everything off.
@ -984,6 +985,7 @@ prepare_display_region() {
GLsizei width = GLsizei(w);
GLsizei height = GLsizei(h);
set_draw_buffer(get_render_buffer(_actual_display_region->get_draw_buffer_type()));
enable_scissor(true);
GLP(Scissor)(x, y, width, height);
GLP(Viewport)(x, y, width, height);
@ -1006,7 +1008,7 @@ prepare_display_region() {
// false if it is not.
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
prepare_lens() {
prepare_lens(Lens::StereoChannel stereo_channel) {
if (_current_lens == (Lens *)NULL) {
return false;
}
@ -1015,7 +1017,7 @@ prepare_lens() {
return false;
}
const LMatrix4f &lens_mat = _current_lens->get_projection_mat();
const LMatrix4f &lens_mat = _current_lens->get_projection_mat(stereo_channel);
// The projection matrix must always be right-handed Y-up, even if
// our coordinate system of choice is otherwise, because certain GL
@ -3732,19 +3734,35 @@ set_draw_buffer(const RenderBuffer &rb) {
break;
case RenderBuffer::T_front_right:
GLP(DrawBuffer)(GL_FRONT_RIGHT);
if (_stereo) {
GLP(DrawBuffer)(GL_FRONT_RIGHT);
} else {
GLP(DrawBuffer)(GL_FRONT);
}
break;
case RenderBuffer::T_front_left:
GLP(DrawBuffer)(GL_FRONT_LEFT);
if (_stereo) {
GLP(DrawBuffer)(GL_FRONT_LEFT);
} else {
GLP(DrawBuffer)(GL_FRONT);
}
break;
case RenderBuffer::T_back_right:
GLP(DrawBuffer)(GL_BACK_RIGHT);
if (_stereo) {
GLP(DrawBuffer)(GL_BACK_RIGHT);
} else {
GLP(DrawBuffer)(GL_BACK);
}
break;
case RenderBuffer::T_back_left:
GLP(DrawBuffer)(GL_BACK_LEFT);
if (_stereo) {
GLP(DrawBuffer)(GL_BACK_LEFT);
} else {
GLP(DrawBuffer)(GL_BACK);
}
break;
default:

View File

@ -78,7 +78,7 @@ public:
virtual void do_clear(const RenderBuffer &buffer);
virtual void prepare_display_region();
virtual bool prepare_lens();
virtual bool prepare_lens(Lens::StereoChannel stereo_channel);
virtual bool begin_frame();
virtual void end_frame();
@ -282,6 +282,8 @@ protected:
MM_alpha_mask = 0x0004,
};
bool _stereo;
int _multisample_mode;
bool _line_smooth_enabled;
bool _point_smooth_enabled;

View File

@ -66,6 +66,13 @@ operator = (const Lens &copy) {
_aspect_ratio = copy._aspect_ratio;
_near_distance = copy._near_distance;
_far_distance = copy._far_distance;
_view_hpr = copy._view_hpr;
_view_vector = copy._view_vector;
_interocular_distance = copy._interocular_distance;
_convergence_distance = copy._convergence_distance;
_keystone = copy._keystone;
_user_flags = copy._user_flags;
_comp_flags = 0;
@ -105,7 +112,8 @@ clear() {
_view_hpr.set(0.0f, 0.0f, 0.0f);
_view_vector.set(0.0f, 1.0f, 0.0f);
_up_vector.set(0.0f, 0.0f, 1.0f);
_iod_offset = 0.0f;
_interocular_distance = 0.0f;
_convergence_distance = 0.0f;
_keystone.set(0.0f, 0.0f);
_user_flags = 0;
@ -432,7 +440,7 @@ set_view_hpr(const LVecBase3f &view_hpr) {
_view_hpr = view_hpr;
adjust_user_flags(UF_view_vector | UF_view_mat,
UF_view_hpr);
adjust_comp_flags(CF_mat | CF_view_vector | CF_iod_offset,
adjust_comp_flags(CF_mat | CF_view_vector,
CF_view_hpr);
throw_change_event();
}
@ -465,7 +473,7 @@ set_view_vector(const LVector3f &view_vector, const LVector3f &up_vector) {
_up_vector = up_vector;
adjust_user_flags(UF_view_hpr | UF_view_mat,
UF_view_vector);
adjust_comp_flags(CF_mat | CF_view_hpr | CF_iod_offset,
adjust_comp_flags(CF_mat | CF_view_hpr,
CF_view_vector);
throw_change_event();
}
@ -509,39 +517,71 @@ get_nodal_point() const {
}
////////////////////////////////////////////////////////////////////
// Function: Lens::set_iod_offset
// Function: Lens::set_interocular_distance
// Access: Published
// Description: Sets the amount by which the lens is shifted to the
// right, perpendicular to its view vector and up
// vector. This is normally used to shift one or both
// lens of a stereo camera to generate parallax. You
// can also simply set a complete transformation matrix
// (via set_view_mat()) that includes an arbitrary
// translation.
// Description: Sets the distance between the left and right eyes of
// a stereo camera. This distance is used to apply a
// stereo effect when the lens is rendered on a stereo
// display region. It only has an effect on a
// PerspectiveLens.
//
// Also see set_interocular_distance(), which relates.
////////////////////////////////////////////////////////////////////
void Lens::
set_iod_offset(float iod_offset) {
_iod_offset = iod_offset;
adjust_user_flags(UF_view_mat,
UF_iod_offset);
adjust_comp_flags(CF_mat | CF_view_hpr | CF_view_vector,
CF_iod_offset);
set_interocular_distance(float interocular_distance) {
_interocular_distance = interocular_distance;
if (_interocular_distance == 0.0f) {
adjust_user_flags(UF_interocular_distance, 0);
} else {
adjust_user_flags(0, UF_interocular_distance);
}
adjust_comp_flags(CF_mat, 0);
throw_change_event();
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_iod_offset
// Function: Lens::get_interocular_distance
// Access: Published
// Description: Returns the aspect ratio of the Lens. This is
// determined based on the indicated film size; see
// set_film_size().
// Description: See set_interocular_distance().
////////////////////////////////////////////////////////////////////
float Lens::
get_iod_offset() const {
if ((_comp_flags & CF_iod_offset) == 0) {
((Lens *)this)->compute_iod_offset();
get_interocular_distance() const {
return _interocular_distance;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::set_convergence_distance
// Access: Published
// Description: Sets the distance between the left and right eyes of
// a stereo camera. This distance is used to apply a
// stereo effect when the lens is rendered on a stereo
// display region. It only has an effect on a
// PerspectiveLens.
//
// Also see set_interocular_distance(), which relates.
////////////////////////////////////////////////////////////////////
void Lens::
set_convergence_distance(float convergence_distance) {
_convergence_distance = convergence_distance;
if (_convergence_distance == 0.0f) {
adjust_user_flags(UF_convergence_distance, 0);
} else {
adjust_user_flags(0, UF_convergence_distance);
}
return _iod_offset;
adjust_comp_flags(CF_mat, 0);
throw_change_event();
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_convergence_distance
// Access: Published
// Description: See set_convergence_distance().
////////////////////////////////////////////////////////////////////
float Lens::
get_convergence_distance() const {
return _convergence_distance;
}
////////////////////////////////////////////////////////////////////
@ -549,7 +589,7 @@ get_iod_offset() const {
// Access: Published
// Description: Sets an arbitrary transformation on the lens. This
// replaces the individual transformation components
// like set_view_hpr() or set_iod_offset().
// like set_view_hpr().
//
// Setting a transformation here will have a slightly
// different effect than putting one on the LensNode
@ -562,9 +602,11 @@ get_iod_offset() const {
void Lens::
set_view_mat(const LMatrix4f &view_mat) {
_lens_mat = view_mat;
adjust_user_flags(UF_view_vector | UF_view_hpr | UF_iod_offset,
adjust_user_flags(UF_view_vector | UF_view_hpr,
UF_view_mat);
adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv | CF_lens_mat_inv | CF_view_hpr | CF_view_vector | CF_iod_offset,
adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv |
CF_projection_mat_left_inv | CF_projection_mat_right_inv |
CF_lens_mat_inv | CF_view_hpr | CF_view_vector,
CF_lens_mat);
throw_change_event();
}
@ -590,8 +632,10 @@ get_view_mat() const {
void Lens::
clear_view_mat() {
_lens_mat = LMatrix4f::ident_mat();
adjust_user_flags(0, UF_view_vector | UF_view_hpr | UF_iod_offset | UF_view_mat);
adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv | CF_lens_mat_inv | CF_view_hpr | CF_view_vector | CF_iod_offset,
adjust_user_flags(0, UF_view_vector | UF_view_hpr | UF_view_mat);
adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv |
CF_projection_mat_left_inv | CF_projection_mat_right_inv |
CF_lens_mat_inv | CF_view_hpr | CF_view_vector,
CF_lens_mat);
throw_change_event();
}
@ -617,7 +661,9 @@ void Lens::
set_keystone(const LVecBase2f &keystone) {
_keystone = keystone;
adjust_user_flags(0, UF_keystone);
adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv | CF_film_mat | CF_film_mat_inv, 0);
adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv |
CF_projection_mat_left_inv | CF_projection_mat_right_inv |
CF_film_mat | CF_film_mat_inv, 0);
throw_change_event();
}
@ -630,7 +676,9 @@ void Lens::
clear_keystone() {
_keystone.set(0.0f, 0.0f);
adjust_user_flags(UF_keystone, 0);
adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv | CF_film_mat | CF_film_mat_inv, 0);
adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv |
CF_projection_mat_left_inv | CF_projection_mat_right_inv |
CF_film_mat | CF_film_mat_inv, 0);
throw_change_event();
}
@ -642,9 +690,9 @@ clear_keystone() {
// PerspectiveLens, but it may be called for other kinds
// of lenses as well.
//
// The frustum will be rooted at the origin (or offset
// by iod_offset, or by whatever translation might have
// been specified in a previous call to set_view_mat).
// The frustum will be rooted at the origin (or by
// whatever translation might have been specified in a
// previous call to set_view_mat).
//
// It is legal for the four points not to be arranged in
// a rectangle; if this is the case, the frustum will be
@ -699,8 +747,7 @@ set_frustum_from_corners(const LVecBase3f &ul, const LVecBase3f &ur,
int flags) {
// We'll need to know the pre-existing eyepoint translation from the
// center, so we can preserve it in the new frustum. This is
// usually just a shift along the x axis, if anything at all, for
// the iod offset, but it could be an arbitrary vector.
// usually (0, 0, 0), but it could be an arbitrary vector.
const LMatrix4f &lens_mat_inv = get_lens_mat_inv();
LVector3f eye_offset;
lens_mat_inv.get_row3(eye_offset, 3);
@ -1018,22 +1065,59 @@ make_bounds() const {
// nonlinear.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_projection_mat() const {
get_projection_mat(StereoChannel channel) const {
if ((_comp_flags & CF_projection_mat) == 0) {
((Lens *)this)->compute_projection_mat();
}
switch (channel) {
case SC_left:
return _projection_mat_left;
case SC_right:
return _projection_mat_right;
case SC_both:
return _projection_mat;
}
return _projection_mat;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_projection_mat_inv
// Access: Public
// Access: Published
// Description: Returns the matrix that transforms from a 2-d point
// on the film to a 3-d vector in space, if such a
// matrix exists.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_projection_mat_inv() const {
get_projection_mat_inv(StereoChannel stereo_channel) const {
switch (stereo_channel) {
case SC_left:
{
if ((_comp_flags & CF_projection_mat_left_inv) == 0) {
Lens *non_const = (Lens *)this;
const LMatrix4f &projection_mat_left = get_projection_mat(SC_left);
non_const->_projection_mat_left_inv.invert_from(projection_mat_left);
non_const->adjust_comp_flags(0, CF_projection_mat_left_inv);
}
}
return _projection_mat_left_inv;
case SC_right:
{
if ((_comp_flags & CF_projection_mat_right_inv) == 0) {
Lens *non_const = (Lens *)this;
const LMatrix4f &projection_mat_right = get_projection_mat(SC_right);
non_const->_projection_mat_right_inv.invert_from(projection_mat_right);
non_const->adjust_comp_flags(0, CF_projection_mat_right_inv);
}
}
return _projection_mat_right_inv;
case SC_both:
break;
}
if ((_comp_flags & CF_projection_mat_inv) == 0) {
Lens *non_const = (Lens *)this;
const LMatrix4f &projection_mat = get_projection_mat();
@ -1043,6 +1127,68 @@ get_projection_mat_inv() const {
return _projection_mat_inv;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_film_mat
// Access: Published
// Description: Returns the matrix that transforms from a point
// behind the lens to a point on the film.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_film_mat() const {
if ((_comp_flags & CF_film_mat) == 0) {
((Lens *)this)->compute_film_mat();
}
return _film_mat;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_film_mat_inv
// Access: Published
// Description: Returns the matrix that transforms from a point on
// the film to a point behind the lens.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_film_mat_inv() const {
if ((_comp_flags & CF_film_mat_inv) == 0) {
Lens *non_const = (Lens *)this;
const LMatrix4f &film_mat = get_film_mat();
non_const->_film_mat_inv.invert_from(film_mat);
non_const->adjust_comp_flags(0, CF_film_mat_inv);
}
return _film_mat_inv;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_lens_mat
// Access: Published
// Description: Returns the matrix that transforms from a point
// in front of the lens to a point in space.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_lens_mat() const {
if ((_comp_flags & CF_lens_mat) == 0) {
((Lens *)this)->compute_lens_mat();
}
return _lens_mat;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_lens_mat_inv
// Access: Published
// Description: Returns the matrix that transforms from a point in
// space to a point in front of the lens.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_lens_mat_inv() const {
if ((_comp_flags & CF_lens_mat_inv) == 0) {
Lens *non_const = (Lens *)this;
const LMatrix4f &lens_mat = get_lens_mat();
non_const->_lens_mat_inv.invert_from(lens_mat);
non_const->adjust_comp_flags(0, CF_lens_mat_inv);
}
return _lens_mat_inv;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::output
// Access: Published, Virtual
@ -1091,68 +1237,6 @@ throw_change_event() {
}
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_film_mat
// Access: Protected
// Description: Returns the matrix that transforms from a point
// behind the lens to a point on the film.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_film_mat() const {
if ((_comp_flags & CF_film_mat) == 0) {
((Lens *)this)->compute_film_mat();
}
return _film_mat;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_film_mat_inv
// Access: Protected
// Description: Returns the matrix that transforms from a point on
// the film to a point behind the lens.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_film_mat_inv() const {
if ((_comp_flags & CF_film_mat_inv) == 0) {
Lens *non_const = (Lens *)this;
const LMatrix4f &film_mat = get_film_mat();
non_const->_film_mat_inv.invert_from(film_mat);
non_const->adjust_comp_flags(0, CF_film_mat_inv);
}
return _film_mat_inv;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_lens_mat
// Access: Protected
// Description: Returns the matrix that transforms from a point
// in front of the lens to a point in space.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_lens_mat() const {
if ((_comp_flags & CF_lens_mat) == 0) {
((Lens *)this)->compute_lens_mat();
}
return _lens_mat;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::get_lens_mat_inv
// Access: Protected
// Description: Returns the matrix that transforms from a point in
// space to a point in front of the lens.
////////////////////////////////////////////////////////////////////
const LMatrix4f &Lens::
get_lens_mat_inv() const {
if ((_comp_flags & CF_lens_mat_inv) == 0) {
Lens *non_const = (Lens *)this;
const LMatrix4f &lens_mat = get_lens_mat();
non_const->_lens_mat_inv.invert_from(lens_mat);
non_const->adjust_comp_flags(0, CF_lens_mat_inv);
}
return _lens_mat_inv;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::extrude_impl
// Access: Protected, Virtual
@ -1411,23 +1495,6 @@ compute_view_vector() {
adjust_comp_flags(0, CF_view_vector);
}
////////////////////////////////////////////////////////////////////
// Function: Lens::compute_iod_offset
// Access: Protected, Virtual
// Description: Computes the IOD offset: the translation along the
// "right" axis.
////////////////////////////////////////////////////////////////////
void Lens::
compute_iod_offset() {
if ((_user_flags & UF_iod_offset) == 0) {
const LMatrix4f &lens_mat_inv = get_lens_mat_inv();
LVector3f translate;
lens_mat_inv.get_row3(translate, 3);
_iod_offset = -translate.dot(LVector3f::right(_cs));
}
adjust_comp_flags(0, CF_iod_offset);
}
////////////////////////////////////////////////////////////////////
// Function: Lens::compute_projection_mat
// Access: Protected, Virtual
@ -1436,9 +1503,15 @@ compute_iod_offset() {
////////////////////////////////////////////////////////////////////
void Lens::
compute_projection_mat() {
_projection_mat = LMatrix4f::ident_mat();
_projection_mat_inv = _projection_mat;
adjust_comp_flags(0, CF_projection_mat | CF_projection_mat_inv);
_projection_mat =
_projection_mat_left =
_projection_mat_right =
_projection_mat_inv =
_projection_mat_left_inv =
_projection_mat_right_inv =
LMatrix4f::ident_mat();
adjust_comp_flags(0, CF_projection_mat | CF_projection_mat_inv |
CF_projection_mat_left_inv |CF_projection_mat_right_inv);
}
////////////////////////////////////////////////////////////////////
@ -1498,11 +1571,6 @@ compute_lens_mat() {
} else {
_lens_mat = LMatrix4f::ident_mat();
}
if ((_user_flags & UF_iod_offset) != 0) {
LVector3f iod_vector = _iod_offset * LVector3f::right(_cs);
_lens_mat = LMatrix4f::translate_mat(iod_vector) * _lens_mat;
}
}
adjust_comp_flags(CF_lens_mat_inv,
CF_lens_mat);

View File

@ -49,6 +49,12 @@ public:
void operator = (const Lens &copy);
PUBLISHED:
enum StereoChannel {
SC_left = 0x01,
SC_right = 0x02,
SC_both = 0x03, // == SC_left | SC_right
};
virtual PT(Lens) make_copy() const=0;
INLINE bool extrude(const LPoint2f &point2d,
@ -107,8 +113,11 @@ PUBLISHED:
const LVector3f &get_view_vector() const;
const LVector3f &get_up_vector() const;
LPoint3f get_nodal_point() const;
void set_iod_offset(float offset);
float get_iod_offset() const;
void set_interocular_distance(float interocular_distance);
float get_interocular_distance() const;
void set_convergence_distance(float convergence_distance);
float get_convergence_distance() const;
void set_view_mat(const LMatrix4f &view_mat);
const LMatrix4f &get_view_mat() const;
@ -142,8 +151,14 @@ PUBLISHED:
virtual PT(BoundingVolume) make_bounds() const;
const LMatrix4f &get_projection_mat() const;
const LMatrix4f &get_projection_mat_inv() const;
const LMatrix4f &get_projection_mat(StereoChannel channel = SC_both) const;
const LMatrix4f &get_projection_mat_inv(StereoChannel channel = SC_both) const;
const LMatrix4f &get_film_mat() const;
const LMatrix4f &get_film_mat_inv() const;
const LMatrix4f &get_lens_mat() const;
const LMatrix4f &get_lens_mat_inv() const;
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level = 0) const;
@ -157,12 +172,6 @@ protected:
void throw_change_event();
const LMatrix4f &get_film_mat() const;
const LMatrix4f &get_film_mat_inv() const;
const LMatrix4f &get_lens_mat() const;
const LMatrix4f &get_lens_mat_inv() const;
virtual bool extrude_impl(const LPoint3f &point2d,
LPoint3f &near_point, LPoint3f &far_point) const;
virtual bool extrude_vec_impl(const LPoint3f &point2d, LVector3f &vec) const;
@ -174,7 +183,6 @@ protected:
virtual void compute_aspect_ratio();
virtual void compute_view_hpr();
virtual void compute_view_vector();
virtual void compute_iod_offset();
virtual void compute_projection_mat();
virtual void compute_film_mat();
virtual void compute_lens_mat();
@ -206,26 +214,30 @@ protected:
LVecBase3f _view_hpr;
LVector3f _view_vector, _up_vector;
float _iod_offset;
float _interocular_distance;
float _convergence_distance;
LVecBase2f _keystone;
LMatrix4f _film_mat, _film_mat_inv;
LMatrix4f _lens_mat, _lens_mat_inv;
LMatrix4f _projection_mat, _projection_mat_inv;
LMatrix4f _projection_mat_left, _projection_mat_left_inv;
LMatrix4f _projection_mat_right, _projection_mat_right_inv;
enum UserFlags {
// Parameters the user may have explicitly specified.
UF_film_width = 0x0001,
UF_film_height = 0x0002,
UF_focal_length = 0x0004,
UF_hfov = 0x0008,
UF_vfov = 0x0010,
UF_aspect_ratio = 0x0020,
UF_view_hpr = 0x0040,
UF_view_vector = 0x0080,
UF_iod_offset = 0x0100,
UF_view_mat = 0x0200,
UF_keystone = 0x0400,
UF_film_width = 0x0001,
UF_film_height = 0x0002,
UF_focal_length = 0x0004,
UF_hfov = 0x0008,
UF_vfov = 0x0010,
UF_aspect_ratio = 0x0020,
UF_view_hpr = 0x0040,
UF_view_vector = 0x0080,
UF_interocular_distance = 0x0100,
UF_convergence_distance = 0x0200,
UF_view_mat = 0x0400,
UF_keystone = 0x0800,
};
enum CompFlags {
@ -236,15 +248,16 @@ protected:
CF_lens_mat_inv = 0x0008,
CF_projection_mat = 0x0010,
CF_projection_mat_inv = 0x0020,
CF_mat = 0x003f, // all of the above.
CF_projection_mat_left_inv = 0x0040,
CF_projection_mat_right_inv = 0x0080,
CF_mat = 0x00ff, // all of the above.
CF_focal_length = 0x0040,
CF_fov = 0x0080,
CF_film_size = 0x0100,
CF_aspect_ratio = 0x0200,
CF_view_hpr = 0x0400,
CF_view_vector = 0x0800,
CF_iod_offset = 0x1000,
CF_focal_length = 0x1000,
CF_fov = 0x2000,
};
short _user_flags;
short _comp_flags;

View File

@ -119,9 +119,11 @@ compute_projection_mat() {
canonical = LMatrix4f::ident_mat();
}
_projection_mat = get_lens_mat_inv() * canonical * get_film_mat();
adjust_comp_flags(CF_projection_mat_inv,
_projection_mat_left = _projection_mat_right = _projection_mat;
adjust_comp_flags(CF_projection_mat_inv | CF_projection_mat_left_inv |
CF_projection_mat_right_inv,
CF_projection_mat);
}

View File

@ -76,8 +76,8 @@ compute_projection_mat() {
float a = (fFar + fNear);
float b = -2.0f * fFar * fNear;
a/=far_minus_near;
b/=far_minus_near;
a /= far_minus_near;
b /= far_minus_near;
LMatrix4f canonical;
switch (cs) {
@ -115,9 +115,29 @@ compute_projection_mat() {
canonical = LMatrix4f::ident_mat();
}
_projection_mat = get_lens_mat_inv() * canonical * get_film_mat();
adjust_comp_flags(CF_projection_mat_inv,
if ((_user_flags & UF_interocular_distance) == 0) {
_projection_mat_left = _projection_mat_right = _projection_mat;
} else {
// Compute the left and right projection matrices in case this
// lens is assigned to a stereo DisplayRegion.
LVector3f iod = _interocular_distance * 0.5f * LVector3f::left(_cs);
_projection_mat_left = get_lens_mat_inv() * LMatrix4f::translate_mat(-iod) * canonical * get_film_mat();
_projection_mat_right = get_lens_mat_inv() * LMatrix4f::translate_mat(iod) * canonical * get_film_mat();
if (_user_flags & UF_convergence_distance) {
nassertv(_convergence_distance != 0.0f);
LVector3f cd = (0.25f / _convergence_distance) * LVector3f::left(_cs);
_projection_mat_left *= LMatrix4f::translate_mat(cd);
_projection_mat_right *= LMatrix4f::translate_mat(-cd);
}
}
adjust_comp_flags(CF_projection_mat_inv | CF_projection_mat_left_inv |
CF_projection_mat_right_inv,
CF_projection_mat);
}