Panda3D
Loading...
Searching...
No Matches
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
27TypeHandle ProjectionScreen::_type_handle;
28
29/**
30 *
31 */
32ProjectionScreen::
33ProjectionScreen(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 */
53ProjectionScreen::
54~ProjectionScreen() {
55}
56
57/**
58 *
59 */
60ProjectionScreen::
61ProjectionScreen(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 */
81make_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 */
120set_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 */
153PT(GeomNode) ProjectionScreen::
154generate_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 */
240regenerate_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 */
266PT(PandaNode) ProjectionScreen::
267make_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 */
296recompute() {
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 */
318recompute_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 */
347void ProjectionScreen::
348do_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 */
366void ProjectionScreen::
367recompute_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 */
399void ProjectionScreen::
400recompute_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 */
428void ProjectionScreen::
429recompute_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";
458 recompute_geom(geom, rel_mat);
459 }
460}
461
462/**
463 * Recomputes the UV's just for the indicated Geom.
464 */
465void ProjectionScreen::
466recompute_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 */
567PandaNode *ProjectionScreen::
568make_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 */
596void ProjectionScreen::
597make_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 */
633PT(GeomNode) ProjectionScreen::
634make_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 */
665PT(Geom) ProjectionScreen::
666make_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}
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
A node that holds Geom objects, renderable pieces of geometry.
Definition geomNode.h:34
get_num_geoms
Returns the number of geoms in the node.
Definition geomNode.h:71
get_geom_state
Returns the RenderState associated with the nth geom of the node.
Definition geomNode.h:75
Defines a series of triangle strips.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This class defines the physical layout of the vertex data stored within a Geom.
static const GeomVertexFormat * get_v3n3()
Returns a standard vertex format with a 3-component normal and a 3-component vertex position.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
const LVecBase3 & get_data3()
Returns the data associated with the read row, expressed as a 3-component value, and advances the rea...
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter,...
bool is_at_end() const
Returns true if the reader or writer is currently at the end of the list of vertices,...
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
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.
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.
A container for geometry primitives.
Definition geom.h:54
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition geom.cxx:100
void set_vertex_data(const GeomVertexData *data)
Replaces the Geom's underlying vertex data table with a completely new table.
Definition geom.cxx:171
A node that contains a Lens.
Definition lensNode.h:29
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
A base class for any number of different kinds of lenses, linear and otherwise.
Definition lens.h:41
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
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
get_far
Returns the position of the far plane (or cylinder, sphere, whatever).
Definition lens.h:114
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
get_near
Returns the position of the near plane (or cylinder, sphere, whatever).
Definition lens.h:113
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
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
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition nodePath.I:188
PandaNode * node() const
Returns the referenced node of the path.
Definition nodePath.I:227
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition nodePath.cxx:794
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
virtual bool is_geom_node() const
A simple downcast check.
void remove_all_children(Thread *current_thread=Thread::get_current_thread())
Removes all the children from the node at once, including stashed children.
get_child
Returns the nth child node of this node.
Definition pandaNode.h:124
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
Definition pandaNode.h:173
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of PandaNode by duplicating ...
get_num_children
Returns the number of child nodes this node has.
Definition pandaNode.h:124
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
A ProjectionScreen implements a simple system for projective texturing.
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
void recompute()
Recomputes all the UV's for geometry below the ProjectionScreen node, as if the texture were projecte...
bool recompute_if_stale()
Calls recompute() only if the relative transform between the ProjectionScreen and the projector has c...
void set_projector(const NodePath &projector)
Specifies the LensNode that is to serve as the projector for this 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 ...
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
A node that renders only one of its children, according to the user's indication.
Definition switchNode.h:25
A thread; that is, a lightweight process.
Definition thread.h:46
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition thread.h:109
Indicates a coordinate-system transform on vertices.
get_mat
Returns the matrix that describes the transform.
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition typedObject.I:38
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition typedObject.I:28
This is a sequence number that increments monotonically.
Definition updateSeq.h:37
This is a class designed to support low-overhead traversals of the complete scene graph,...
PandaNode * node() const
Returns the node traversed to so far.
get_node_path
Constructs and returns an actual NodePath that represents the same path we have just traversed.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.