33 ProjectionScreen(
const std::string &name) :
PandaNode(name)
37 _texcoord_name = InternalName::get_texcoord();
39 _has_undist_lut =
false;
40 _invert_uvs = project_invert_uvs;
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;
47 _auto_recompute =
true;
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)
71 _computed_rel_top_mat =
false;
105 if (_auto_recompute) {
121 _projector_node =
nullptr;
122 _projector = projector;
124 nassertv(projector.
node()->
is_of_type(LensNode::get_class_type()));
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) {
161 nassertr(projector_node->
get_lens() !=
nullptr,
nullptr);
173 int num_verts = num_x_verts * num_y_verts;
177 PN_stdfloat x_scale = 2.0f / (num_x_verts - 1);
178 PN_stdfloat y_scale = 2.0f / (num_y_verts - 1);
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);
194 LPoint3 near_point, far_point;
195 lens->
extrude(film, near_point, far_point);
196 LPoint3 point = near_point + t * (far_point - near_point);
204 normal.
add_data3(-normalize(norm * rel_mat));
207 nassertr(vdata->get_num_rows() == num_verts,
nullptr);
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);
221 strip->add_vertex((ti - 1) * num_x_verts + (num_x_verts-1));
222 strip->close_primitive();
226 geom->add_primitive(strip);
228 geom_node->add_geom(geom);
241 int num_x_verts,
int num_y_verts, PN_stdfloat distance,
242 PN_stdfloat fill_ratio) {
248 generate_screen(projector, screen_name, num_x_verts, num_y_verts,
249 distance, fill_ratio);
250 add_child(geom_node);
268 nassertr(!this_np.
is_empty() && this_np.
node() ==
this,
nullptr);
273 nassertr(camera_node->
get_lens() !=
nullptr,
nullptr);
281 bool computed_rel_mat =
false;
282 make_mesh_children(top, this_np, camera, rel_mat, computed_rel_mat);
298 do_recompute(this_np);
319 nassertr(!this_np.
is_empty() && this_np.
node() ==
this,
false);
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) {
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);
347 void ProjectionScreen::
348 do_recompute(
const NodePath &this_np) {
349 if (_projector_node !=
nullptr &&
350 _projector_node->get_lens() !=
nullptr) {
352 recompute_node(this_np, _rel_top_mat, _computed_rel_top_mat);
354 _computed_rel_top_mat =
false;
356 _projector_lens_change = _projector_node->get_lens()->get_last_change();
366 void ProjectionScreen::
368 bool &computed_rel_mat) {
371 recompute_geom_node(np, rel_mat, computed_rel_mat);
379 int i = DCAST(
SwitchNode, node)->get_visible_child();
382 recompute_child(
WorkingNodePath(np, child), rel_mat, computed_rel_mat);
388 for (
int i = 0; i < num_children; i++) {
390 recompute_child(
WorkingNodePath(np, child), rel_mat, computed_rel_mat);
399 void ProjectionScreen::
401 bool &computed_rel_mat) {
408 LMatrix4 new_rel_mat;
409 bool computed_new_rel_mat =
false;
411 if (distort_cat.is_spam()) {
413 <<
"Saving rel_mat " << (
void *)&new_rel_mat <<
" at " << np <<
"\n";
416 recompute_node(np, new_rel_mat, computed_new_rel_mat);
421 recompute_node(np, rel_mat, computed_rel_mat);
428 void ProjectionScreen::
430 bool &computed_rel_mat) {
432 if (!computed_rel_mat) {
436 computed_rel_mat =
true;
438 if (distort_cat.is_spam()) {
440 <<
"Computing rel_mat " << (
void *)&rel_mat <<
" at " << np <<
"\n";
442 <<
" " << rel_mat <<
"\n";
445 if (distort_cat.is_spam()) {
447 <<
"Applying rel_mat " << (
void *)&rel_mat <<
" to " << np <<
"\n";
452 for (
int i = 0; i < num_geoms; i++) {
453 PT(
Geom) geom = node->modify_geom(i);
455 <<
" " << *node <<
" got geom " << geom
456 <<
", cache_ref = " << geom->get_cache_ref_count() <<
"\n";
458 recompute_geom(geom, rel_mat);
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);
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);
481 Lens *lens = _projector_node->get_lens();
482 nassertv(lens !=
nullptr);
484 const LMatrix4 &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv;
487 CPT(
GeomVertexData) vdata = geom->get_animated_vertex_data(
true, current_thread);
490 if (!vformat->has_column(_texcoord_name) || (_texcoord_3d && vformat->get_column(_texcoord_name)->get_num_components() < 3)) {
492 vdata = vdata->replace_column
493 (_texcoord_name, 3, Geom::NT_stdfloat, Geom::C_texcoord);
496 if (_vignette_on && !vdata->has_column(InternalName::get_color())) {
498 vdata = vdata->replace_column
499 (InternalName::get_color(), 1, Geom::NT_packed_dabc, Geom::C_color);
509 CPT(
GeomVertexData) animated_vdata = geom->get_animated_vertex_data(
true, current_thread);
513 GeomVertexReader vertex(animated_vdata, InternalName::get_vertex(), current_thread);
516 color.set_column(InternalName::get_color());
519 while (!vertex.is_at_end()) {
520 LVertex vert = vertex.get_data3();
523 LPoint3 vert3d = vert * rel_mat;
524 LPoint3 film(0.0f, 0.0f, 0.0f);
525 bool good = lens->
project(vert3d, film);
529 LPoint3 uvw = film * to_uv;
531 if (good && _has_undist_lut) {
543 uvw = LCAST(PN_stdfloat, p);
544 uvw[1] = 1.0 - uvw[1];
547 texcoord.set_data3(uvw);
553 color.set_data4(_frame_color);
555 color.set_data4(_vignette_color);
570 LMatrix4 &rel_mat,
bool &computed_rel_mat) {
575 new_node = make_mesh_geom_node(np, camera, rel_mat, computed_rel_mat);
578 new_node->clear_transform();
582 new_node =
new PandaNode(node->get_name());
583 new_node->set_state(node->get_state());
587 result_parent->add_child(new_node);
588 make_mesh_children(new_node, np, camera, rel_mat, computed_rel_mat);
596 void ProjectionScreen::
599 LMatrix4 &rel_mat,
bool &computed_rel_mat) {
602 for (
int i = 0; i < num_children; i++) {
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);
618 new_child = make_mesh_node(new_node,
WorkingNodePath(np, child), camera,
619 rel_mat, computed_rel_mat);
622 if (new_child !=
nullptr) {
624 new_child->
set_state(child->get_state());
635 LMatrix4 &rel_mat,
bool &computed_rel_mat) {
640 if (!computed_rel_mat) {
644 computed_rel_mat =
true;
648 for (
int i = 0; i < num_geoms; i++) {
649 const Geom *geom = node->get_geom(i);
651 make_mesh_geom(geom, lens_node->
get_lens(), rel_mat);
652 if (new_geom !=
nullptr) {
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);
676 new_geom->
set_vertex_data(new_geom->get_animated_vertex_data(
false, current_thread));
684 LPoint3 vert3d = vert * rel_mat;
685 LPoint3 film(0.0f, 0.0f, 0.0f);
686 bool good = lens->
project(vert3d, film);
688 if (good && _has_undist_lut) {
692 LPoint3 uvw = film * lens_to_uv;
700 uvw = LCAST(PN_stdfloat, p);
701 uvw[1] = 1.0 - uvw[1];
704 film = uvw * uv_to_lens;