48 make_default_lod(
const std::string &name) {
49 switch (default_lod_type.get_value()) {
58 <<
"Invalid LODNodeType value: " << (int)default_lod_type <<
"\n";
102 cdata->_center = cdata->_center * mat;
107 PN_stdfloat factor = y.length();
109 SwitchVector::iterator si;
110 for (si = cdata->_switch_vector.begin();
111 si != cdata->_switch_vector.end();
113 (*si).rescale(factor);
138 return show_switches_cull_callback(trav, data);
141 consider_verify_lods(trav, data);
145 CPT(
TransformState) rel_transform = get_rel_transform(trav, data);
146 LPoint3 center = cdata->_center * rel_transform->get_mat();
147 PN_stdfloat dist2 = center.dot(center);
149 int num_children = std::min(
get_num_children(), (
int)cdata->_switch_vector.size());
150 for (
int index = 0; index < num_children; ++index) {
151 const Switch &sw = cdata->_switch_vector[index];
153 if (cdata->_got_force_switch) {
154 in_range = (cdata->_force_switch == index);
156 in_range = sw.in_range_2(dist2 * cdata->_lod_scale
163 if (child !=
nullptr) {
179 output(std::ostream &out)
const {
180 PandaNode::output(out);
181 CDReader cdata(_cycler);
182 out <<
" center(" << cdata->_center <<
") ";
183 if (cdata->_switch_vector.empty()) {
184 out <<
"no switches.";
186 SwitchVector::const_iterator si;
187 si = cdata->_switch_vector.begin();
188 out <<
"(" << (*si).get_in() <<
"/" << (*si).get_out() <<
")";
190 while (si != cdata->_switch_vector.end()) {
191 out <<
" (" << (*si).get_in() <<
"/" << (*si).get_out() <<
")";
223 do_show_switch(cdata, index, get_default_show_color(index));
224 mark_internal_bounds_stale();
241 do_show_switch(cdata, index, color);
242 mark_internal_bounds_stale();
251 do_hide_switch(cdata, index);
252 mark_internal_bounds_stale();
261 for (
int i = 0; i < (int)cdata->_switch_vector.size(); ++i) {
262 do_show_switch(cdata, i, get_default_show_color(i));
264 mark_internal_bounds_stale();
273 for (
int i = 0; i < (int)cdata->_switch_vector.size(); ++i) {
274 do_hide_switch(cdata, i);
276 mark_internal_bounds_stale();
290 for (
int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
291 PN_stdfloat suggested_radius;
292 if (!do_verify_child_bounds(cdata, index, suggested_radius)) {
293 const Switch &sw = cdata->_switch_vector[index];
295 <<
"Level " << index <<
" geometry of " << *
this 296 <<
" is larger than its switch radius; suggest radius of " 297 << suggested_radius <<
" instead of " << sw.get_in() <<
"\n";
312 if (data.get_net_transform(trav)->is_singular()) {
318 CDReader cdata(_cycler);
320 if (cdata->_got_force_switch) {
321 return cdata->_force_switch;
324 CPT(
TransformState) rel_transform = get_rel_transform(trav, data);
325 LPoint3 center = cdata->_center * rel_transform->get_mat();
326 PN_stdfloat dist2 = center.dot(center);
328 for (
int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
329 if (cdata->_switch_vector[index].in_range_2(dist2 * cdata->_lod_scale
331 if (pgraph_cat.is_debug()) {
333 << data.get_node_path() <<
" at distance " << sqrt(dist2)
334 <<
", selected child " << index <<
"\n";
341 if (pgraph_cat.is_debug()) {
343 << data.get_node_path() <<
" at distance " << sqrt(dist2)
344 <<
", no children in range.\n";
358 CDReader cdata(_cycler);
360 CPT(
TransformState) rel_transform = get_rel_transform(trav, data);
361 LPoint3 center = cdata->_center * rel_transform->get_mat();
362 PN_stdfloat dist2 = center.dot(center);
367 look_at(mat, -center, LVector3(0.0f, 0.0f, 1.0f));
368 mat.set_row(3, center);
370 rel_transform->invert_compose(TransformState::make_mat(mat));
372 for (
int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
373 const Switch &sw = cdata->_switch_vector[index];
376 if (cdata->_got_force_switch) {
377 in_range = (cdata->_force_switch == index);
379 in_range = sw.in_range_2(dist2);
387 if (child !=
nullptr) {
389 next_data3._state = next_data3._state->compose(sw.get_viz_model_state());
420 int &internal_vertices,
422 Thread *current_thread)
const {
433 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
435 SwitchVector::const_iterator si;
436 for (si = cdata->_switch_vector.begin();
437 si != cdata->_switch_vector.end();
439 const Switch &sw = (*si);
442 child_volumes.push_back(sphere);
443 pt_volumes.push_back(sphere);
448 const BoundingVolume **child_end = child_begin + child_volumes.size();
450 bound->around(child_begin, child_end);
453 internal_bounds = bound;
454 internal_vertices = 0;
472 lod_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
477 cull_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
479 rel_transform = data.get_modelview_transform(trav);
483 return rel_transform;
490 do_show_switch(LODNode::CData *cdata,
int index,
const LColor &color) {
491 nassertv(index >= 0 && index < (
int)cdata->_switch_vector.size());
493 if (!cdata->_switch_vector[index].is_shown()) {
496 cdata->_switch_vector[index].show(color);
503 do_hide_switch(LODNode::CData *cdata,
int index) {
504 nassertv(index >= 0 && index < (
int)cdata->_switch_vector.size());
506 if (cdata->_switch_vector[index].is_shown()) {
509 cdata->_switch_vector[index].hide();
520 do_verify_child_bounds(
const LODNode::CData *cdata,
int index,
521 PN_stdfloat &suggested_radius)
const {
522 suggested_radius = 0.0f;
525 const Switch &sw = cdata->_switch_vector[index];
527 if (child !=
nullptr) {
531 if (seq == sw._bounds_seq) {
534 return sw._verify_ok;
537 ((Switch &)sw)._bounds_seq = seq;
538 ((Switch &)sw)._verify_ok =
true;
540 if (bv->is_empty()) {
544 if (bv->is_infinite()) {
552 const Switch &sw = cdata->_switch_vector[index];
555 DCAST_INTO_R(gbv, bv,
false);
559 int flags = sphere.contains(gbv);
560 if ((flags & BoundingVolume::IF_all) != 0) {
570 sphere.extend_by(gbv);
571 suggested_radius = sphere.get_radius();
572 ((Switch &)sw)._verify_ok =
false;
579 LPoint3 min_point(0.0f, 0.0f, 0.0f);
580 LPoint3 max_point(0.0f, 0.0f, 0.0f);
582 bool found_any =
false;
583 child->calc_tight_bounds(min_point, max_point, found_any,
584 TransformState::make_identity(),
585 Thread::get_current_thread());
595 LPoint3 box_center = (min_point + max_point) / 2.0f;
596 PN_stdfloat box_radius = std::min(std::min(max_point[0] - box_center[0],
597 max_point[1] - box_center[1]),
598 max_point[2] - box_center[2]);
601 box_sphere.local_object();
605 flags = sphere.contains(&box_sphere);
606 if ((flags & BoundingVolume::IF_all) == 0) {
609 sphere.extend_by(&box_sphere);
611 sphere.extend_by(gbv);
613 suggested_radius = sphere.get_radius();
614 ((Switch &)sw)._verify_ok =
false;
630 CDLockedReader cdata(_cycler);
632 if (cdata->_got_force_switch) {
639 if (seq != cdata->_bounds_seq) {
641 for (
int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
642 PN_stdfloat suggested_radius;
643 if (!do_verify_child_bounds(cdata, index, suggested_radius)) {
644 const Switch &sw = cdata->_switch_vector[index];
645 std::ostringstream strm;
647 <<
"Level " << index <<
" geometry of " << data.get_node_path()
648 <<
" is larger than its switch radius; suggest radius of " 649 << suggested_radius <<
" instead of " << sw.get_in()
650 <<
" (configure verify-lods 0 to ignore this error)";
651 nassert_raise(strm.str());
654 CDWriter cdataw(_cycler, cdata);
655 cdataw->_bounds_seq = seq;
662 const LColor &LODNode::
663 get_default_show_color(
int index) {
664 static LColor default_colors[] = {
665 LColor(1.0f, 0.0f, 0.0f, 0.7f),
666 LColor(0.0f, 1.0f, 0.0f, 0.7f),
667 LColor(0.0f, 0.0f, 1.0f, 0.7f),
668 LColor(0.0f, 1.0f, 1.0f, 0.7f),
669 LColor(1.0f, 0.0f, 1.0f, 0.7f),
670 LColor(1.0f, 1.0f, 0.0f, 0.7f),
672 static const int num_default_colors =
sizeof(default_colors) /
sizeof(LColor);
674 return default_colors[index % num_default_colors];
709 node->fillin(scan, manager);
720 PandaNode::fillin(scan, manager);
729 return new CData(*
this);
736 void LODNode::CData::
740 for (
size_t i = 1; i < _switch_vector.size(); ++i) {
741 if (_switch_vector[i].get_out() > _switch_vector[_lowest].get_out()) {
744 if (_switch_vector[i].get_in() < _switch_vector[_highest].get_in()) {
754 void LODNode::CData::
756 _center.write_datagram(dg);
760 SwitchVector::const_iterator si;
761 for (si = _switch_vector.begin();
762 si != _switch_vector.end();
764 (*si).write_datagram(dg);
772 void LODNode::CData::
774 _center.read_datagram(scan);
776 _switch_vector.clear();
779 _switch_vector.reserve(num_switches);
780 for (
int i = 0; i < num_switches; i++) {
782 sw.read_datagram(scan);
784 _switch_vector.push_back(sw);
793 void LODNode::Switch::
797 static const int num_slices = 50;
798 static const int num_rings = 1;
802 static const PN_stdfloat edge_ratio = 0.1;
814 for (ri = 0; ri <= num_rings; ++ri) {
816 PN_stdfloat r = (PN_stdfloat)ri / (PN_stdfloat)num_rings;
819 PN_stdfloat d = r * (_in - _out) + _out;
821 for (si = 0; si < num_slices; ++si) {
823 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
826 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
828 PN_stdfloat x = ccos(t);
829 PN_stdfloat y = csin(t);
830 vertex.add_data3(x * d, y * d, 0.0f);
831 normal.add_data3(0.0f, 0.0f, 1.0f);
832 color.add_data4(_show_color);
837 for (ri = 0; ri <= 1; ++ri) {
838 PN_stdfloat r = (PN_stdfloat)ri;
839 PN_stdfloat d = r * (_in - _out) + _out;
841 for (si = 0; si < num_slices; ++si) {
842 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
843 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
845 PN_stdfloat x = ccos(t);
846 PN_stdfloat y = csin(t);
848 vertex.add_data3(x * d, y * d, 0.5f * edge_ratio * d);
849 normal.add_data3(x, y, 0.0f);
850 color.add_data4(_show_color);
853 for (si = 0; si < num_slices; ++si) {
854 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
855 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
857 PN_stdfloat x = ccos(t);
858 PN_stdfloat y = csin(t);
860 vertex.add_data3(x * d, y * d, -0.5f * edge_ratio * d);
861 normal.add_data3(x, y, 0.0f);
862 color.add_data4(_show_color);
868 for (ri = 0; ri < num_rings; ++ri) {
869 for (si = 0; si < num_slices; ++si) {
870 strips->add_vertex(ri * num_slices + si);
871 strips->add_vertex((ri + 1) * num_slices + si);
873 strips->add_vertex(ri * num_slices);
874 strips->add_vertex((ri + 1) * num_slices);
875 strips->close_primitive();
879 for (ri = 0; ri <= 1; ++ri) {
880 for (si = 0; si < num_slices; ++si) {
881 strips->add_vertex((num_rings + 1 + ri * 2) * num_slices + si);
882 strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices + si);
884 strips->add_vertex((num_rings + 1 + ri * 2) * num_slices);
885 strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices);
886 strips->close_primitive();
890 ring_geom->add_primitive(strips);
893 geom_node->add_geom(ring_geom);
897 material->set_twoside(
true);
901 RenderState::make(CullFaceAttrib::make(CullFaceAttrib::M_cull_none),
902 TextureAttrib::make_off(),
903 ShaderAttrib::make_off(),
904 MaterialAttrib::make(material),
905 RenderState::get_max_priority());
906 if (_show_color[3] != 1.0f) {
907 viz_state = viz_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha),
908 RenderState::get_max_priority());
911 geom_node->set_state(viz_state);
913 _ring_viz = geom_node.p();
920 void LODNode::Switch::
921 compute_spindle_viz() {
925 static const int num_slices = 10;
926 static const int num_rings = 10;
937 for (ri = 0; ri <= num_rings; ++ri) {
939 PN_stdfloat r = (PN_stdfloat)ri / (PN_stdfloat)num_rings;
942 PN_stdfloat z = 100.0f - r * 200.0f;
944 for (si = 0; si < num_slices; ++si) {
946 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
949 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
951 PN_stdfloat x = ccos(t);
952 PN_stdfloat y = csin(t);
953 vertex.add_data3(x, y, z);
954 normal.add_data3(x, y, 0.0f);
955 color.add_data4(_show_color);
961 for (ri = 0; ri < num_rings; ++ri) {
962 for (si = 0; si < num_slices; ++si) {
963 strips->add_vertex(ri * num_slices + si);
964 strips->add_vertex((ri + 1) * num_slices + si);
966 strips->add_vertex(ri * num_slices);
967 strips->add_vertex((ri + 1) * num_slices);
968 strips->close_primitive();
972 spindle_geom->add_primitive(strips);
975 geom_node->add_geom(spindle_geom);
978 RenderState::make(CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise),
979 TextureAttrib::make_off(),
980 ShaderAttrib::make_off(),
981 RenderState::get_max_priority());
982 if (_show_color[3] != 1.0f) {
983 viz_state = viz_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha),
984 RenderState::get_max_priority());
987 geom_node->set_state(viz_state);
989 _spindle_viz = geom_node.p();
996 void LODNode::Switch::
997 compute_viz_model_state() {
1001 _viz_model_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
1002 TextureAttrib::make_off(),
1003 ShaderAttrib::make_off(),
1004 ColorAttrib::make_flat(_show_color),
1005 RenderState::get_max_priority());
1006 CPT(
RenderState) st2 = RenderState::make(TransparencyAttrib::make(TransparencyAttrib::M_none),
1007 RenderState::get_max_priority());
1008 _viz_model_state = _viz_model_state->compose(st2);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A basic node of the scene graph or data graph.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
static Material * get_material(Material *temp)
Returns a Material pointer that represents the same material described by temp, except that it is a s...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
bool is_empty() const
Returns true if the NodePath contains no nodes.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This defines a bounding sphere, consisting of a center and a radius.
bool is_infinite() const
The other side of the empty coin is an infinite volume.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A single page of data maintained by a PipelineCycler.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Base class for objects that can be written to and read from Bam files.
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Defines a series of triangle strips.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
void hide_switch(int index)
Disables a previous call to show_switch().
void hide_all_switches()
Hides all levels, restoring the LODNode to normal operation.
get_lod_center
Returns the point from which the LOD distances will be measured, if it was set by set_lod_center(),...
void apply_transform(const TransformState *node_transform)
Applies the indicated transform changes onto the current data.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
CPT(TransformState) LODNode
Returns the relative transform to convert from the LODNode space to the camera space.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL vector.
static void register_with_read_factory()
Tells the BamReader how to create objects of type LODNode.
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
void show_switch(int index)
This is provided as a debugging aid.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
PT(LODNode) LODNode
Creates a new LODNode of the type specified by the default-lod-type config variable.
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
get_num_children
Returns the number of child nodes this node has.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A Level-of-Detail node with alpha based switching.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for geometry primitives.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this PandaNode by the indicated matrix, if it means anything to do so.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Camera * get_camera_node() const
Returns the camera used to render the scene.
virtual bool is_lod_node() const
A simple downcast check.
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_cull_center
Returns the point from which the culling operations will be performed, if it was set by set_cull_cent...
Defines the way an object appears in the presence of lighting.
bool verify_child_bounds() const
Returns true if the bounding volumes for the geometry of each fhild node entirely fits within the swi...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_any_shown() const
Returns true if any switch has been shown with show_switch(), indicating the LODNode is in debug show...
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A thread; that is, a lightweight process.
void show_all_switches()
Shows all levels in their default colors.
SceneSetup * get_scene() const
Returns the SceneSetup object.
A class to retrieve the individual data elements previously stored in a Datagram.
get_child
Returns the nth child node of this node.
TypeHandle is the identifier used to differentiate C++ class types.
This is a sequence number that increments monotonically.
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
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.
get_lod_scale
Returns the multiplier for LOD distances.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.