16 #include "fadeLodNode.h" 17 #include "cullTraverserData.h" 18 #include "cullTraverser.h" 19 #include "config_pgraphnodes.h" 20 #include "geomVertexData.h" 21 #include "geomVertexWriter.h" 22 #include "geomVertexFormat.h" 23 #include "geomTristrips.h" 24 #include "mathNumbers.h" 27 #include "transformState.h" 29 #include "materialAttrib.h" 30 #include "materialPool.h" 31 #include "renderState.h" 32 #include "cullFaceAttrib.h" 33 #include "textureAttrib.h" 34 #include "boundingSphere.h" 35 #include "geometricBoundingVolume.h" 38 #include "shaderAttrib.h" 39 #include "colorAttrib.h" 40 #include "clipPlaneAttrib.h" 51 make_default_lod(
const string &name) {
52 switch (default_lod_type.get_value()) {
61 <<
"Invalid LODNodeType value: " << (int)default_lod_type <<
"\n";
119 cdata->_center = cdata->_center * mat;
124 PN_stdfloat factor = y.
length();
126 SwitchVector::iterator si;
127 for (si = cdata->_switch_vector.begin();
128 si != cdata->_switch_vector.end();
130 (*si).rescale(factor);
162 return show_switches_cull_callback(trav, data);
165 consider_verify_lods(trav, data);
169 CPT(TransformState) rel_transform = get_rel_transform(trav, data);
170 LPoint3 center = cdata->_center * rel_transform->get_mat();
171 PN_stdfloat dist2 = center.dot(center);
173 int num_children = min(
get_num_children(), (
int)cdata->_switch_vector.size());
174 for (
int index = 0; index < num_children; ++index) {
175 const Switch &sw = cdata->_switch_vector[index];
177 if (cdata->_got_force_switch) {
178 in_range = (cdata->_force_switch == index);
180 in_range = sw.in_range_2(dist2 * cdata->_lod_scale
205 output(ostream &out)
const {
206 PandaNode::output(out);
208 out <<
" center(" << cdata->_center <<
") ";
209 if (cdata->_switch_vector.empty()) {
210 out <<
"no switches.";
212 SwitchVector::const_iterator si;
213 si = cdata->_switch_vector.begin();
214 out <<
"(" << (*si).get_in() <<
"/" << (*si).get_out() <<
")";
216 while (si != cdata->_switch_vector.end()) {
217 out <<
" (" << (*si).get_in() <<
"/" << (*si).get_out() <<
")";
257 do_show_switch(cdata, index, get_default_show_color(index));
258 mark_internal_bounds_stale();
280 do_show_switch(cdata, index, color);
281 mark_internal_bounds_stale();
292 do_hide_switch(cdata, index);
293 mark_internal_bounds_stale();
304 for (
int i = 0; i < (int)cdata->_switch_vector.size(); ++i) {
305 do_show_switch(cdata, i, get_default_show_color(i));
307 mark_internal_bounds_stale();
319 for (
int i = 0; i < (int)cdata->_switch_vector.size(); ++i) {
320 do_hide_switch(cdata, i);
322 mark_internal_bounds_stale();
339 for (
int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
340 PN_stdfloat suggested_radius;
341 if (!do_verify_child_bounds(cdata, index, suggested_radius)) {
342 const Switch &sw = cdata->_switch_vector[index];
344 <<
"Level " << index <<
" geometry of " << *
this 345 <<
" is larger than its switch radius; suggest radius of " 346 << suggested_radius <<
" instead of " << sw.get_in() <<
"\n";
363 if (data.get_net_transform(trav)->is_singular()) {
371 if (cdata->_got_force_switch) {
372 return cdata->_force_switch;
375 CPT(TransformState) rel_transform = get_rel_transform(trav, data);
376 LPoint3 center = cdata->_center * rel_transform->get_mat();
377 PN_stdfloat dist2 = center.dot(center);
379 for (
int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
380 if (cdata->_switch_vector[index].in_range_2(dist2 * cdata->_lod_scale
382 if (pgraph_cat.is_debug()) {
384 << data._node_path <<
" at distance " << sqrt(dist2)
385 <<
", selected child " << index <<
"\n";
392 if (pgraph_cat.is_debug()) {
394 << data._node_path <<
" at distance " << sqrt(dist2)
395 <<
", no children in range.\n";
414 CPT(TransformState) rel_transform = get_rel_transform(trav, data);
415 LPoint3 center = cdata->_center * rel_transform->get_mat();
416 PN_stdfloat dist2 = center.dot(center);
421 look_at(mat, -center,
LVector3(0.0f, 0.0f, 1.0f));
423 CPT(TransformState) viz_transform =
424 rel_transform->invert_compose(TransformState::make_mat(mat));
426 for (
int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
427 const Switch &sw = cdata->_switch_vector[index];
430 if (cdata->_got_force_switch) {
431 in_range = (cdata->_force_switch == index);
433 in_range = sw.in_range_2(dist2);
443 next_data3._state = next_data3._state->compose(sw.get_viz_model_state());
451 RenderState::make_empty(),
452 RenderEffects::make_empty(),
453 ClipPlaneAttrib::make());
461 RenderState::make_empty(),
462 RenderEffects::make_empty(),
463 ClipPlaneAttrib::make());
483 int &internal_vertices,
485 Thread *current_thread)
const {
496 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
498 SwitchVector::const_iterator si;
499 for (si = cdata->_switch_vector.begin();
500 si != cdata->_switch_vector.end();
502 const Switch &sw = (*si);
505 child_volumes.push_back(sphere);
506 pt_volumes.push_back(sphere);
511 const BoundingVolume **child_end = child_begin + child_volumes.size();
513 bound->around(child_begin, child_end);
516 internal_bounds = bound;
517 internal_vertices = 0;
526 CPT(TransformState) LODNode::
532 CPT(TransformState) rel_transform;
537 lod_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
542 cull_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
544 rel_transform = data.get_modelview_transform(trav);
548 return rel_transform;
557 do_show_switch(LODNode::CData *cdata,
int index,
const LColor &color) {
558 nassertv(index >= 0 && index < (
int)cdata->_switch_vector.size());
560 if (!cdata->_switch_vector[index].is_shown()) {
563 cdata->_switch_vector[index].show(color);
572 do_hide_switch(LODNode::CData *cdata,
int index) {
573 nassertv(index >= 0 && index < (
int)cdata->_switch_vector.size());
575 if (cdata->_switch_vector[index].is_shown()) {
578 cdata->_switch_vector[index].hide();
592 do_verify_child_bounds(
const LODNode::CData *cdata,
int index,
593 PN_stdfloat &suggested_radius)
const {
594 suggested_radius = 0.0f;
597 const Switch &sw = cdata->_switch_vector[index];
603 if (seq == sw._bounds_seq) {
606 return sw._verify_ok;
609 ((Switch &)sw)._bounds_seq = seq;
610 ((Switch &)sw)._verify_ok =
true;
612 if (bv->is_empty()) {
616 if (bv->is_infinite()) {
624 const Switch &sw = cdata->_switch_vector[index];
627 DCAST_INTO_R(gbv, bv,
false);
631 int flags = sphere.contains(gbv);
632 if ((flags & BoundingVolume::IF_all) != 0) {
642 sphere.extend_by(gbv);
643 suggested_radius = sphere.get_radius();
644 ((Switch &)sw)._verify_ok =
false;
651 LPoint3 min_point(0.0f, 0.0f, 0.0f);
652 LPoint3 max_point(0.0f, 0.0f, 0.0f);
654 bool found_any =
false;
655 child->calc_tight_bounds(min_point, max_point, found_any,
656 TransformState::make_identity(),
667 LPoint3 box_center = (min_point + max_point) / 2.0f;
668 PN_stdfloat box_radius = min(min(max_point[0] - box_center[0],
669 max_point[1] - box_center[1]),
670 max_point[2] - box_center[2]);
677 flags = sphere.contains(&box_sphere);
678 if ((flags & BoundingVolume::IF_all) == 0) {
681 sphere.extend_by(&box_sphere);
683 sphere.extend_by(gbv);
685 suggested_radius = sphere.get_radius();
686 ((Switch &)sw)._verify_ok =
false;
706 if (cdata->_got_force_switch) {
713 if (seq != cdata->_bounds_seq) {
715 for (
int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
716 PN_stdfloat suggested_radius;
717 if (!do_verify_child_bounds(cdata, index, suggested_radius)) {
718 const Switch &sw = cdata->_switch_vector[index];
721 <<
"Level " << index <<
" geometry of " << data._node_path
722 <<
" is larger than its switch radius; suggest radius of " 723 << suggested_radius <<
" instead of " << sw.get_in()
724 <<
" (configure verify-lods 0 to ignore this error)";
725 nassert_raise(strm.str());
729 cdataw->_bounds_seq = seq;
740 get_default_show_color(
int index) {
741 static LColor default_colors[] = {
742 LColor(1.0f, 0.0f, 0.0f, 0.7f),
743 LColor(0.0f, 1.0f, 0.0f, 0.7f),
744 LColor(0.0f, 0.0f, 1.0f, 0.7f),
745 LColor(0.0f, 1.0f, 1.0f, 0.7f),
746 LColor(1.0f, 0.0f, 1.0f, 0.7f),
747 LColor(1.0f, 1.0f, 0.0f, 0.7f),
749 static const int num_default_colors =
sizeof(default_colors) /
sizeof(
LColor);
751 return default_colors[index % num_default_colors];
793 parse_params(params, scan, manager);
794 node->fillin(scan, manager);
808 PandaNode::fillin(scan, manager);
819 return new CData(*
this);
828 void LODNode::CData::
832 for (
size_t i = 1; i < _switch_vector.size(); ++i) {
833 if (_switch_vector[i].
get_out() > _switch_vector[_lowest].get_out()) {
836 if (_switch_vector[i].
get_in() < _switch_vector[_highest].get_in()) {
848 void LODNode::CData::
850 _center.write_datagram(dg);
854 SwitchVector::const_iterator si;
855 for (si = _switch_vector.begin();
856 si != _switch_vector.end();
858 (*si).write_datagram(dg);
869 void LODNode::CData::
871 _center.read_datagram(scan);
873 _switch_vector.clear();
876 _switch_vector.reserve(num_switches);
877 for (
int i = 0; i < num_switches; i++) {
879 sw.read_datagram(scan);
881 _switch_vector.push_back(sw);
892 void LODNode::Switch::
896 static const int num_slices = 50;
897 static const int num_rings = 1;
901 static const PN_stdfloat edge_ratio = 0.1;
903 const GeomVertexFormat *format = GeomVertexFormat::get_v3n3cp();
913 for (ri = 0; ri <= num_rings; ++ri) {
915 PN_stdfloat r = (PN_stdfloat)ri / (PN_stdfloat)num_rings;
918 PN_stdfloat d = r * (_in - _out) + _out;
920 for (si = 0; si < num_slices; ++si) {
922 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
925 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
927 PN_stdfloat x = ccos(t);
928 PN_stdfloat y = csin(t);
936 for (ri = 0; ri <= 1; ++ri) {
937 PN_stdfloat r = (PN_stdfloat)ri;
938 PN_stdfloat d = r * (_in - _out) + _out;
940 for (si = 0; si < num_slices; ++si) {
941 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
942 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
944 PN_stdfloat x = ccos(t);
945 PN_stdfloat y = csin(t);
947 vertex.
add_data3(x * d, y * d, 0.5f * edge_ratio * d);
952 for (si = 0; si < num_slices; ++si) {
953 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
954 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
956 PN_stdfloat x = ccos(t);
957 PN_stdfloat y = csin(t);
959 vertex.
add_data3(x * d, y * d, -0.5f * edge_ratio * d);
967 for (ri = 0; ri < num_rings; ++ri) {
968 for (si = 0; si < num_slices; ++si) {
969 strips->add_vertex(ri * num_slices + si);
970 strips->add_vertex((ri + 1) * num_slices + si);
972 strips->add_vertex(ri * num_slices);
973 strips->add_vertex((ri + 1) * num_slices);
974 strips->close_primitive();
979 for (ri = 0; ri <= 1; ++ri) {
980 for (si = 0; si < num_slices; ++si) {
981 strips->add_vertex((num_rings + 1 + ri * 2) * num_slices + si);
982 strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices + si);
984 strips->add_vertex((num_rings + 1 + ri * 2) * num_slices);
985 strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices);
986 strips->close_primitive();
989 PT(
Geom) ring_geom =
new Geom(vdata);
990 ring_geom->add_primitive(strips);
993 geom_node->add_geom(ring_geom);
997 material->set_twoside(
true);
1001 RenderState::make(CullFaceAttrib::make(CullFaceAttrib::M_cull_none),
1002 TextureAttrib::make_off(),
1003 ShaderAttrib::make_off(),
1004 MaterialAttrib::make(material),
1005 RenderState::get_max_priority());
1006 if (_show_color[3] != 1.0f) {
1007 viz_state = viz_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha),
1008 RenderState::get_max_priority());
1011 geom_node->set_state(viz_state);
1013 _ring_viz = geom_node.p();
1022 void LODNode::Switch::
1023 compute_spindle_viz() {
1028 static const int num_slices = 10;
1029 static const int num_rings = 10;
1031 const GeomVertexFormat *format = GeomVertexFormat::get_v3n3cp();
1040 for (ri = 0; ri <= num_rings; ++ri) {
1042 PN_stdfloat r = (PN_stdfloat)ri / (PN_stdfloat)num_rings;
1045 PN_stdfloat z = 100.0f - r * 200.0f;
1047 for (si = 0; si < num_slices; ++si) {
1049 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
1052 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
1054 PN_stdfloat x = ccos(t);
1055 PN_stdfloat y = csin(t);
1064 for (ri = 0; ri < num_rings; ++ri) {
1065 for (si = 0; si < num_slices; ++si) {
1066 strips->add_vertex(ri * num_slices + si);
1067 strips->add_vertex((ri + 1) * num_slices + si);
1069 strips->add_vertex(ri * num_slices);
1070 strips->add_vertex((ri + 1) * num_slices);
1071 strips->close_primitive();
1074 PT(
Geom) spindle_geom =
new Geom(vdata);
1075 spindle_geom->add_primitive(strips);
1078 geom_node->add_geom(spindle_geom);
1081 RenderState::make(CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise),
1082 TextureAttrib::make_off(),
1083 ShaderAttrib::make_off(),
1084 RenderState::get_max_priority());
1085 if (_show_color[3] != 1.0f) {
1086 viz_state = viz_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha),
1087 RenderState::get_max_priority());
1090 geom_node->set_state(viz_state);
1092 _spindle_viz = geom_node.p();
1101 void LODNode::Switch::
1102 compute_viz_model_state() {
1106 _viz_model_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
1107 TextureAttrib::make_off(),
1108 ShaderAttrib::make_off(),
1109 ColorAttrib::make_flat(_show_color),
1110 RenderState::get_max_priority());
1111 CPT(
RenderState) st2 = RenderState::make(TransparencyAttrib::make(TransparencyAttrib::M_none),
1112 RenderState::get_max_priority());
1113 _viz_model_state = _viz_model_state->compose(st2);
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...
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.
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.
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
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.
A single page of data maintained by a PipelineCycler.
const NodePath & get_cull_center() const
Returns the point from which the culling operations will be performed, if it was set by set_cull_cent...
Base class for objects that can be written to and read from Bam files.
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
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 ...
PN_stdfloat get_out(int index) const
Returns the "out" distance of the indicated switch range.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Defines a series of triangle strips.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
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.
void add_data4(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat w)
Sets the write row to a particular 4-component value, and advances the write row. ...
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
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.
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.
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
A Level-of-Detail node with alpha based switching.
const NodePath & get_lod_center() const
Returns the point from which the LOD distances will be measured, if it was set by set_lod_center()...
This is a 4-by-4 transform matrix.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
PN_stdfloat get_in(int index) const
Returns the "in" distance of the indicated switch range.
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
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...
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. ...
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...
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 register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
This is the base class for all three-component vectors and points.
void apply_transform_and_state(CullTraverser *trav)
Applies the transform and state from the current node onto the current data.
This class is similar to CycleDataReader, except it allows reading from a particular stage of the pip...
float length() const
Returns the length of the vector, by the Pythagorean theorem.
bool is_any_shown() const
Returns true if any switch has been shown with show_switch(), indicating the LODNode is in debug show...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
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.
PN_stdfloat get_lod_scale() const
Returns the multiplier for LOD distances.
void set_row(int row, const LVecBase4f &v)
Replaces the indicated row of the matrix.
A class to retrieve the individual data elements previously stored in a Datagram. ...
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 ...
LVecBase3f get_row3(int row) const
Retrieves the row column of the matrix as a 3-component vector, ignoring the last column...
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.
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other...