Panda3D

billboardEffect.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 billboardEffect.cxx
10 * @author drose
11 * @date 2002-03-14
12 */
13
14 #include "billboardEffect.h"
15 #include "cullTraverser.h"
16 #include "cullTraverserData.h"
17 #include "nodePath.h"
18 #include "look_at.h"
19 #include "bamReader.h"
20 #include "bamWriter.h"
21 #include "datagram.h"
22 #include "datagramIterator.h"
23
24 TypeHandle BillboardEffect::_type_handle;
25
26 /**
27 * Constructs a new BillboardEffect object with the indicated properties.
28 */
29 CPT(RenderEffect) BillboardEffect::
30 make(const LVector3 &up_vector, bool eye_relative,
31 bool axial_rotate, PN_stdfloat offset, const NodePath &look_at,
32 const LPoint3 &look_at_point, bool fixed_depth) {
33 BillboardEffect *effect = new BillboardEffect;
34 effect->_up_vector = up_vector;
35 effect->_eye_relative = eye_relative;
36 effect->_axial_rotate = axial_rotate;
37 effect->_offset = offset;
38 effect->_look_at = look_at;
39 effect->_look_at_point = look_at_point;
40 effect->_fixed_depth = fixed_depth;
41 effect->_off = false;
42 return return_new(effect);
43 }
44
45 /**
46 * Returns true if it is generally safe to transform this particular kind of
47 * RenderEffect by calling the xform() method, false otherwise.
48 */
49 bool BillboardEffect::
50 safe_to_transform() const {
51 return false;
52 }
53
54 /**
55 * Preprocesses the accumulated transform that is about to be applied to (or
56 * through) this node due to a flatten operation. The returned value will be
57 * used instead.
58 */
59 CPT(TransformState) BillboardEffect::
60 prepare_flatten_transform(const TransformState *net_transform) const {
61 // We don't want any flatten operation to rotate the billboarded node, since
62 // the billboard effect should eat any rotation that comes in from above.
63 return net_transform->set_hpr(LVecBase3(0, 0, 0));
64 }
65
66 /**
67 *
68 */
69 void BillboardEffect::
70 output(std::ostream &out) const {
71 out << get_type() << ":";
72 if (is_off()) {
73 out << "(off)";
74 } else {
75 if (_axial_rotate) {
76 out << "(axis";
77 } else {
78 out << "(point";
79 }
80 if (!_up_vector.almost_equal(LVector3::up())) {
81 out << " up " << _up_vector;
82 }
83 if (_eye_relative) {
84 out << " eye";
85 }
86 if (_fixed_depth) {
87 out << " depth " << -_offset;
88 } else if (_offset != 0.0f) {
89 out << " offset " << _offset;
90 }
91 if (!_look_at.is_empty()) {
92 out << " look at " << _look_at;
93 }
94 if (!_look_at_point.almost_equal(LPoint3(0.0f, 0.0f, 0.0f))) {
95 out << " look at point " << _look_at_point;
96 }
97 out << ")";
98 }
99 }
100
101 /**
102 * Should be overridden by derived classes to return true if cull_callback()
103 * has been defined. Otherwise, returns false to indicate cull_callback()
104 * does not need to be called for this effect during the cull traversal.
105 */
106 bool BillboardEffect::
107 has_cull_callback() const {
108 return true;
109 }
110
111 /**
112 * If has_cull_callback() returns true, this function will be called during
113 * the cull traversal to perform any additional operations that should be
114 * performed at cull time. This may include additional manipulation of render
115 * state or additional visible/invisible decisions, or any other arbitrary
116 * operation.
117 *
118 * At the time this function is called, the current node's transform and state
119 * have not yet been applied to the net_transform and net_state. This
120 * callback may modify the node_transform and node_state to apply an effective
121 * change to the render state at this level.
122 */
123 void BillboardEffect::
124 cull_callback(CullTraverser *trav, CullTraverserData &data,
125 CPT(TransformState) &node_transform,
126 CPT(RenderState) &) const {
127 CPT(TransformState) modelview_transform = data.get_modelview_transform(trav);
128 if (modelview_transform->is_singular()) {
129 // If we're under a singular transform, never mind.
130 return;
131 }
132
133 // Since the "modelview" transform from the cull traverser already includes
134 // the inverse camera transform, the camera transform is identity.
135 CPT(TransformState) camera_transform = TransformState::make_identity();
136
137 // But if we're rotating to face something other than the camera, we have to
138 // compute the "camera" transform to compensate for that.
139 if (!_look_at.is_empty()) {
140 camera_transform = trav->get_camera_transform()->invert_compose(_look_at.get_net_transform());
141 }
142
143 compute_billboard(node_transform, modelview_transform, camera_transform);
144 }
145
146 /**
147 * Should be overridden by derived classes to return true if
148 * adjust_transform() has been defined, and therefore the RenderEffect has
149 * some effect on the node's apparent local and net transforms.
150 */
151 bool BillboardEffect::
152 has_adjust_transform() const {
153 // A BillboardEffect can only affect the net transform when it is to a
154 // particular node. A billboard to a camera is camera-dependent, of course,
155 // so it has no effect in the absence of any particular camera viewing it.
156 return !_look_at.is_empty();
157 }
158
159 /**
160 * Performs some operation on the node's apparent net and/or local transforms.
161 * This will only be called if has_adjust_transform() is redefined to return
162 * true.
163 *
164 * Both parameters are in/out. The original transforms will be passed in, and
165 * they may (or may not) be modified in-place by the RenderEffect.
166 */
167 void BillboardEffect::
168 adjust_transform(CPT(TransformState) &net_transform,
169 CPT(TransformState) &node_transform,
170 const PandaNode *) const {
171 // A BillboardEffect can only affect the net transform when it is to a
172 // particular node. A billboard to a camera is camera-dependent, of course,
173 // so it has no effect in the absence of any particular camera viewing it.
174 if (_look_at.is_empty()) {
175 return;
176 }
177
178 CPT(TransformState) camera_transform = _look_at.get_net_transform();
179
180 compute_billboard(node_transform, net_transform, camera_transform);
181 }
182
183
184 /**
185 * Intended to be overridden by derived BillboardEffect types to return a
186 * unique number indicating whether this BillboardEffect is equivalent to the
187 * other one.
188 *
189 * This should return 0 if the two BillboardEffect objects are equivalent, a
190 * number less than zero if this one should be sorted before the other one,
191 * and a number greater than zero otherwise.
192 *
193 * This will only be called with two BillboardEffect objects whose get_type()
194 * functions return the same.
195 */
196 int BillboardEffect::
197 compare_to_impl(const RenderEffect *other) const {
198 const BillboardEffect *ta;
199 DCAST_INTO_R(ta, other, 0);
200
201 if (_axial_rotate != ta->_axial_rotate) {
202 return (int)_axial_rotate - (int)ta->_axial_rotate;
203 }
204 if (_eye_relative != ta->_eye_relative) {
205 return (int)_eye_relative - (int)ta->_eye_relative;
206 }
207 if (_fixed_depth != ta->_fixed_depth) {
208 return (int)_fixed_depth - (int)ta->_fixed_depth;
209 }
210 if (_offset != ta->_offset) {
211 return _offset < ta->_offset ? -1 : 1;
212 }
213 int compare = _up_vector.compare_to(ta->_up_vector);
214 if (compare != 0) {
215 return compare;
216 }
217 compare = _look_at.compare_to(ta->_look_at);
218 if (compare != 0) {
219 return compare;
220 }
221 compare = _look_at_point.compare_to(ta->_look_at_point);
222 if (compare != 0) {
223 return compare;
224 }
225 return 0;
226 }
227
228 /**
229 * Computes the billboard operation given the parent's net transform and the
230 * camera transform.
231 *
232 * The result is applied to node_transform, which is modified in-place.
233 */
234 void BillboardEffect::
235 compute_billboard(CPT(TransformState) &node_transform,
236 const TransformState *net_transform,
237 const TransformState *camera_transform) const {
238 // First, extract out just the translation component of the node's local
239 // transform. This gets applied to the net transform, to compute the look-
240 // at direction properly.
241 CPT(TransformState) translate = TransformState::make_pos(node_transform->get_pos());
242
243 // And then the translation gets removed from the node, but we keep its
244 // rotation etc., which gets applied after the billboard operation.
245 node_transform = node_transform->set_pos(LPoint3(0.0f, 0.0f, 0.0f));
246
247 CPT(TransformState) rel_transform =
248 net_transform->compose(translate)->invert_compose(camera_transform);
249 if (!rel_transform->has_mat()) {
250 // Never mind.
251 return;
252 }
253
254 const LMatrix4 &rel_mat = rel_transform->get_mat();
255
256 // Determine the look_at point in the camera space.
257 LVector3 camera_pos, up;
258
259 // If this is an eye-relative Billboard, then (a) the up vector is relative
260 // to the camera, not to the world, and (b) the look direction is towards
261 // the plane that contains the camera, perpendicular to the forward
262 // direction, not directly to the camera.
263
264 if (_eye_relative) {
265 up = _up_vector * rel_mat;
266 camera_pos = LVector3::forward() * rel_mat;
267
268 } else {
269 up = _up_vector;
270 camera_pos = -(_look_at_point * rel_mat);
271 }
272
273 // Now determine the rotation matrix for the Billboard.
274 LMatrix4 rotate;
275 if (_axial_rotate) {
276 heads_up(rotate, camera_pos, up);
277 } else {
278 look_at(rotate, camera_pos, up);
279 }
280
281 // Also slide the billboard geometry towards the camera according to the
282 // offset factor.
283 if (_offset != 0.0f || _fixed_depth) {
284 LVector3 translate(rel_mat(3, 0), rel_mat(3, 1), rel_mat(3, 2));
285 LPoint3 pos;
286 if (_fixed_depth) {
287 pos = translate / rel_mat(3, 3);
288 } else {
289 pos.fill(0.0f);
290 }
291 translate.normalize();
292 translate *= _offset;
293 rotate.set_row(3, pos + translate);
294 }
295
296 node_transform = translate->compose(TransformState::make_mat(rotate))->compose(node_transform);
297 }
298
299 /**
300 * Tells the BamReader how to create objects of type BillboardEffect.
301 */
302 void BillboardEffect::
303 register_with_read_factory() {
304 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
305 }
306
307 /**
308 * Writes the contents of this object to the datagram for shipping out to a
309 * Bam file.
310 */
311 void BillboardEffect::
312 write_datagram(BamWriter *manager, Datagram &dg) {
313 RenderEffect::write_datagram(manager, dg);
314
315 dg.add_bool(_off);
316 _up_vector.write_datagram(dg);
317 dg.add_bool(_eye_relative);
318 dg.add_bool(_axial_rotate);
319 dg.add_stdfloat(_offset);
320 _look_at_point.write_datagram(dg);
321
322 if (manager->get_file_minor_ver() >= 43) {
323 _look_at.write_datagram(manager, dg);
324 dg.add_bool(_fixed_depth);
325 }
326 }
327
328 /**
329 * Receives an array of pointers, one for each time manager->read_pointer()
330 * was called in fillin(). Returns the number of pointers processed.
331 */
332 int BillboardEffect::
333 complete_pointers(TypedWritable **p_list, BamReader *manager) {
334 int pi = RenderEffect::complete_pointers(p_list, manager);
335
336 if (manager->get_file_minor_ver() >= 43) {
337 pi += _look_at.complete_pointers(p_list + pi, manager);
338 }
339
340 return pi;
341 }
342
343 /**
344 * This function is called by the BamReader's factory when a new object of
345 * type BillboardEffect is encountered in the Bam file. It should create the
346 * BillboardEffect and extract its information from the file.
347 */
348 TypedWritable *BillboardEffect::
349 make_from_bam(const FactoryParams &params) {
350 BillboardEffect *effect = new BillboardEffect;
351 DatagramIterator scan;
352 BamReader *manager;
353
354 parse_params(params, scan, manager);
355 effect->fillin(scan, manager);
356
357 return effect;
358 }
359
360 /**
361 * This internal function is called by make_from_bam to read in all of the
362 * relevant data from the BamFile for the new BillboardEffect.
363 */
364 void BillboardEffect::
365 fillin(DatagramIterator &scan, BamReader *manager) {
366 RenderEffect::fillin(scan, manager);
367
368 _off = scan.get_bool();
369 _up_vector.read_datagram(scan);
370 _eye_relative = scan.get_bool();
371 _axial_rotate = scan.get_bool();
372 _offset = scan.get_stdfloat();
373 _look_at_point.read_datagram(scan);
374
375 if (manager->get_file_minor_ver() >= 43) {
376 _look_at.fillin(scan, manager);
377 _fixed_depth = scan.get_bool();
378 } else {
379 _fixed_depth = false;
380 }
381 }
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
parse_params
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
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT
CPT(RenderEffect) BillboardEffect
Constructs a new BillboardEffect object with the indicated properties.
Definition: billboardEffect.cxx:29
billboardEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
BamWriter::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
Definition: bamWriter.I:59
BillboardEffect
Indicates that geometry at this node should automatically rotate to face the camera,...
Definition: billboardEffect.h:27
BillboardEffect::complete_pointers
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: billboardEffect.cxx:333
BillboardEffect::write_datagram
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: billboardEffect.cxx:312
BillboardEffect::is_off
bool is_off() const
Returns true if the BillboardEffect is an 'off' BillboardEffect, indicating that it does not enable b...
Definition: billboardEffect.I:59
BillboardEffect::safe_to_transform
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of RenderEffect by calling the...
Definition: billboardEffect.cxx:50
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
CullTraverser::get_camera_transform
const TransformState * get_camera_transform() const
Returns the position of the camera relative to the starting node.
Definition: cullTraverser.I:61
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_stdfloat
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
Definition: datagramIterator.I:242
DatagramIterator::get_bool
bool get_bool()
Extracts a boolean value.
Definition: datagramIterator.I:48
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::add_stdfloat
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
Definition: datagram.I:133
Datagram::add_bool
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
Factory::register_factory
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
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
NodePath::fillin
void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is called by make_from_bam to read in all of the relevant data from the BamFil...
Definition: nodePath.cxx:6990
NodePath::is_empty
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
NodePath::complete_pointers
int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: nodePath.cxx:6930
NodePath::compare_to
int compare_to(const NodePath &other) const
Returns a number less than zero if this NodePath sorts before the other one, greater than zero if it ...
Definition: nodePath.I:1965
NodePath::write_datagram
void write_datagram(BamWriter *manager, Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: nodePath.cxx:6879
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
RenderEffect
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:48
RenderEffect::write_datagram
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: renderEffect.cxx:283
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
TransformState::get_mat
get_mat
Returns the matrix that describes the transform.
Definition: transformState.h:156
TransformState::get_pos
get_pos
Returns the pos component of the transform.
Definition: transformState.h:150
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
TypedWritable::complete_pointers
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: typedWritable.cxx:81
cullTraverserData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullTraverser.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
look_at.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
nodePath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.