Panda3D
projectionScreen.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file projectionScreen.cxx
10  * @author drose
11  * @date 2001-12-11
12  */
13 
14 #include "projectionScreen.h"
15 #include "geomNode.h"
16 #include "transformState.h"
17 #include "workingNodePath.h"
18 #include "switchNode.h"
19 #include "geom.h"
20 #include "geomTristrips.h"
21 #include "geomVertexWriter.h"
22 #include "geomVertexReader.h"
23 #include "geomVertexRewriter.h"
24 #include "config_distort.h"
25 #include "cullTraverserData.h"
26 
27 TypeHandle ProjectionScreen::_type_handle;
28 
29 /**
30  *
31  */
32 ProjectionScreen::
33 ProjectionScreen(const std::string &name) : PandaNode(name)
34 {
35  set_cull_callback();
36 
37  _texcoord_name = InternalName::get_texcoord();
38 
39  _has_undist_lut = false;
40  _invert_uvs = project_invert_uvs;
41  _texcoord_3d = false;
42  _vignette_on = false;
43  _vignette_color.set(0.0f, 0.0f, 0.0f, 1.0f);
44  _frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
45  _computed_rel_top_mat = false;
46  _stale = true;
47  _auto_recompute = true;
48 }
49 
50 /**
51  *
52  */
53 ProjectionScreen::
54 ~ProjectionScreen() {
55 }
56 
57 /**
58  *
59  */
60 ProjectionScreen::
61 ProjectionScreen(const ProjectionScreen &copy) :
62  PandaNode(copy),
63  _projector(copy._projector),
64  _projector_node(copy._projector_node),
65  _texcoord_name(copy._texcoord_name),
66  _vignette_on(copy._vignette_on),
67  _vignette_color(copy._vignette_color),
68  _frame_color(copy._frame_color),
69  _auto_recompute(copy._auto_recompute)
70 {
71  _computed_rel_top_mat = false;
72  _stale = true;
73 }
74 
75 /**
76  * Returns a newly-allocated Node that is a shallow copy of this one. It will
77  * be a different Node pointer, but its internal data may or may not be shared
78  * with that of the original Node.
79  */
81 make_copy() const {
82  return new ProjectionScreen(*this);
83 }
84 
85 /**
86  * This function will be called during the cull traversal to perform any
87  * additional operations that should be performed at cull time. This may
88  * include additional manipulation of render state or additional
89  * visible/invisible decisions, or any other arbitrary operation.
90  *
91  * Note that this function will *not* be called unless set_cull_callback() is
92  * called in the constructor of the derived class. It is necessary to call
93  * set_cull_callback() to indicated that we require cull_callback() to be
94  * called.
95  *
96  * By the time this function is called, the node has already passed the
97  * bounding-volume test for the viewing frustum, and the node's transform and
98  * state have already been applied to the indicated CullTraverserData object.
99  *
100  * The return value is true if this node should be visible, or false if it
101  * should be culled.
102  */
105  if (_auto_recompute) {
106  recompute_if_stale(data.get_node_path());
107  }
108  return true;
109 }
110 
111 /**
112  * Specifies the LensNode that is to serve as the projector for this screen.
113  * The relative position of the LensNode to the ProjectionScreen, as well as
114  * the properties of the lens associated with the LensNode, determines the
115  * UV's that will be assigned to the geometry within the ProjectionScreen.
116  *
117  * The NodePath must refer to a LensNode (or a Camera).
118  */
120 set_projector(const NodePath &projector) {
121  _projector_node = nullptr;
122  _projector = projector;
123  if (!projector.is_empty()) {
124  nassertv(projector.node()->is_of_type(LensNode::get_class_type()));
125  _projector_node = DCAST(LensNode, projector.node());
126  _stale = true;
127  }
128 }
129 
130 /**
131  * Synthesizes a polygon mesh based on the projection area of the indicated
132  * projector. This generates and returns a new GeomNode but does not
133  * automatically parent it to the ProjectionScreen node; see
134  * regenerate_screen().
135  *
136  * The specified projector need not be the same as the projector given to the
137  * ProjectionScreen with set_projector() (although this is often what you
138  * want).
139  *
140  * num_x_verts and num_y_verts specify the number of vertices to make in the
141  * grid across the horizontal and vertical dimension of the projector,
142  * respectively; distance represents the approximate distance of the screen
143  * from the lens center.
144  *
145  * The fill_ratio parameter specifies the fraction of the image to cover. If
146  * it is 1.0, the entire image is shown full-size; if it is 0.9, 10% of the
147  * image around the edges is not part of the grid (and the grid is drawn
148  * smaller by the same 10%). This is intended to work around graphics drivers
149  * that tend to show dark edges or other unsatisfactory artifacts around the
150  * edges of textures: render the texture larger than necessary by a certain
151  * fraction, and make the screen smaller by the inverse fraction.
152  */
153 PT(GeomNode) ProjectionScreen::
154 generate_screen(const NodePath &projector, const std::string &screen_name,
155  int num_x_verts, int num_y_verts, PN_stdfloat distance,
156  PN_stdfloat fill_ratio) {
157  nassertr(!projector.is_empty() &&
158  projector.node()->is_of_type(LensNode::get_class_type()),
159  nullptr);
160  LensNode *projector_node = DCAST(LensNode, projector.node());
161  nassertr(projector_node->get_lens() != nullptr, nullptr);
162 
163  // First, get the relative coordinate space of the projector.
164  LMatrix4 rel_mat;
165  NodePath this_np(this);
166  rel_mat = projector.get_transform(this_np)->get_mat();
167 
168  // Create a GeomNode to hold this mesh.
169  PT(GeomNode) geom_node = new GeomNode(screen_name);
170 
171  // Now compute all the vertices for the screen. These are arranged in order
172  // from left to right and bottom to top.
173  int num_verts = num_x_verts * num_y_verts;
174  Lens *lens = projector_node->get_lens();
175  PN_stdfloat t = (distance - lens->get_near()) / (lens->get_far() - lens->get_near());
176 
177  PN_stdfloat x_scale = 2.0f / (num_x_verts - 1);
178  PN_stdfloat y_scale = 2.0f / (num_y_verts - 1);
179 
180  PT(GeomVertexData) vdata = new GeomVertexData
181  ("projectionScreen", GeomVertexFormat::get_v3n3(),
182  Geom::UH_dynamic);
183  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
184  GeomVertexWriter normal(vdata, InternalName::get_normal());
185 
186  for (int yi = 0; yi < num_y_verts; yi++) {
187  for (int xi = 0; xi < num_x_verts; xi++) {
188  LPoint2 film = LPoint2((PN_stdfloat)xi * x_scale - 1.0f,
189  (PN_stdfloat)yi * y_scale - 1.0f);
190 
191  // Reduce the image by the fill ratio.
192  film *= fill_ratio;
193 
194  LPoint3 near_point, far_point;
195  lens->extrude(film, near_point, far_point);
196  LPoint3 point = near_point + t * (far_point - near_point);
197 
198  // Normals aren't often needed on projection screens, but you never
199  // know.
200  LVector3 norm;
201  lens->extrude_vec(film, norm);
202 
203  vertex.add_data3(point * rel_mat);
204  normal.add_data3(-normalize(norm * rel_mat));
205  }
206  }
207  nassertr(vdata->get_num_rows() == num_verts, nullptr);
208 
209  // Now synthesize a triangle mesh. We run triangle strips horizontally
210  // across the grid.
211  PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
212  // Fill up the index array into the vertices. This lays out the order of
213  // the vertices in each tristrip.
214  int ti, si;
215  for (ti = 1; ti < num_y_verts; ti++) {
216  strip->add_vertex(ti * num_x_verts);
217  for (si = 1; si < num_x_verts; si++) {
218  strip->add_vertex((ti - 1) * num_x_verts + (si-1));
219  strip->add_vertex(ti * num_x_verts + si);
220  }
221  strip->add_vertex((ti - 1) * num_x_verts + (num_x_verts-1));
222  strip->close_primitive();
223  }
224 
225  PT(Geom) geom = new Geom(vdata);
226  geom->add_primitive(strip);
227 
228  geom_node->add_geom(geom);
229 
230  _stale = true;
231  ++_last_screen;
232  return geom_node;
233 }
234 
235 /**
236  * Removes all the children from the ProjectionScreen node, and adds the newly
237  * generated child returned by generate_screen().
238  */
240 regenerate_screen(const NodePath &projector, const std::string &screen_name,
241  int num_x_verts, int num_y_verts, PN_stdfloat distance,
242  PN_stdfloat fill_ratio) {
243  // First, remove all existing children.
245 
246  // And attach a new child.
247  PT(GeomNode) geom_node =
248  generate_screen(projector, screen_name, num_x_verts, num_y_verts,
249  distance, fill_ratio);
250  add_child(geom_node);
251 }
252 
253 /**
254  * Generates a deep copy of the hierarchy at the ProjectionScreen node and
255  * below, with vertices flattened into two dimensions as if they were seen by
256  * the indicated camera node.
257  *
258  * This is useful for rendering an image as seen through a non-linear lens.
259  * The resulting mesh will have vertices in the range [-1, 1] in both x and y,
260  * and may be then rendered with an ordinary orthographic lens, to generate
261  * the effect of seeing the image through the specified non-linear lens.
262  *
263  * The returned node has no parent; it is up to the caller to parent it
264  * somewhere or store it so that it does not get dereferenced and deleted.
265  */
266 PT(PandaNode) ProjectionScreen::
267 make_flat_mesh(const NodePath &this_np, const NodePath &camera) {
268  nassertr(!this_np.is_empty() && this_np.node() == this, nullptr);
269  nassertr(!camera.is_empty() &&
270  camera.node()->is_of_type(LensNode::get_class_type()),
271  nullptr);
272  LensNode *camera_node = DCAST(LensNode, camera.node());
273  nassertr(camera_node->get_lens() != nullptr, nullptr);
274 
275  // First, ensure the UV's are up-to-date.
276  recompute_if_stale(this_np);
277 
278  PT(PandaNode) top = new PandaNode(get_name());
279 
280  LMatrix4 rel_mat;
281  bool computed_rel_mat = false;
282  make_mesh_children(top, this_np, camera, rel_mat, computed_rel_mat);
283 
284  return top;
285 }
286 
287 /**
288  * Recomputes all the UV's for geometry below the ProjectionScreen node, as if
289  * the texture were projected from the associated projector.
290  *
291  * This function is normally called automatically whenever the relevant
292  * properties change, so it should not normally need to be called directly by
293  * the user. However, it does no harm to call this if there is any doubt.
294  */
296 recompute() {
297  NodePath this_np(NodePath::any_path(this));
298  do_recompute(this_np);
299 }
300 
301 /**
302  * Calls recompute() only if the relative transform between the
303  * ProjectionScreen and the projector has changed, or if any other relevant
304  * property has changed. Returns true if recomputed, false otherwise.
305  */
308  NodePath this_np(NodePath::any_path(this));
309  return recompute_if_stale(this_np);
310 }
311 
312 /**
313  * Calls recompute() only if the relative transform between the
314  * ProjectionScreen and the projector has changed, or if any other relevant
315  * property has changed. Returns true if recomputed, false otherwise.
316  */
318 recompute_if_stale(const NodePath &this_np) {
319  nassertr(!this_np.is_empty() && this_np.node() == this, false);
320 
321  if (_projector_node != nullptr &&
322  _projector_node->get_lens() != nullptr) {
323  UpdateSeq lens_change = _projector_node->get_lens()->get_last_change();
324  if (_stale || lens_change != _projector_lens_change) {
325  recompute();
326  return true;
327 
328  } else {
329  // Get the relative transform to ensure it hasn't changed.
330  CPT(TransformState) transform = this_np.get_transform(_projector);
331  const LMatrix4 &top_mat = transform->get_mat();
332  if (!_rel_top_mat.almost_equal(top_mat)) {
333  _rel_top_mat = top_mat;
334  _computed_rel_top_mat = true;
335  do_recompute(this_np);
336  return true;
337  }
338  }
339  }
340 
341  return false;
342 }
343 
344 /**
345  * Starts the recomputation process.
346  */
347 void ProjectionScreen::
348 do_recompute(const NodePath &this_np) {
349  if (_projector_node != nullptr &&
350  _projector_node->get_lens() != nullptr) {
351 
352  recompute_node(this_np, _rel_top_mat, _computed_rel_top_mat);
353  // Make sure this flag is set to false for next time.
354  _computed_rel_top_mat = false;
355 
356  _projector_lens_change = _projector_node->get_lens()->get_last_change();
357  _stale = false;
358  }
359 }
360 
361 /**
362  * Recurses over all geometry at the indicated node and below, looking for
363  * GeomNodes that want to have new UV's computed. When a new transform space
364  * is encountered, a new relative matrix is computed.
365  */
366 void ProjectionScreen::
367 recompute_node(const WorkingNodePath &np, LMatrix4 &rel_mat,
368  bool &computed_rel_mat) {
369  PandaNode *node = np.node();
370  if (node->is_geom_node()) {
371  recompute_geom_node(np, rel_mat, computed_rel_mat);
372  }
373 
374  if (node->is_exact_type(SwitchNode::get_class_type())) {
375  // We make a special case for switch nodes only. Other kinds of selective
376  // child nodes, like LOD's and sequence nodes, will get all of their
377  // children traversed; switch nodes will only traverse the currently
378  // active child.
379  int i = DCAST(SwitchNode, node)->get_visible_child();
380  if (i >= 0 && i < node->get_num_children()) {
381  PandaNode *child = node->get_child(i);
382  recompute_child(WorkingNodePath(np, child), rel_mat, computed_rel_mat);
383  }
384 
385  } else {
386  // A non-switch node. Recurse on all children.
387  int num_children = node->get_num_children();
388  for (int i = 0; i < num_children; i++) {
389  PandaNode *child = node->get_child(i);
390  recompute_child(WorkingNodePath(np, child), rel_mat, computed_rel_mat);
391  }
392  }
393 }
394 
395 /**
396  * Works in conjunction with recompute_node() to recurse over the whole graph.
397  * This is called on each child of a given node.
398  */
399 void ProjectionScreen::
400 recompute_child(const WorkingNodePath &np, LMatrix4 &rel_mat,
401  bool &computed_rel_mat) {
402  PandaNode *child = np.node();
403 
404  const TransformState *transform = child->get_transform();
405  if (!transform->is_identity()) {
406  // This child node has a transform; therefore, we must recompute the
407  // relative matrix from this point.
408  LMatrix4 new_rel_mat;
409  bool computed_new_rel_mat = false;
410 
411  if (distort_cat.is_spam()) {
412  distort_cat.spam()
413  << "Saving rel_mat " << (void *)&new_rel_mat << " at " << np << "\n";
414  }
415 
416  recompute_node(np, new_rel_mat, computed_new_rel_mat);
417 
418  } else {
419  // This child has no transform, so we can use the same transform space
420  // from before.
421  recompute_node(np, rel_mat, computed_rel_mat);
422  }
423 }
424 
425 /**
426  * Recomputes the UV's just for the indicated GeomNode.
427  */
428 void ProjectionScreen::
429 recompute_geom_node(const WorkingNodePath &np, LMatrix4 &rel_mat,
430  bool &computed_rel_mat) {
431  GeomNode *node = DCAST(GeomNode, np.node());
432  if (!computed_rel_mat) {
433  // All right, time to compute the matrix.
434  NodePath true_np = np.get_node_path();
435  rel_mat = true_np.get_transform(_projector)->get_mat();
436  computed_rel_mat = true;
437 
438  if (distort_cat.is_spam()) {
439  distort_cat.spam()
440  << "Computing rel_mat " << (void *)&rel_mat << " at " << np << "\n";
441  distort_cat.spam()
442  << " " << rel_mat << "\n";
443  }
444  } else {
445  if (distort_cat.is_spam()) {
446  distort_cat.spam()
447  << "Applying rel_mat " << (void *)&rel_mat << " to " << np << "\n";
448  }
449  }
450 
451  int num_geoms = node->get_num_geoms();
452  for (int i = 0; i < num_geoms; i++) {
453  PT(Geom) geom = node->modify_geom(i);
454  distort_cat.debug()
455  << " " << *node << " got geom " << geom
456  << ", cache_ref = " << geom->get_cache_ref_count() << "\n";
457  geom->test_ref_count_integrity();
458  recompute_geom(geom, rel_mat);
459  }
460 }
461 
462 /**
463  * Recomputes the UV's just for the indicated Geom.
464  */
465 void ProjectionScreen::
466 recompute_geom(Geom *geom, const LMatrix4 &rel_mat) {
467  static const LMatrix4 lens_to_uv
468  (0.5f, 0.0f, 0.0f, 0.0f,
469  0.0f, 0.5f, 0.0f, 0.0f,
470  0.0f, 0.0f, 1.0f, 0.0f,
471  0.5f, 0.5f, 0.0f, 1.0f);
472 
473  static const LMatrix4 lens_to_uv_inverted
474  (0.5f, 0.0f, 0.0f, 0.0f,
475  0.0f,-0.5f, 0.0f, 0.0f,
476  0.0f, 0.0f, 1.0f, 0.0f,
477  0.5f, 0.5f, 0.0f, 1.0f);
478 
479  Thread *current_thread = Thread::get_current_thread();
480 
481  Lens *lens = _projector_node->get_lens();
482  nassertv(lens != nullptr);
483 
484  const LMatrix4 &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv;
485 
486  // Iterate through all the vertices in the Geom.
487  CPT(GeomVertexData) vdata = geom->get_animated_vertex_data(true, current_thread);
488 
489  CPT(GeomVertexFormat) vformat = vdata->get_format();
490  if (!vformat->has_column(_texcoord_name) || (_texcoord_3d && vformat->get_column(_texcoord_name)->get_num_components() < 3)) {
491  // We need to add a new column for the new texcoords.
492  vdata = vdata->replace_column
493  (_texcoord_name, 3, Geom::NT_stdfloat, Geom::C_texcoord);
494  geom->set_vertex_data(vdata);
495  }
496  if (_vignette_on && !vdata->has_column(InternalName::get_color())) {
497  // We need to add a column for color.
498  vdata = vdata->replace_column
499  (InternalName::get_color(), 1, Geom::NT_packed_dabc, Geom::C_color);
500  geom->set_vertex_data(vdata);
501  }
502 
503  // Clear the vdata pointer so we don't force a copy in the below.
504  vdata.clear();
505 
506  PT(GeomVertexData) modify_vdata = geom->modify_vertex_data();
507 
508  // Maybe the vdata has animation that we should consider.
509  CPT(GeomVertexData) animated_vdata = geom->get_animated_vertex_data(true, current_thread);
510 
511  GeomVertexWriter texcoord(modify_vdata, _texcoord_name, current_thread);
512  GeomVertexWriter color(modify_vdata, current_thread);
513  GeomVertexReader vertex(animated_vdata, InternalName::get_vertex(), current_thread);
514 
515  if (_vignette_on) {
516  color.set_column(InternalName::get_color());
517  }
518 
519  while (!vertex.is_at_end()) {
520  LVertex vert = vertex.get_data3();
521 
522  // For each vertex, project to the film plane.
523  LPoint3 vert3d = vert * rel_mat;
524  LPoint3 film(0.0f, 0.0f, 0.0f);
525  bool good = lens->project(vert3d, film);
526 
527  // Now the lens gives us coordinates in the range [-1, 1]. Rescale these
528  // to [0, 1].
529  LPoint3 uvw = film * to_uv;
530 
531  if (good && _has_undist_lut) {
532  LPoint3f p;
533  if (!_undist_lut.calc_bilinear_point(p, uvw[0], 1.0 - uvw[1])) {
534  // Point is missing.
535 
536  // We're better off keeping the point where it is, undistorted--it's
537  // probably close to where it should be--than we are changing it
538  // arbitrarily to (0, 0), which might be far away from where it should
539  // be. uvw.set(0, 0, 0);
540  good = false;
541 
542  } else {
543  uvw = LCAST(PN_stdfloat, p);
544  uvw[1] = 1.0 - uvw[1];
545  }
546  }
547  texcoord.set_data3(uvw);
548 
549  // If we have vignette color in effect, color the vertex according to
550  // whether it fell in front of the lens or not.
551  if (_vignette_on) {
552  if (good) {
553  color.set_data4(_frame_color);
554  } else {
555  color.set_data4(_vignette_color);
556  }
557  }
558  }
559 }
560 
561 /**
562  * Recurses over all geometry at the indicated node and below, and generates a
563  * corresponding node hierarchy with all the geometry copied, but flattened
564  * into 2-d, as seen from the indicated camera. Returns the newly created
565  * node, or NULL if no node was created.
566  */
567 PandaNode *ProjectionScreen::
568 make_mesh_node(PandaNode *result_parent, const WorkingNodePath &np,
569  const NodePath &camera,
570  LMatrix4 &rel_mat, bool &computed_rel_mat) {
571  PandaNode *node = np.node();
572 
573  PT(PandaNode) new_node;
574  if (node->is_geom_node()) {
575  new_node = make_mesh_geom_node(np, camera, rel_mat, computed_rel_mat);
576  } else if (node->safe_to_flatten()) {
577  new_node = node->make_copy();
578  new_node->clear_transform();
579  } else {
580  // If we can't safely flatten the node, just make a plain node in its
581  // place.
582  new_node = new PandaNode(node->get_name());
583  new_node->set_state(node->get_state());
584  }
585 
586  // Now attach the new node to the result.
587  result_parent->add_child(new_node);
588  make_mesh_children(new_node, np, camera, rel_mat, computed_rel_mat);
589  return new_node;
590 }
591 
592 /**
593  * Walks over the list of children for the indicated node, calling
594  * make_mesh_node() on each one.
595  */
596 void ProjectionScreen::
597 make_mesh_children(PandaNode *new_node, const WorkingNodePath &np,
598  const NodePath &camera,
599  LMatrix4 &rel_mat, bool &computed_rel_mat) {
600  PandaNode *node = np.node();
601  int num_children = node->get_num_children();
602  for (int i = 0; i < num_children; i++) {
603  PandaNode *child = node->get_child(i);
604  PandaNode *new_child;
605 
606  const TransformState *transform = child->get_transform();
607  if (!transform->is_identity()) {
608  // This child node has a transform; therefore, we must recompute the
609  // relative matrix from this point.
610  LMatrix4 new_rel_mat;
611  bool computed_new_rel_mat = false;
612  new_child = make_mesh_node(new_node, WorkingNodePath(np, child), camera,
613  new_rel_mat, computed_new_rel_mat);
614 
615  } else {
616  // This child has no transform, so we can use the same transform space
617  // from before.
618  new_child = make_mesh_node(new_node, WorkingNodePath(np, child), camera,
619  rel_mat, computed_rel_mat);
620  }
621 
622  if (new_child != nullptr) {
623  // Copy all of the render state (except TransformState) to the new arc.
624  new_child->set_state(child->get_state());
625  }
626  }
627 }
628 
629 /**
630  * Makes a new GeomNode, just like the given one, except flattened into two
631  * dimensions as seen by the indicated camera.
632  */
633 PT(GeomNode) ProjectionScreen::
634 make_mesh_geom_node(const WorkingNodePath &np, const NodePath &camera,
635  LMatrix4 &rel_mat, bool &computed_rel_mat) {
636  GeomNode *node = DCAST(GeomNode, np.node());
637  PT(GeomNode) new_node = new GeomNode(node->get_name());
638  LensNode *lens_node = DCAST(LensNode, camera.node());
639 
640  if (!computed_rel_mat) {
641  // All right, time to compute the matrix.
642  NodePath true_np = np.get_node_path();
643  rel_mat = true_np.get_transform(camera)->get_mat();
644  computed_rel_mat = true;
645  }
646 
647  int num_geoms = node->get_num_geoms();
648  for (int i = 0; i < num_geoms; i++) {
649  const Geom *geom = node->get_geom(i);
650  PT(Geom) new_geom =
651  make_mesh_geom(geom, lens_node->get_lens(), rel_mat);
652  if (new_geom != nullptr) {
653  new_node->add_geom(new_geom, node->get_geom_state(i));
654  }
655  }
656 
657  return new_node;
658 }
659 
660 /**
661  * Makes a new Geom, just like the given one, except flattened into two
662  * dimensions as seen by the indicated lens. Any triangle in the original
663  * mesh that involves an unprojectable vertex is eliminated.
664  */
665 PT(Geom) ProjectionScreen::
666 make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4 &rel_mat) {
667  static const LMatrix4 lens_to_uv
668  (0.5f, 0.0f, 0.0f, 0.0f,
669  0.0f, 0.5f, 0.0f, 0.0f,
670  0.0f, 0.0f, 1.0f, 0.0f,
671  0.5f, 0.5f, 0.0f, 1.0f);
672  static const LMatrix4 uv_to_lens = invert(lens_to_uv);
673 
674  Thread *current_thread = Thread::get_current_thread();
675  PT(Geom) new_geom = geom->make_copy();
676  new_geom->set_vertex_data(new_geom->get_animated_vertex_data(false, current_thread));
677  PT(GeomVertexData) vdata = new_geom->modify_vertex_data();
678  GeomVertexRewriter vertex(vdata, InternalName::get_vertex());
679  while (!vertex.is_at_end()) {
680  LVertex vert = vertex.get_data3();
681 
682  // Project each vertex into the film plane, but use three dimensions so
683  // the Z coordinate remains meaningful.
684  LPoint3 vert3d = vert * rel_mat;
685  LPoint3 film(0.0f, 0.0f, 0.0f);
686  bool good = lens->project(vert3d, film);
687 
688  if (good && _has_undist_lut) {
689 
690  // Now the lens gives us coordinates in the range [-1, 1]. Rescale these
691  // to [0, 1].
692  LPoint3 uvw = film * lens_to_uv;
693 
694  LPoint3f p;
695  if (!_undist_lut.calc_bilinear_point(p, uvw[0], 1.0 - uvw[1])) {
696  // Point is missing.
697  uvw.set(0, 0, 0);
698  good = false;
699  } else {
700  uvw = LCAST(PN_stdfloat, p);
701  uvw[1] = 1.0 - uvw[1];
702  }
703 
704  film = uvw * uv_to_lens;
705  }
706 
707  vertex.set_data3(film);
708  }
709 
710  return new_geom;
711 }
PandaNode::remove_all_children
void remove_all_children(Thread *current_thread=Thread::get_current_thread())
Removes all the children from the node at once, including stashed children.
Definition: pandaNode.cxx:830
Geom
A container for geometry primitives.
Definition: geom.h:54
TransformState::is_identity
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
Definition: transformState.I:197
GeomVertexFormat::get_v3n3
static const GeomVertexFormat * get_v3n3()
Returns a standard vertex format with a 3-component normal and a 3-component vertex position.
Definition: geomVertexFormat.I:260
UpdateSeq
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
PandaNode::is_geom_node
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2062
Geom::make_copy
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:100
geomVertexWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Geom::set_vertex_data
void set_vertex_data(const GeomVertexData *data)
Replaces the Geom's underlying vertex data table with a completely new table.
Definition: geom.cxx:171
GeomVertexRewriter
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter,...
Definition: geomVertexRewriter.h:33
GeomVertexData
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
Definition: geomVertexData.h:68
ProjectionScreen
A ProjectionScreen implements a simple system for projective texturing.
Definition: projectionScreen.h:48
geomVertexReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PfmFile::calc_bilinear_point
bool calc_bilinear_point(LPoint3f &result, PN_float32 x, PN_float32 y) const
Computes the weighted average of the four nearest points to the floating- point index (x,...
Definition: pfmFile.cxx:689
projectionScreen.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexWriter::add_data3
void add_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row.
Definition: geomVertexWriter.I:1132
GeomVertexWriter
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
Definition: geomVertexWriter.h:55
ProjectionScreen::recompute_if_stale
bool recompute_if_stale()
Calls recompute() only if the relative transform between the ProjectionScreen and the projector has c...
Definition: projectionScreen.cxx:307
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
GeomVertexReader
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
Definition: geomVertexReader.h:47
PandaNode::set_state
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
Definition: pandaNode.h:173
TransformState::get_mat
get_mat
Returns the matrix that describes the transform.
Definition: transformState.h:156
NodePath::get_transform
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:791
WorkingNodePath::get_node_path
get_node_path
Constructs and returns an actual NodePath that represents the same path we have just traversed.
Definition: workingNodePath.h:60
GeomNode::get_num_geoms
get_num_geoms
Returns the number of geoms in the node.
Definition: geomNode.h:71
ProjectionScreen::recompute
void recompute()
Recomputes all the UV's for geometry below the ProjectionScreen node, as if the texture were projecte...
Definition: projectionScreen.cxx:296
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
GeomNode
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:34
ProjectionScreen::regenerate_screen
void regenerate_screen(const NodePath &projector, const std::string &screen_name, int num_x_verts, int num_y_verts, PN_stdfloat distance, PN_stdfloat fill_ratio)
Removes all the children from the ProjectionScreen node, and adds the newly generated child returned ...
Definition: projectionScreen.cxx:240
cullTraverserData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
switchNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexRewriter::is_at_end
bool is_at_end() const
Returns true if the reader or writer is currently at the end of the list of vertices,...
Definition: geomVertexRewriter.I:291
Lens::extrude_vec
bool extrude_vec(const LPoint2 &point2d, LVector3 &vec3d) const
Given a 2-d point in the range (-1,1) in both dimensions, where (0,0) is the center of the lens and (...
Definition: lens.I:72
transformState.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ProjectionScreen::make_copy
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
Definition: projectionScreen.cxx:81
Lens::project
bool project(const LPoint3 &point3d, LPoint3 &point2d) const
Given a 3-d point in space, determine the 2-d point this maps to, in the range (-1,...
Definition: lens.I:131
PT
PT(GeomNode) ProjectionScreen
Synthesizes a polygon mesh based on the projection area of the indicated projector.
Definition: projectionScreen.cxx:153
WorkingNodePath
This is a class designed to support low-overhead traversals of the complete scene graph,...
Definition: workingNodePath.h:39
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
ReferenceCount::test_ref_count_integrity
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
Definition: referenceCount.I:197
WorkingNodePath::node
PandaNode * node() const
Returns the node traversed to so far.
Definition: workingNodePath.I:89
Lens::get_near
get_near
Returns the position of the near plane (or cylinder, sphere, whatever).
Definition: lens.h:113
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
geomVertexRewriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::get_child
get_child
Returns the nth child node of this node.
Definition: pandaNode.h:124
Lens
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
geom.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexReader::get_data3
const LVecBase3 & get_data3()
Returns the data associated with the read row, expressed as a 3-component value, and advances the rea...
Definition: geomVertexReader.I:577
GeomVertexFormat
This class defines the physical layout of the vertex data stored within a Geom.
Definition: geomVertexFormat.h:55
LensNode::get_lens
Lens * get_lens(int index=0) const
Returns a pointer to the particular Lens associated with this LensNode, or NULL if there is not yet a...
Definition: lensNode.I:47
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
workingNodePath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ProjectionScreen::set_projector
void set_projector(const NodePath &projector)
Specifies the LensNode that is to serve as the projector for this screen.
Definition: projectionScreen.cxx:120
SwitchNode
A node that renders only one of its children, according to the user's indication.
Definition: switchNode.h:25
LensNode
A node that contains a Lens.
Definition: lensNode.h:29
PandaNode::make_copy
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
Definition: pandaNode.cxx:481
PandaNode::safe_to_flatten
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of PandaNode by duplicating ...
Definition: pandaNode.cxx:195
config_distort.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomTristrips
Defines a series of triangle strips.
Definition: geomTristrips.h:23
GeomVertexWriter::set_data3
void set_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row.
Definition: geomVertexWriter.I:640
geomTristrips.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomNode::get_geom_state
get_geom_state
Returns the RenderState associated with the nth geom of the node.
Definition: geomNode.h:75
geomNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::get_num_children
get_num_children
Returns the number of child nodes this node has.
Definition: pandaNode.h:124
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
NodePath::node
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
Lens::get_far
get_far
Returns the position of the far plane (or cylinder, sphere, whatever).
Definition: lens.h:114
TypedObject::is_exact_type
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
ProjectionScreen::cull_callback
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
Definition: projectionScreen.cxx:104
NodePath::any_path
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node.
Definition: nodePath.I:62
Lens::extrude
bool extrude(const LPoint2 &point2d, LPoint3 &near_point, LPoint3 &far_point) const
Given a 2-d point in the range (-1,1) in both dimensions, where (0,0) is the center of the lens and (...
Definition: lens.I:24
TypedObject::is_of_type
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
NodePath::is_empty
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188