define Lens::extrude_depth() to reverse Lens::project(), and use this in PfmVizzer

This commit is contained in:
David Rose 2013-01-10 02:01:39 +00:00
parent 8dff4f69e5
commit eefb99cbc5
13 changed files with 217 additions and 69 deletions

View File

@ -149,6 +149,9 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
// Compute the depth as a linear distance in the range 0 .. 1.
PN_stdfloat z = (pdist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
point2d.set
(
// The x position is the angle about the Z axis.
@ -156,8 +159,8 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
// The y position is the Z height divided by the perspective
// distance.
p[2] * focal_length / pdist,
// Z is the perspective distance scaled into the range (1, -1).
(do_get_near(lens_cdata) - pdist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata))
// Z is the distance scaled into the range 1 .. -1.
1.0 - 2.0 * z
);
// Now we have to transform the point according to the film

View File

@ -198,11 +198,14 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
PN_stdfloat factor = r * focal_length / fisheye_k;
// Compute the depth as a linear distance in the range 0 .. 1.
PN_stdfloat z = (dist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
point2d.set
(y[0] * factor,
y[1] * factor,
// Z is the distance scaled into the range (1, -1).
(do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata))
// Z is the distance scaled into the range 1 .. -1.
1.0 - 2.0 * z
);
// Now we have to transform the point according to the film

View File

@ -117,14 +117,17 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
// into the XY plane to do this.
LVector2 xy(v3[0], v3[1]);
// Compute the depth as a linear distance in the range 0 .. 1.
PN_stdfloat z = (dist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
point2d.set
(
// The x position is the angle about the Z axis.
rad_2_deg(catan2(xy[0], xy[1])) * focal_length / ospherical_k,
// The y position is the Z height.
p[2],
// Z is the distance scaled into the range (1, -1).
(do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata))
// Z is the distance scaled into the range 1 .. -1.
1.0 - 2.0 * z
);
// Now we have to transform the point according to the film

View File

@ -115,14 +115,17 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
xy.normalize();
LVector2d yz(v3[0]*xy[0] + v3[1]*xy[1], v3[2]);
// Compute the depth as a linear distance in the range 0 .. 1.
PN_stdfloat z = (dist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
point2d.set
(
// The x position is the angle about the Z axis.
rad_2_deg(catan2(xy[0], xy[1])) * focal_length / pspherical_k,
// The y position is the angle about the X axis.
rad_2_deg(catan2(yz[1], yz[0])) * focal_length / pspherical_k,
// Z is the distance scaled into the range (1, -1).
(do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata))
// Z is the distance scaled into the range 1 .. -1.
1.0 - 2.0 * z
);
// Now we have to transform the point according to the film

View File

@ -529,14 +529,14 @@ recompute_geom(Geom *geom, const 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, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f);
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f);
static const LMatrix4 lens_to_uv_inverted
(0.5f, 0.0f, 0.0f, 0.0f,
0.0f,-0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f);
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f);
Thread *current_thread = Thread::get_current_thread();
@ -546,8 +546,9 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) {
const LMatrix4 &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv;
// Iterate through all the vertices in the Geom.
CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread);
vdata = vdata->animate_vertices(true, current_thread);
CPT(GeomVertexData) vdata = geom->get_vertex_data();
CPT(GeomVertexFormat) vformat = vdata->get_format();
if (!vformat->has_column(_texcoord_name) || (_texcoord_3d && vformat->get_column(_texcoord_name)->get_num_components() < 3)) {
// We need to add a new column for the new texcoords.
@ -582,12 +583,14 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) {
LVertex vert = vertex.get_data3();
// For each vertex, project to the film plane.
LPoint3 vert3d = vert * rel_mat;
LPoint3 film(0.0f, 0.0f, 0.0f);
bool good = lens->project(vert * rel_mat, film);
bool good = lens->project(vert3d, film);
// Now the lens gives us coordinates in the range [-1, 1].
// Rescale these to [0, 1].
texcoord.set_data3(film * to_uv);
LPoint3 uvw = film * to_uv;
texcoord.set_data3(uvw);
// If we have vignette color in effect, color the vertex according
// to whether it fell in front of the lens or not.
@ -615,17 +618,18 @@ make_mesh_node(PandaNode *result_parent, const WorkingNodePath &np,
const NodePath &camera,
LMatrix4 &rel_mat, bool &computed_rel_mat) {
PandaNode *node = np.node();
if (!node->safe_to_flatten()) {
// If we can't safely flatten this node, ignore it (and all of its
// children) completely. It's got no business being here anyway.
return NULL;
}
PT(PandaNode) new_node;
if (node->is_geom_node()) {
new_node = make_mesh_geom_node(np, camera, rel_mat, computed_rel_mat);
} else {
} else if (node->safe_to_flatten()) {
new_node = node->make_copy();
new_node->clear_transform();
} else {
// If we can't safely flatten the node, just make a plain node in
// its place.
new_node = new PandaNode(node->get_name());
new_node->set_state(node->get_state());
}
// Now attach the new node to the result.
@ -666,11 +670,13 @@ make_mesh_children(PandaNode *new_node, const WorkingNodePath &np,
rel_mat, computed_rel_mat);
}
if (new_child != NULL) {
// Copy all of the render state (except TransformState) to the
// new arc.
new_child->set_state(child->get_state());
}
}
}
////////////////////////////////////////////////////////////////////
// Function: ProjectionScreen::make_mesh_geom_node
@ -725,8 +731,9 @@ make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4 &rel_mat) {
// Project each vertex into the film plane, but use three
// dimensions so the Z coordinate remains meaningful.
LPoint3 vert3d = vert * rel_mat;
LPoint3 film(0.0f, 0.0f, 0.0f);
lens->project(vert * rel_mat, film);
lens->project(vert3d, film);
vertex.set_data3(film);
}

View File

@ -58,6 +58,21 @@ extrude(const LPoint3 &point2d, LPoint3 &near_point, LPoint3 &far_point) const {
return do_extrude(cdata, point2d, near_point, far_point);
}
////////////////////////////////////////////////////////////////////
// Function: Lens::extrude_depth
// Access: Published
// Description: Uses the depth component of the 3-d result from
// project() to compute the original point in 3-d space
// corresponding to a particular point on the lens.
// This exactly reverses project(), assuming the point
// does fall legitimately within the lens.
////////////////////////////////////////////////////////////////////
INLINE bool Lens::
extrude_depth(const LPoint3 &point2d, LPoint3 &point3d) const {
CDReader cdata(_cycler);
return do_extrude_depth(cdata, point2d, point3d);
}
////////////////////////////////////////////////////////////////////
// Function: Lens::extrude_vec
// Access: Published

View File

@ -1242,6 +1242,37 @@ do_extrude(const CData *cdata,
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::do_extrude_depth
// Access: Protected, Virtual
// Description: This is the generic implementation, which is based on
// do_extrude() and assumes a linear distribution of
// depth values between the near and far points.
////////////////////////////////////////////////////////////////////
bool Lens::
do_extrude_depth(const CData *cdata,
const LPoint3 &point2d, LPoint3 &point3d) const {
LPoint3 near_point, far_point;
bool result = extrude(point2d, near_point, far_point);
point3d = near_point + (far_point - near_point) * point2d[2];
return result;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::do_extrude_depth_with_mat
// Access: Protected
// Description: Implements do_extrude_depth() by using the projection
// matrix. This is efficient, but works only for a
// linear (Perspective or Orthographic) lens.
////////////////////////////////////////////////////////////////////
bool Lens::
do_extrude_depth_with_mat(const CData *cdata,
const LPoint3 &point2d, LPoint3 &point3d) const {
const LMatrix4 &projection_mat_inv = do_get_projection_mat_inv(cdata);
point3d = projection_mat_inv.xform_point_general(point2d);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::do_extrude_vec
// Access: Protected, Virtual

View File

@ -62,6 +62,7 @@ PUBLISHED:
LPoint3 &near_point, LPoint3 &far_point) const;
INLINE bool extrude(const LPoint3 &point2d,
LPoint3 &near_point, LPoint3 &far_point) const;
INLINE bool extrude_depth(const LPoint3 &point2d, LPoint3 &point3d) const;
INLINE bool extrude_vec(const LPoint2 &point2d, LVector3 &vec3d) const;
INLINE bool extrude_vec(const LPoint3 &point2d, LVector3 &vec3d) const;
INLINE bool project(const LPoint3 &point3d, LPoint3 &point2d) const;
@ -216,6 +217,10 @@ protected:
virtual bool do_extrude(const CData *cdata, const LPoint3 &point2d,
LPoint3 &near_point, LPoint3 &far_point) const;
virtual bool do_extrude_depth(const CData *cdata, const LPoint3 &point2d,
LPoint3 &point3d) const;
bool do_extrude_depth_with_mat(const CData *cdata, const LPoint3 &point2d,
LPoint3 &point3d) const;
virtual bool do_extrude_vec(const CData *cdata,
const LPoint3 &point2d, LVector3 &vec) const;
virtual bool do_project(const CData *cdata,

View File

@ -64,6 +64,19 @@ write(ostream &out, int indent_level) const {
indent(out, indent_level) << get_type() << " film size = " << get_film_size() << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: OrthographicLens::do_extrude_depth
// Access: Protected, Virtual
// Description: This is the generic implementation, which is based on
// do_extrude() and assumes a linear distribution of
// depth values between the near and far points.
////////////////////////////////////////////////////////////////////
bool OrthographicLens::
do_extrude_depth(const CData *cdata,
const LPoint3 &point2d, LPoint3 &point3d) const {
return do_extrude_depth_with_mat(cdata, point2d, point3d);
}
////////////////////////////////////////////////////////////////////
// Function: OrthographicLens::do_compute_projection_mat
// Access: Protected, Virtual

View File

@ -47,6 +47,8 @@ public:
virtual void write(ostream &out, int indent_level = 0) const;
protected:
virtual bool do_extrude_depth(const CData *cdata, const LPoint3 &point2d,
LPoint3 &point3d) const;
virtual void do_compute_projection_mat(Lens::CData *lens_cdata);
public:

View File

@ -53,6 +53,19 @@ is_perspective() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PerspectiveLens::do_extrude_depth
// Access: Protected, Virtual
// Description: This is the generic implementation, which is based on
// do_extrude() and assumes a linear distribution of
// depth values between the near and far points.
////////////////////////////////////////////////////////////////////
bool PerspectiveLens::
do_extrude_depth(const CData *cdata,
const LPoint3 &point2d, LPoint3 &point3d) const {
return do_extrude_depth_with_mat(cdata, point2d, point3d);
}
////////////////////////////////////////////////////////////////////
// Function: PerspectiveLens::do_compute_projection_mat
// Access: Protected, Virtual

View File

@ -39,6 +39,8 @@ public:
virtual bool is_perspective() const;
protected:
virtual bool do_extrude_depth(const CData *cdata, const LPoint3 &point2d,
LPoint3 &point3d) const;
virtual void do_compute_projection_mat(Lens::CData *lens_cdata);
virtual PN_stdfloat fov_to_film(PN_stdfloat fov, PN_stdfloat focal_length, bool horiz) const;

View File

@ -89,18 +89,22 @@ project(const Lens *lens) {
void PfmVizzer::
extrude(const Lens *lens) {
nassertv(_pfm.is_valid());
nassertv(lens->is_linear());
static LMatrix4 from_uv(2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, -1.0, 1.0);
const LMatrix4 &proj_mat_inv = lens->get_projection_mat_inv();
0.0, 0.0, 1.0, 0.0,
-1.0, -1.0, 0.0, 1.0);
PfmFile result;
result.clear(_pfm.get_x_size(), _pfm.get_y_size(), 3);
result.set_zero_special(true);
if (lens->is_linear()) {
// If the lens is linear (Perspective or Orthographic), we can
// take the slightly faster approach of extruding all the points
// via a transform matrix.
const LMatrix4 &proj_mat_inv = lens->get_projection_mat_inv();
if (_pfm.get_num_channels() == 1) {
// Create an implicit UV coordinate for each point.
LPoint2 uv_scale(1.0, 1.0);
@ -115,14 +119,14 @@ extrude(const Lens *lens) {
if (!_pfm.has_point(xi, yi)) {
continue;
}
LPoint3 p;
LPoint3 p, rp;
p.set(((PN_stdfloat)xi + 0.5) * uv_scale[0],
((PN_stdfloat)yi + 0.5) * uv_scale[1],
(PN_stdfloat)_pfm.get_point1(xi, yi));
from_uv.xform_point_in_place(p);
proj_mat_inv.xform_point_general_in_place(p);
result.set_point(xi, yi, p);
rp = proj_mat_inv.xform_point_general(p);
result.set_point(xi, yi, rp);
}
}
} else {
@ -132,12 +136,56 @@ extrude(const Lens *lens) {
if (!_pfm.has_point(xi, yi)) {
continue;
}
LPoint3 p;
LPoint3 p, rp;
p = LCAST(PN_stdfloat, _pfm.get_point(xi, yi));
from_uv.xform_point_in_place(p);
proj_mat_inv.xform_point_general_in_place(p);
result.set_point(xi, yi, p);
rp = proj_mat_inv.xform_point_general(p);
result.set_point(xi, yi, rp);
}
}
}
} else {
// If the lens is some non-linear specialty lens, we have to call
// Lens::extrude_depth() to correctly extrude each point.
if (_pfm.get_num_channels() == 1) {
// Create an implicit UV coordinate for each point.
LPoint2 uv_scale(1.0, 1.0);
if (_pfm.get_x_size() > 1) {
uv_scale[0] = 1.0 / PN_stdfloat(_pfm.get_x_size());
}
if (_pfm.get_y_size() > 1) {
uv_scale[1] = 1.0 / PN_stdfloat(_pfm.get_y_size());
}
for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
if (!_pfm.has_point(xi, yi)) {
continue;
}
LPoint3 p, rp;
p.set(((PN_stdfloat)xi + 0.5) * uv_scale[0],
((PN_stdfloat)yi + 0.5) * uv_scale[1],
(PN_stdfloat)_pfm.get_point1(xi, yi));
from_uv.xform_point_in_place(p);
lens->extrude_depth(p, rp);
result.set_point(xi, yi, rp);
}
}
} else {
// Use the existing UV coordinate for each point.
for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
if (!_pfm.has_point(xi, yi)) {
continue;
}
LPoint3 p, rp;
p = LCAST(PN_stdfloat, _pfm.get_point(xi, yi));
from_uv.xform_point_in_place(p);
lens->extrude_depth(p, rp);
result.set_point(xi, yi, rp);
}
}
}
}