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  */
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  */
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  */
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  */
354 write_datagram(BamWriter *manager, Datagram &dg) {
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 }
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
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
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
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
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
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
Definition: camera.h:35
get_aux_scene_data
Returns the AuxSceneData associated with the indicated NodePath, or NULL if nothing is associated.
Definition: camera.h:103
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
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
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,...
Definition: cullTraverser.h:45
SceneSetup * get_scene() const
Returns the SceneSetup object.
Definition: cullTraverser.I:35
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
A class to retrieve the individual data elements previously stored in a Datagram.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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
This is the data that is associated with a particular instance of the FadeLODNode for the scene graph...
A Level-of-Detail node with alpha based switching.
Definition: fadeLodNode.h:24
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
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
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...
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.
Definition: fadeLodNode.cxx:61
static void register_with_read_factory()
Tells the BamReader how to create objects of type LODNode.
A Level-of-Detail node.
Definition: lodNode.h:28
get_out
Returns the "out" distance of the indicated switch range.
Definition: lodNode.h:61
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
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
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
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
get_child
Returns the nth child node of this node.
Definition: pandaNode.h:124
get_num_children
Returns the number of child nodes this node has.
Definition: pandaNode.h:124
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
Camera * get_camera_node() const
Returns the camera used to render the scene.
Definition: sceneSetup.I:115
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
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.
CPT(RenderState) FadeLODNode
Returns a RenderState for rendering the old element during first half of fade.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.