From a51504890864d8f15f00a2b31e1073e6a7a57704 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 11 Apr 2013 14:41:46 +0000 Subject: [PATCH] add undist_lut to ProjectionScreen, PfmVizzer --- panda/src/distort/projectionScreen.I | 52 ++++++++++++++++++++++++++ panda/src/distort/projectionScreen.cxx | 51 ++++++++++++++++++++++++- panda/src/distort/projectionScreen.h | 8 ++++ panda/src/grutil/pfmVizzer.I | 10 +++++ panda/src/grutil/pfmVizzer.cxx | 29 ++++++++++++-- panda/src/grutil/pfmVizzer.h | 8 +++- panda/src/pnmimage/pfmFile.cxx | 29 ++++++++------ 7 files changed, 168 insertions(+), 19 deletions(-) diff --git a/panda/src/distort/projectionScreen.I b/panda/src/distort/projectionScreen.I index 2c7e9a84a6..560138cf7f 100644 --- a/panda/src/distort/projectionScreen.I +++ b/panda/src/distort/projectionScreen.I @@ -26,6 +26,58 @@ get_projector() const { return _projector; } +//////////////////////////////////////////////////////////////////// +// Function: ProjectionScreen::clear_undist_lut +// Access: Published +// Description: Removes the distortion lookup table from the +// projector, if specified. +//////////////////////////////////////////////////////////////////// +INLINE void ProjectionScreen:: +clear_undist_lut() { + _has_undist_lut = false; + _undist_lut = PfmFile(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ProjectionScreen::set_undist_lut +// Access: Published +// Description: Applies a distortion lookup table to the +// projector. This mapping warps the lens effect by +// passing each ray through an indirection table: the +// point (u,v) in the indicated lookup table stores the +// actual (u,v) that the lens produces. +// +// This does not affect the operation of +// generate_screen(). +//////////////////////////////////////////////////////////////////// +INLINE void ProjectionScreen:: +set_undist_lut(const PfmFile &undist_lut) { + _has_undist_lut = undist_lut.is_valid(); + _undist_lut = undist_lut; +} + +//////////////////////////////////////////////////////////////////// +// Function: ProjectionScreen::has_undist_lut +// Access: Published +// Description: Returns true if a valid distortion lookup table was +// provided via set_undist_lut(), false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool ProjectionScreen:: +has_undist_lut() const { + return _has_undist_lut; +} + +//////////////////////////////////////////////////////////////////// +// Function: ProjectionScreen::get_undist_lut +// Access: Published +// Description: Returns the distortion lookup table provided via +// set_undist_lut(), if any. +//////////////////////////////////////////////////////////////////// +INLINE const PfmFile &ProjectionScreen:: +get_undist_lut() const { + return _undist_lut; +} + //////////////////////////////////////////////////////////////////// // Function: ProjectionScreen::set_texcoord_name // Access: Published diff --git a/panda/src/distort/projectionScreen.cxx b/panda/src/distort/projectionScreen.cxx index ea5d6ee9e5..f8b62d0deb 100644 --- a/panda/src/distort/projectionScreen.cxx +++ b/panda/src/distort/projectionScreen.cxx @@ -39,6 +39,7 @@ ProjectionScreen(const string &name) : PandaNode(name) _texcoord_name = InternalName::get_texcoord(); + _has_undist_lut = false; _invert_uvs = project_invert_uvs; _texcoord_3d = false; _vignette_on = false; @@ -214,7 +215,7 @@ generate_screen(const NodePath &projector, const string &screen_name, for (int yi = 0; yi < num_y_verts; yi++) { for (int xi = 0; xi < num_x_verts; xi++) { LPoint2 film = LPoint2((PN_stdfloat)xi * x_scale - 1.0f, - (PN_stdfloat)yi * y_scale - 1.0f); + (PN_stdfloat)yi * y_scale - 1.0f); // Reduce the image by the fill ratio. film *= fill_ratio; @@ -590,6 +591,22 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) { // Now the lens gives us coordinates in the range [-1, 1]. // Rescale these to [0, 1]. LPoint3 uvw = film * to_uv; + + if (good && _has_undist_lut) { + int x_size = _undist_lut.get_x_size(); + int y_size = _undist_lut.get_y_size(); + + int dist_xi = (int)cfloor(uvw[0] * (PN_float32)x_size); + int dist_yi = (int)cfloor(uvw[1] * (PN_float32)y_size); + if (!_undist_lut.has_point(dist_xi, y_size - 1 - dist_yi)) { + // Point is missing. + uvw.set(0, 0, 0); + good = false; + } else { + uvw = _undist_lut.get_point(dist_xi, y_size - 1 - dist_yi); + uvw[1] = 1.0 - uvw[1]; + } + } texcoord.set_data3(uvw); // If we have vignette color in effect, color the vertex according @@ -722,6 +739,13 @@ make_mesh_geom_node(const WorkingNodePath &np, const NodePath &camera, //////////////////////////////////////////////////////////////////// PT(Geom) ProjectionScreen:: make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4 &rel_mat) { + static const LMatrix4 lens_to_uv + (0.5f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.5f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.0f, 1.0f); + static const LMatrix4 uv_to_lens = invert(lens_to_uv); + Thread *current_thread = Thread::get_current_thread(); PT(Geom) new_geom = geom->make_copy(); PT(GeomVertexData) vdata = new_geom->modify_vertex_data(); @@ -735,7 +759,30 @@ make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4 &rel_mat) { // dimensions so the Z coordinate remains meaningful. LPoint3 vert3d = vert * rel_mat; LPoint3 film(0.0f, 0.0f, 0.0f); - lens->project(vert3d, film); + bool good = lens->project(vert3d, film); + + if (good && _has_undist_lut) { + + // Now the lens gives us coordinates in the range [-1, 1]. + // Rescale these to [0, 1]. + LPoint3 uvw = film * lens_to_uv; + + int x_size = _undist_lut.get_x_size(); + int y_size = _undist_lut.get_y_size(); + + int dist_xi = (int)cfloor(uvw[0] * (PN_float32)x_size); + int dist_yi = (int)cfloor(uvw[1] * (PN_float32)y_size); + if (!_undist_lut.has_point(dist_xi, y_size - 1 - dist_yi)) { + // Point is missing. + uvw.set(0, 0, 0); + good = false; + } else { + uvw = _undist_lut.get_point(dist_xi, y_size - 1 - dist_yi); + uvw[1] = 1.0 - uvw[1]; + } + + film = uvw * uv_to_lens; + } vertex.set_data3(film); } diff --git a/panda/src/distort/projectionScreen.h b/panda/src/distort/projectionScreen.h index 890ea2898d..6d4b8bc215 100644 --- a/panda/src/distort/projectionScreen.h +++ b/panda/src/distort/projectionScreen.h @@ -23,6 +23,7 @@ #include "nodePath.h" #include "internalName.h" #include "pointerTo.h" +#include "pfmFile.h" class Geom; class WorkingNodePath; @@ -67,6 +68,11 @@ PUBLISHED: void set_projector(const NodePath &projector); INLINE const NodePath &get_projector() const; + INLINE void clear_undist_lut(); + INLINE void set_undist_lut(const PfmFile &undist_lut); + INLINE bool has_undist_lut() const; + INLINE const PfmFile &get_undist_lut() const; + PT(GeomNode) generate_screen(const NodePath &projector, const string &screen_name, int num_x_verts, int num_y_verts, @@ -124,6 +130,8 @@ private: NodePath _projector; PT(LensNode) _projector_node; + bool _has_undist_lut; + PfmFile _undist_lut; PT(InternalName) _texcoord_name; bool _invert_uvs; bool _texcoord_3d; diff --git a/panda/src/grutil/pfmVizzer.I b/panda/src/grutil/pfmVizzer.I index 0aa6495b18..2ab7efbcb2 100644 --- a/panda/src/grutil/pfmVizzer.I +++ b/panda/src/grutil/pfmVizzer.I @@ -180,3 +180,13 @@ INLINE const PNMImage *PfmVizzer:: get_vis_blend() const { return _vis_blend; } + +//////////////////////////////////////////////////////////////////// +// Function: PfmVizzer::VisColumn::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PfmVizzer::VisColumn:: +VisColumn() { + _undist_lut = NULL; +} diff --git a/panda/src/grutil/pfmVizzer.cxx b/panda/src/grutil/pfmVizzer.cxx index c559d72d70..7e91aad19f 100644 --- a/panda/src/grutil/pfmVizzer.cxx +++ b/panda/src/grutil/pfmVizzer.cxx @@ -230,8 +230,8 @@ clear_vis_columns() { void PfmVizzer:: add_vis_column(ColumnType source, ColumnType target, InternalName *name, const TransformState *transform, - const Lens *lens) { - add_vis_column(_vis_columns, source, target, name, transform, lens); + const Lens *lens, const PfmFile *undist_lut) { + add_vis_column(_vis_columns, source, target, name, transform, lens, undist_lut); } //////////////////////////////////////////////////////////////////// @@ -726,7 +726,7 @@ make_vis_mesh_geom(GeomNode *gnode, bool inverted) const { void PfmVizzer:: add_vis_column(VisColumns &vis_columns, ColumnType source, ColumnType target, InternalName *name, const TransformState *transform, - const Lens *lens) { + const Lens *lens, const PfmFile *undist_lut) { VisColumn column; column._source = source; column._target = target; @@ -736,6 +736,9 @@ add_vis_column(VisColumns &vis_columns, ColumnType source, ColumnType target, column._transform = TransformState::make_identity(); } column._lens = lens; + if (undist_lut != NULL && undist_lut->is_valid()) { + column._undist_lut = undist_lut; + } vis_columns.push_back(column); } @@ -986,10 +989,12 @@ add_data(const PfmVizzer &vizzer, GeomVertexWriter &vwriter, int xi, int yi, boo //////////////////////////////////////////////////////////////////// bool PfmVizzer::VisColumn:: transform_point(LPoint2f &point) const { + bool success = true; if (!_transform->is_identity()) { LCAST(PN_float32, _transform->get_mat3()).xform_point_in_place(point); } - return true; + + return success; } //////////////////////////////////////////////////////////////////// @@ -1016,6 +1021,22 @@ transform_point(LPoint3f &point) const { point = to_uv.xform_point(LCAST(PN_float32, film)); } + if (_undist_lut != NULL) { + int x_size = _undist_lut->get_x_size(); + int y_size = _undist_lut->get_y_size(); + + int dist_xi = (int)cfloor(point[0] * (PN_float32)x_size); + int dist_yi = (int)cfloor(point[1] * (PN_float32)y_size); + if (!_undist_lut->has_point(dist_xi, y_size - 1 - dist_yi)) { + // Point is missing. + point.set(0, 0, 0); + success = false; + } else { + point = _undist_lut->get_point(dist_xi, y_size - 1 - dist_yi); + point[1] = 1.0 - point[1]; + } + } + return success; } diff --git a/panda/src/grutil/pfmVizzer.h b/panda/src/grutil/pfmVizzer.h index 12da3c4e15..c3229d6ce6 100644 --- a/panda/src/grutil/pfmVizzer.h +++ b/panda/src/grutil/pfmVizzer.h @@ -63,7 +63,8 @@ PUBLISHED: void clear_vis_columns(); void add_vis_column(ColumnType source, ColumnType target, InternalName *name, - const TransformState *transform = NULL, const Lens *lens = NULL); + const TransformState *transform = NULL, const Lens *lens = NULL, + const PfmFile *undist_lut = NULL); BLOCKING NodePath generate_vis_points() const; @@ -88,6 +89,7 @@ private: class VisColumn { public: + INLINE VisColumn(); bool add_data(const PfmVizzer &vizzer, GeomVertexWriter &vwriter, int xi, int yi, bool reverse_normals) const; bool transform_point(LPoint2f &point) const; bool transform_point(LPoint3f &point) const; @@ -99,13 +101,15 @@ private: PT(InternalName) _name; CPT(TransformState) _transform; CPT(Lens) _lens; + const PfmFile *_undist_lut; }; typedef pvector VisColumns; static void add_vis_column(VisColumns &vis_columns, ColumnType source, ColumnType target, InternalName *name, - const TransformState *transform = NULL, const Lens *lens = NULL); + const TransformState *transform = NULL, + const Lens *lens = NULL, const PfmFile *undist_lut = NULL); void build_auto_vis_columns(VisColumns &vis_columns, bool for_points) const; CPT(GeomVertexFormat) make_array_format(const VisColumns &vis_columns) const; diff --git a/panda/src/pnmimage/pfmFile.cxx b/panda/src/pnmimage/pfmFile.cxx index f029bf4f76..c6decbf218 100644 --- a/panda/src/pnmimage/pfmFile.cxx +++ b/panda/src/pnmimage/pfmFile.cxx @@ -79,7 +79,7 @@ clear() { _x_size = 0; _y_size = 0; _scale = 1.0; - _num_channels = 3; + _num_channels = 0; _table.clear(); clear_no_data_value(); } @@ -1044,6 +1044,11 @@ xform(const LMatrix4f &transform) { // file at (x,y), where (x,y) is the point value from // the dist map. // +// By convention, the y axis in inverted in the +// distortion map relative to the coordinates here. A y +// value of 0 in the distortion map corresponds with a v +// value of 1 in this file. +// // If scale_factor is not 1, it should be a value > 1, // and it specifies the factor to upscale the working // table while processing, to reduce artifacts from @@ -1091,16 +1096,11 @@ forward_distort(const PfmFile &dist, PN_float32 scale_factor) { LPoint2f uv = dist_p->get_point2(xi, yi); int dist_xi = (int)cfloor(uv[0] * (PN_float32)working_x_size); int dist_yi = (int)cfloor(uv[1] * (PN_float32)working_y_size); - if (dist_xi < 0 || dist_xi >= working_x_size || - dist_yi < 0 || dist_yi >= working_y_size) { + if (!source_p->has_point(dist_xi, working_y_size - 1 - dist_yi)) { continue; } - if (!source_p->has_point(dist_xi, dist_yi)) { - continue; - } - - result.set_point(xi, yi, source_p->get_point(dist_xi, dist_yi)); + result.set_point(xi, working_y_size - 1 - yi, source_p->get_point(dist_xi, working_y_size - 1 - dist_yi)); } } @@ -1122,6 +1122,11 @@ forward_distort(const PfmFile &dist, PN_float32 scale_factor) { // file at (u,v), where (x,y) is the point value from // the dist map. // +// By convention, the y axis in inverted in the +// distortion map relative to the coordinates here. A y +// value of 0 in the distortion map corresponds with a v +// value of 1 in this file. +// // If scale_factor is not 1, it should be a value > 1, // and it specifies the factor to upscale the working // table while processing, to reduce artifacts from @@ -1163,7 +1168,7 @@ reverse_distort(const PfmFile &dist, PN_float32 scale_factor) { for (int yi = 0; yi < working_y_size; ++yi) { for (int xi = 0; xi < working_x_size; ++xi) { - if (!source_p->has_point(xi, yi)) { + if (!source_p->has_point(xi, working_y_size - 1 - yi)) { continue; } if (!dist_p->has_point(xi, yi)) { @@ -1177,11 +1182,13 @@ reverse_distort(const PfmFile &dist, PN_float32 scale_factor) { continue; } - if (!source_p->has_point(dist_xi, dist_yi)) { + /* + if (!source_p->has_point(dist_xi, working_y_size - 1 - dist_yi)) { continue; } + */ - result.set_point(dist_xi, dist_yi, source_p->get_point(xi, yi)); + result.set_point(dist_xi, working_y_size - 1 - dist_yi, source_p->get_point(xi, working_y_size - 1 - yi)); } }