Panda3D
fadeLodNode.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 fadeLodNode.cxx
10  * @author sshodhan
11  * @date 2004-06-14
12  */
13 
14 #include "fadeLodNode.h"
15 #include "fadeLodNodeData.h"
16 #include "cullTraverserData.h"
17 #include "cullTraverser.h"
18 #include "clockObject.h"
19 #include "colorScaleAttrib.h"
20 #include "depthWriteAttrib.h"
21 #include "transparencyAttrib.h"
22 #include "cullBinAttrib.h"
23 #include "depthOffsetAttrib.h"
24 
25 TypeHandle FadeLODNode::_type_handle;
26 
27 /**
28  *
29  */
30 FadeLODNode::
31 FadeLODNode(const std::string &name) :
32  LODNode(name)
33 {
34  set_cull_callback();
35 
36  _fade_time = lod_fade_time;
37  _fade_bin_name = lod_fade_bin_name;
38  _fade_bin_draw_order = lod_fade_bin_draw_order;
39  _fade_state_override = lod_fade_state_override;
40 }
41 
42 /**
43  *
44  */
45 FadeLODNode::
46 FadeLODNode(const FadeLODNode &copy) :
47  LODNode(copy)
48 {
49  _fade_time = copy._fade_time;
50  _fade_bin_name = copy._fade_bin_name;
51  _fade_bin_draw_order = copy._fade_bin_draw_order;
52  _fade_state_override = copy._fade_state_override;
53 }
54 
55 /**
56  * Returns a newly-allocated Node that is a shallow copy of this one. It will
57  * be a different Node pointer, but its internal data may or may not be shared
58  * with that of the original Node.
59  */
61 make_copy() const {
62  return new FadeLODNode(*this);
63 }
64 
65 /**
66  * This function will be called during the cull traversal to perform any
67  * additional operations that should be performed at cull time. This may
68  * include additional manipulation of render state or additional
69  * visible/invisible decisions, or any other arbitrary operation.
70  *
71  * Note that this function will *not* be called unless set_cull_callback() is
72  * called in the constructor of the derived class. It is necessary to call
73  * set_cull_callback() to indicated that we require cull_callback() to be
74  * called.
75  *
76  * By the time this function is called, the node has already passed the
77  * bounding-volume test for the viewing frustum, and the node's transform and
78  * state have already been applied to the indicated CullTraverserData object.
79  *
80  * The return value is true if this node should be visible, or false if it
81  * should be culled.
82  */
83 bool FadeLODNode::
85  if (!support_fade_lod) {
86  return LODNode::cull_callback(trav, data);
87  }
88 
89  if (is_any_shown()) {
90  return show_switches_cull_callback(trav, data);
91  }
92 
93  consider_verify_lods(trav, data);
94 
95  Camera *camera = trav->get_scene()->get_camera_node();
96  NodePath this_np = data.get_node_path();
97  FadeLODNodeData *ldata =
98  DCAST(FadeLODNodeData, camera->get_aux_scene_data(this_np));
99 
101 
102  if (ldata == nullptr || now > ldata->get_expiration_time()) {
103  // This is the first time we have rendered this instance of this LOD node
104  // in a while.
105  ldata = new FadeLODNodeData;
106  ldata->_fade_mode = FadeLODNodeData::FM_solid;
107  ldata->_fade_out = -1;
108  ldata->_fade_in = compute_child(trav, data);
109  camera->set_aux_scene_data(this_np, ldata);
110 
111  } else {
112  // We had rendered this LOD node last frame (or not too long ago, at
113  // least).
114 
115  if (ldata->_fade_mode == FadeLODNodeData::FM_solid) {
116  // We were drawing just one solid child last frame; check whether it's
117  // time to begin a transition.
118  int index = compute_child(trav, data);
119  if (index != ldata->_fade_in) {
120  // Start a transition.
121  if (index >= 0 && ldata->_fade_in >= 0 &&
122  get_out(index) > get_out(ldata->_fade_in)) {
123  // We are fading from a more-detailed model to a less-detailed
124  // model.
125  ldata->_fade_mode = FadeLODNodeData::FM_less_detail;
126  } else {
127  // We are fading from a less-detailed model to a more-detailed
128  // model.
129  ldata->_fade_mode = FadeLODNodeData::FM_more_detail;
130  }
131 
132  // We start the fade as of the last frame we actually rendered; that
133  // way, if the object happened to be offscreen for a large part of the
134  // fade, we'll just view the tail end of it--a little nicer.
135  ldata->_fade_start = ldata->get_last_render_time();
136  ldata->_fade_out = ldata->_fade_in;
137  ldata->_fade_in = index;
138  }
139  }
140 
141  if (ldata->_fade_mode != FadeLODNodeData::FM_solid) {
142  // Play the transition.
143 
144  PN_stdfloat elapsed = now - ldata->_fade_start;
145 
146  if (elapsed >= _fade_time) {
147  // Transition complete.
148  ldata->_fade_mode = FadeLODNodeData::FM_solid;
149 
150  } else {
151  PN_stdfloat half_fade_time = _fade_time * 0.5f;
152 
153  int in_child = ldata->_fade_in;
154  int out_child = ldata->_fade_out;
155 
156  if (ldata->_fade_mode == FadeLODNodeData::FM_less_detail) {
157  // If we're fading from a more-detailed model to a less-detailed
158  // model, reverse the fade effect for best visual quality.
159  elapsed = _fade_time - elapsed;
160  int t = in_child;
161  in_child = out_child;
162  out_child = t;
163  }
164 
165  nassertr(elapsed >= 0.0f && elapsed <= _fade_time, false);
166 
167  if (elapsed < half_fade_time) {
168  // FIRST HALF OF FADE Fade the new LOD in with z writing off Keep
169  // drawing the old LOD opaque with z writing on
170  if (out_child >= 0 && out_child < get_num_children()) {
171  PandaNode *child = get_child(out_child);
172  if (child != nullptr) {
173  CullTraverserData next_data_out(data, child);
174  next_data_out._state =
175  next_data_out._state->compose(get_fade_1_old_state());
176  trav->traverse(next_data_out);
177  }
178  }
179 
180  if (in_child >= 0 && in_child < get_num_children()) {
181  PandaNode *child = get_child(in_child);
182  if (child != nullptr) {
183  CullTraverserData next_data_in(data, child);
184 
185  PN_stdfloat in_alpha = elapsed / half_fade_time;
186  next_data_in._state =
187  next_data_in._state->compose(get_fade_1_new_state(in_alpha));
188  trav->traverse(next_data_in);
189  }
190  }
191 
192  } else {
193  // SECOND HALF OF FADE: Fade out the old LOD with z write off and
194  // draw the opaque new LOD with z write on
195  if (in_child >= 0 && in_child < get_num_children()) {
196  PandaNode *child = get_child(in_child);
197  if (child != nullptr) {
198  CullTraverserData next_data_in(data, child);
199  next_data_in._state =
200  next_data_in._state->compose(get_fade_2_new_state());
201  trav->traverse(next_data_in);
202  }
203  }
204 
205  if (out_child >= 0 && out_child < get_num_children()) {
206  PandaNode *child = get_child(out_child);
207  if (child != nullptr) {
208  CullTraverserData next_data_out(data, child);
209 
210  PN_stdfloat out_alpha = 1.0f - (elapsed - half_fade_time) / half_fade_time;
211  next_data_out._state =
212  next_data_out._state->compose(get_fade_2_old_state(out_alpha));
213  trav->traverse(next_data_out);
214  }
215  }
216  }
217  }
218  }
219  }
220 
221  if (ldata->_fade_mode == FadeLODNodeData::FM_solid) {
222  // This is the normal case: we're not in the middle of a transition; we're
223  // just drawing one child of the LOD.
224  int index = ldata->_fade_in;
225  if (index >= 0 && index < get_num_children()) {
226  PandaNode *child = get_child(index);
227  if (child != nullptr) {
228  CullTraverserData next_data(data, child);
229  trav->traverse(next_data);
230  }
231  }
232  }
233 
234  ldata->set_last_render_time(now);
235  ldata->set_duration(_fade_time);
236 
237  return false;
238 }
239 
240 /**
241  *
242  */
243 void FadeLODNode::
244 output(std::ostream &out) const {
245  LODNode::output(out);
246  out << " fade time: " << _fade_time;
247 }
248 
249 /**
250  * Specifies the cull bin and draw order that is assigned to the fading part
251  * of the geometry during a transition.
252  */
253 void FadeLODNode::
254 set_fade_bin(const std::string &name, int draw_order) {
255  _fade_bin_name = name;
256  _fade_bin_draw_order = draw_order;
257  _fade_1_new_state.clear();
258  _fade_2_old_state.clear();
259 }
260 
261 /**
262  * Specifies the override value that is applied to the state changes necessary
263  * to apply the fade effect. This should be larger than any attrib overrides
264  * on the fading geometry.
265  */
266 void FadeLODNode::
267 set_fade_state_override(int override) {
268  _fade_state_override = override;
269  _fade_1_old_state.clear();
270  _fade_1_new_state.clear();
271  _fade_2_old_state.clear();
272  _fade_2_new_state.clear();
273 }
274 
275 /**
276  * Returns a RenderState for rendering the old element during first half of
277  * fade.
278  */
279 CPT(RenderState) FadeLODNode::
280 get_fade_1_old_state() {
281  if (_fade_1_old_state == nullptr) {
282  _fade_1_old_state = RenderState::make_empty();
283  }
284 
285  return _fade_1_old_state;
286 }
287 
288 /**
289  * Returns a RenderState for rendering the new element during first half of
290  * fade.
291  */
292 CPT(RenderState) FadeLODNode::
293 get_fade_1_new_state(PN_stdfloat in_alpha) {
294  if (_fade_1_new_state == nullptr) {
295  _fade_1_new_state = RenderState::make
296  (TransparencyAttrib::make(TransparencyAttrib::M_alpha),
297  CullBinAttrib::make(_fade_bin_name, _fade_bin_draw_order),
298  DepthOffsetAttrib::make(),
299  _fade_state_override);
300  }
301 
302  LVecBase4 alpha_scale(1.0f, 1.0f, 1.0f, in_alpha);
303  return _fade_1_new_state->compose
304  (RenderState::make(ColorScaleAttrib::make(alpha_scale)));
305 }
306 
307 /**
308  * Returns a RenderState for rendering the old element during second half of
309  * fade.
310  */
311 CPT(RenderState) FadeLODNode::
312 get_fade_2_old_state(PN_stdfloat out_alpha) {
313  if (_fade_2_old_state == nullptr) {
314  _fade_2_old_state = RenderState::make
315  (TransparencyAttrib::make(TransparencyAttrib::M_alpha),
316  DepthWriteAttrib::make(DepthWriteAttrib::M_off),
317  CullBinAttrib::make(_fade_bin_name, _fade_bin_draw_order),
318  _fade_state_override);
319  }
320 
321  LVecBase4 alpha_scale(1.0f, 1.0f, 1.0f, out_alpha);
322  return _fade_2_old_state->compose
323  (RenderState::make(ColorScaleAttrib::make(alpha_scale)));
324 }
325 
326 /**
327  * Returns a RenderState for rendering the new element during second half of
328  * fade.
329  */
330 CPT(RenderState) FadeLODNode::
331 get_fade_2_new_state() {
332  if (_fade_2_new_state == nullptr) {
333  _fade_2_new_state = RenderState::make
334  (DepthOffsetAttrib::make(),
335  _fade_state_override);
336  }
337 
338  return _fade_2_new_state;
339 }
340 
341 /**
342  * Tells the BamReader how to create objects of type LODNode.
343  */
344 void FadeLODNode::
346  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
347 }
348 
349 /**
350  * Writes the contents of this object to the datagram for shipping out to a
351  * Bam file.
352  */
353 void FadeLODNode::
355  LODNode::write_datagram(manager, dg);
356 }
357 
358 /**
359  * This function is called by the BamReader's factory when a new object of
360  * type LODNode is encountered in the Bam file. It should create the LODNode
361  * and extract its information from the file.
362  */
363 TypedWritable *FadeLODNode::
364 make_from_bam(const FactoryParams &params) {
365  FadeLODNode *node = new FadeLODNode("");
366  DatagramIterator scan;
367  BamReader *manager;
368 
369  parse_params(params, scan, manager);
370  node->fillin(scan, manager);
371 
372  return node;
373 }
374 
375 /**
376  * This internal function is called by make_from_bam to read in all of the
377  * relevant data from the BamFile for the new FadeLODNode.
378  */
379 void FadeLODNode::
380 fillin(DatagramIterator &scan, BamReader *manager) {
381  LODNode::fillin(scan, manager);
382 }
This is the data that is associated with a particular instance of the FadeLODNode for the scene graph...
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
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: fadeLodNode.cxx:84
double get_expiration_time() const
Returns the frame_time at which this AuxSceneData object is currently scheduled to be removed from th...
Definition: auxSceneData.I:67
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_duration(double duration)
Specifies the minimum length in time, in seconds, to keep this AuxSceneData object around in the scen...
Definition: auxSceneData.I:31
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
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...
Definition: bamReader.h:110
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
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: lodNode.cxx:136
This collects together the pieces of data that are accumulated for each node while walking the scene ...
set_fade_state_override
Specifies the override value that is applied to the state changes necessary to apply the fade effect.
Definition: fadeLodNode.h:49
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 ...
Definition: bamWriter.h:63
CPT(RenderState) FadeLODNode
Returns a RenderState for rendering the old element during first half of fade.
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
double get_last_render_time() const
Returns the last time this object was used during traversal (according to set_last_render_time()).
Definition: auxSceneData.I:58
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
Definition: fadeLodNode.cxx:61
void set_fade_bin(const std::string &name, int draw_order)
Specifies the cull bin and draw order that is assigned to the fading part of the geometry during a tr...
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
get_num_children
Returns the number of child nodes this node has.
Definition: pandaNode.h:124
A Level-of-Detail node with alpha based switching.
Definition: fadeLodNode.h:24
void set_last_render_time(double render_time)
Should be called with the current frame_time each time the AuxSceneData is used during traversal.
Definition: auxSceneData.I:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.h:91
A Level-of-Detail node.
Definition: lodNode.h:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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.
Definition: factory.I:73
Camera * get_camera_node() const
Returns the camera used to render the scene.
Definition: sceneSetup.I:115
get_aux_scene_data
Returns the AuxSceneData associated with the indicated NodePath, or NULL if nothing is associated.
Definition: camera.h:103
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
bool is_any_shown() const
Returns true if any switch has been shown with show_switch(), indicating the LODNode is in debug show...
Definition: lodNode.I:218
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
SceneSetup * get_scene() const
Returns the SceneSetup object.
Definition: cullTraverser.I:35
A class to retrieve the individual data elements previously stored in a Datagram.
get_child
Returns the nth child node of this node.
Definition: pandaNode.h:124
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
Definition: camera.h:35
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: lodNode.cxx:691
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_out
Returns the "out" distance of the indicated switch range.
Definition: lodNode.h:61
static void register_with_read_factory()
Tells the BamReader how to create objects of type LODNode.