Panda3D
Loading...
Searching...
No Matches
cullTraverser.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 cullTraverser.cxx
10 * @author drose
11 * @date 2002-02-23
12 */
13
14#include "config_pgraph.h"
15#include "cullTraverser.h"
16#include "cullTraverserData.h"
17#include "transformState.h"
18#include "renderState.h"
19#include "colorAttrib.h"
20#include "renderModeAttrib.h"
21#include "cullFaceAttrib.h"
22#include "depthOffsetAttrib.h"
23#include "cullHandler.h"
24#include "dcast.h"
25#include "geomNode.h"
26#include "config_pgraph.h"
27#include "boundingSphere.h"
28#include "boundingBox.h"
29#include "boundingHexahedron.h"
30#include "portalClipper.h"
31#include "geom.h"
32#include "geomTristrips.h"
33#include "geomTriangles.h"
34#include "geomLinestrips.h"
35#include "geomLines.h"
36#include "geomVertexWriter.h"
37
38PStatCollector CullTraverser::_nodes_pcollector("Nodes");
39PStatCollector CullTraverser::_geom_nodes_pcollector("Nodes:GeomNodes");
40PStatCollector CullTraverser::_geoms_pcollector("Geoms");
41PStatCollector CullTraverser::_geoms_occluded_pcollector("Geoms:Occluded");
42
43TypeHandle CullTraverser::_type_handle;
44
45/**
46 *
47 */
48CullTraverser::
49CullTraverser() :
50 _gsg(nullptr),
51 _current_thread(Thread::get_current_thread())
52{
53 _camera_mask = DrawMask::all_on();
54 _has_tag_state_key = false;
55 _initial_state = RenderState::make_empty();
56 _cull_handler = nullptr;
57 _portal_clipper = nullptr;
58 _effective_incomplete_render = true;
59}
60
61/**
62 *
63 */
64CullTraverser::
65CullTraverser(const CullTraverser &copy) :
66 _gsg(copy._gsg),
67 _current_thread(copy._current_thread),
68 _scene_setup(copy._scene_setup),
69 _camera_mask(copy._camera_mask),
70 _has_tag_state_key(copy._has_tag_state_key),
71 _tag_state_key(copy._tag_state_key),
72 _initial_state(copy._initial_state),
73 _view_frustum(copy._view_frustum),
74 _cull_handler(copy._cull_handler),
75 _portal_clipper(copy._portal_clipper),
76 _effective_incomplete_render(copy._effective_incomplete_render)
77{
78}
79
80/**
81 * Sets the SceneSetup object that indicates the initial camera position, etc.
82 * This must be called before traversal begins.
83 */
86 bool dr_incomplete_render) {
87 _scene_setup = scene_setup;
88 _gsg = gsg;
89
90 _initial_state = scene_setup->get_initial_state();
91
92 _current_thread = Thread::get_current_thread();
93
94 const Camera *camera = scene_setup->get_camera_node();
95 _tag_state_key = camera->get_tag_state_key();
96 _has_tag_state_key = !_tag_state_key.empty();
97 _camera_mask = camera->get_camera_mask();
98
99 _effective_incomplete_render = _gsg->get_incomplete_render() && dr_incomplete_render;
100}
101
102/**
103 * Begins the traversal from the indicated node.
104 */
106traverse(const NodePath &root) {
107 nassertv(_cull_handler != nullptr);
108 nassertv(_scene_setup != nullptr);
109
110 if (allow_portal_cull) {
111 // This _view_frustum is in cull_center space Erik: obsolete?
112 // PT(GeometricBoundingVolume) vf = _view_frustum;
113
114 GeometricBoundingVolume *local_frustum = nullptr;
115 PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds();
116 if (bv != nullptr) {
117 local_frustum = bv->as_geometric_bounding_volume();
118 }
119
120 // This local_frustum is in camera space
121 PortalClipper portal_viewer(local_frustum, _scene_setup);
122 if (debug_portal_cull) {
123 portal_viewer.draw_camera_frustum();
124 }
125
126 // Store this pointer in this
127 set_portal_clipper(&portal_viewer);
128
129 CullTraverserData data(root, TransformState::make_identity(),
130 _initial_state, _view_frustum,
131 _current_thread);
132
133 traverse(data);
134
135 // Finally add the lines to be drawn
136 if (debug_portal_cull) {
137 portal_viewer.draw_lines();
138 }
139
140 // Render the frustum relative to the cull center.
141 NodePath cull_center = _scene_setup->get_cull_center();
142 CPT(TransformState) transform = cull_center.get_transform(root);
143
144 CullTraverserData my_data(data, portal_viewer._previous);
145 my_data._net_transform = my_data._net_transform->compose(transform);
146 traverse(my_data);
147
148 } else {
149 CullTraverserData data(root, TransformState::make_identity(),
150 _initial_state, _view_frustum,
151 _current_thread);
152
153 do_traverse(data);
154 }
155}
156
157/**
158 * Traverses from the next node with the given data, which has been
159 * constructed with the node but has not yet been converted into the node's
160 * space.
161 */
164 do_traverse(data);
165}
166
167/**
168 * Traverses all the children of the indicated node, with the given data,
169 * which has been converted into the node's space.
170 */
173 _nodes_pcollector.add_level(1);
174 PandaNodePipelineReader *node_reader = data.node_reader();
175 PandaNode *node = data.node();
176
177 if (!data.is_this_node_hidden(_camera_mask)) {
178 node->add_for_draw(this, data);
179
180 // Check for a decal effect.
181 const RenderEffects *node_effects = node_reader->get_effects();
182 if (node_effects->has_decal()) {
183 // If we *are* implementing decals with DepthOffsetAttribs, apply it
184 // now, so that each child of this node gets offset by a tiny amount.
185 data._state = data._state->compose(get_depth_offset_state());
186#ifndef NDEBUG
187 // This is just a sanity check message.
188 if (!node->is_geom_node()) {
189 pgraph_cat.error()
190 << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
191 }
192#endif
193 }
194 }
195
196 // Now visit all the node's children.
197 PandaNode::Children children = node_reader->get_children();
198 node_reader->release();
199 int num_children = children.get_num_children();
200 if (!node->has_selective_visibility()) {
201 for (int i = 0; i < num_children; ++i) {
202 CullTraverserData next_data(data, children.get_child(i));
203 do_traverse(next_data);
204 }
205 } else {
206 int i = node->get_first_visible_child();
207 while (i < num_children) {
208 CullTraverserData next_data(data, children.get_child(i));
209 do_traverse(next_data);
210 i = node->get_next_visible_child(i);
211 }
212 }
213}
214
215/**
216 * Should be called when the traverser has finished traversing its scene, this
217 * gives it a chance to do any necessary finalization.
218 */
220end_traverse() {
221 _cull_handler->end_traverse();
222}
223
224/**
225 * Draws an appropriate visualization of the indicated bounding volume.
226 */
229 const TransformState *internal_transform) const {
230 PT(Geom) bounds_viz = make_bounds_viz(vol);
231
232 if (bounds_viz != nullptr) {
233 _geoms_pcollector.add_level(2);
234 CullableObject *outer_viz =
235 new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
236 internal_transform);
237 _cull_handler->record_object(outer_viz, this);
238
239 CullableObject *inner_viz =
240 new CullableObject(std::move(bounds_viz), get_bounds_inner_viz_state(),
241 internal_transform);
242 _cull_handler->record_object(inner_viz, this);
243 }
244}
245
246/**
247 * Returns true if the current node is fully or partially within the viewing
248 * area and should be drawn, or false if it (and all of its children) should
249 * be pruned.
250 */
251bool CullTraverser::
252is_in_view(CullTraverserData &data) {
253 return data.is_in_view(_camera_mask);
254}
255
256/**
257 * Draws an appropriate visualization of the node's external bounding volume.
258 */
259void CullTraverser::
260show_bounds(CullTraverserData &data, bool tight) {
261 PandaNode *node = data.node();
262 CPT(TransformState) internal_transform = data.get_internal_transform(this);
263
264 if (tight) {
265 PT(Geom) bounds_viz = make_tight_bounds_viz(node);
266
267 if (bounds_viz != nullptr) {
268 _geoms_pcollector.add_level(1);
269 CullableObject *outer_viz =
270 new CullableObject(std::move(bounds_viz), get_bounds_outer_viz_state(),
271 internal_transform);
272 _cull_handler->record_object(outer_viz, this);
273 }
274
275 } else {
276 draw_bounding_volume(node->get_bounds(), internal_transform);
277
278 if (node->is_geom_node()) {
279 // Also show the bounding volumes of included Geoms.
280 internal_transform = internal_transform->compose(node->get_transform());
281 GeomNode *gnode = (GeomNode *)node;
282 int num_geoms = gnode->get_num_geoms();
283 for (int i = 0; i < num_geoms; ++i) {
284 draw_bounding_volume(gnode->get_geom(i)->get_bounds(),
285 internal_transform);
286 }
287 }
288 }
289}
290
291/**
292 * Returns an appropriate visualization of the indicated bounding volume.
293 */
294PT(Geom) CullTraverser::
295make_bounds_viz(const BoundingVolume *vol) {
296 PT(Geom) geom;
297 if (vol->is_infinite() || vol->is_empty()) {
298 // No way to draw an infinite or empty bounding volume.
299
300 } else if (vol->is_of_type(BoundingSphere::get_class_type())) {
301 const BoundingSphere *sphere = DCAST(BoundingSphere, vol);
302
303 static const int num_slices = 16;
304 static const int num_stacks = 8;
305
306 PT(GeomVertexData) vdata = new GeomVertexData
307 ("bounds", GeomVertexFormat::get_v3(),
308 Geom::UH_stream);
309 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
310
311 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
312 for (int sl = 0; sl < num_slices; ++sl) {
313 PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
314 PN_stdfloat longitude1 = (PN_stdfloat)(sl + 1) / (PN_stdfloat)num_slices;
315 vertex.add_data3(compute_point(sphere, 0.0, longitude0));
316 for (int st = 1; st < num_stacks; ++st) {
317 PN_stdfloat latitude = (PN_stdfloat)st / (PN_stdfloat)num_stacks;
318 vertex.add_data3(compute_point(sphere, latitude, longitude0));
319 vertex.add_data3(compute_point(sphere, latitude, longitude1));
320 }
321 vertex.add_data3(compute_point(sphere, 1.0, longitude0));
322
323 strip->add_next_vertices(num_stacks * 2);
324 strip->close_primitive();
325 }
326
327 geom = new Geom(vdata);
328 geom->add_primitive(strip);
329
330 } else if (vol->is_of_type(BoundingHexahedron::get_class_type())) {
331 const BoundingHexahedron *fvol = DCAST(BoundingHexahedron, vol);
332
333 PT(GeomVertexData) vdata = new GeomVertexData
334 ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream);
335 vdata->unclean_set_num_rows(8);
336
337 {
338 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
339 for (int i = 0; i < 8; ++i) {
340 vertex.set_data3(fvol->get_point(i));
341 }
342 }
343
344 PT(GeomLines) lines = new GeomLines(Geom::UH_stream);
345 lines->add_vertices(0, 1);
346 lines->add_vertices(1, 2);
347 lines->add_vertices(2, 3);
348 lines->add_vertices(3, 0);
349
350 lines->add_vertices(4, 5);
351 lines->add_vertices(5, 6);
352 lines->add_vertices(6, 7);
353 lines->add_vertices(7, 4);
354
355 lines->add_vertices(0, 4);
356 lines->add_vertices(1, 5);
357 lines->add_vertices(2, 6);
358 lines->add_vertices(3, 7);
359
360 geom = new Geom(vdata);
361 geom->add_primitive(lines);
362
363 } else if (vol->is_of_type(FiniteBoundingVolume::get_class_type())) {
364 const FiniteBoundingVolume *fvol = DCAST(FiniteBoundingVolume, vol);
365
366 BoundingBox box(fvol->get_min(), fvol->get_max());
367 box.local_object();
368
369 PT(GeomVertexData) vdata = new GeomVertexData
370 ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream);
371 vdata->unclean_set_num_rows(8);
372
373 {
374 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
375 for (int i = 0; i < 8; ++i) {
376 vertex.set_data3(box.get_point(i));
377 }
378 }
379
380 PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_stream);
381 tris->add_vertices(0, 4, 5);
382 tris->add_vertices(0, 5, 1);
383 tris->add_vertices(4, 6, 7);
384 tris->add_vertices(4, 7, 5);
385 tris->add_vertices(6, 2, 3);
386 tris->add_vertices(6, 3, 7);
387 tris->add_vertices(2, 0, 1);
388 tris->add_vertices(2, 1, 3);
389 tris->add_vertices(1, 5, 7);
390 tris->add_vertices(1, 7, 3);
391 tris->add_vertices(2, 6, 4);
392 tris->add_vertices(2, 4, 0);
393
394 geom = new Geom(vdata);
395 geom->add_primitive(tris);
396
397 } else {
398 pgraph_cat.warning()
399 << "Don't know how to draw a representation of "
400 << vol->get_class_type() << "\n";
401 }
402
403 return geom;
404}
405
406/**
407 * Returns a bounding-box visualization of the indicated node's "tight"
408 * bounding volume.
409 */
410PT(Geom) CullTraverser::
411make_tight_bounds_viz(PandaNode *node) const {
412 PT(Geom) geom;
413
414 NodePath np = NodePath::any_path(node);
415
416 LPoint3 n, x;
417 bool found_any = false;
418 node->calc_tight_bounds(n, x, found_any, TransformState::make_identity(),
419 _current_thread);
420 if (found_any) {
421 PT(GeomVertexData) vdata = new GeomVertexData
422 ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream);
423 vdata->unclean_set_num_rows(8);
424
425 {
426 GeomVertexWriter vertex(vdata, InternalName::get_vertex(),
427 _current_thread);
428 vertex.set_data3(n[0], n[1], n[2]);
429 vertex.set_data3(n[0], n[1], x[2]);
430 vertex.set_data3(n[0], x[1], n[2]);
431 vertex.set_data3(n[0], x[1], x[2]);
432 vertex.set_data3(x[0], n[1], n[2]);
433 vertex.set_data3(x[0], n[1], x[2]);
434 vertex.set_data3(x[0], x[1], n[2]);
435 vertex.set_data3(x[0], x[1], x[2]);
436 }
437
438 PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream);
439
440 // We wind one long linestrip around the wireframe cube. This does
441 // require backtracking a few times here and there.
442 strip->add_vertex(0);
443 strip->add_vertex(1);
444 strip->add_vertex(3);
445 strip->add_vertex(2);
446 strip->add_vertex(0);
447 strip->add_vertex(4);
448 strip->add_vertex(5);
449 strip->add_vertex(7);
450 strip->add_vertex(6);
451 strip->add_vertex(4);
452 strip->add_vertex(6);
453 strip->add_vertex(2);
454 strip->add_vertex(3);
455 strip->add_vertex(7);
456 strip->add_vertex(5);
457 strip->add_vertex(1);
458 strip->close_primitive();
459
460 geom = new Geom(vdata);
461 geom->add_primitive(strip);
462 }
463
464 return geom;
465}
466
467/**
468 * Returns a point on the surface of the sphere. latitude and longitude range
469 * from 0.0 to 1.0.
470 */
471LVertex CullTraverser::
472compute_point(const BoundingSphere *sphere,
473 PN_stdfloat latitude, PN_stdfloat longitude) {
474 PN_stdfloat s1, c1;
475 csincos(latitude * MathNumbers::pi, &s1, &c1);
476
477 PN_stdfloat s2, c2;
478 csincos(longitude * 2.0 * MathNumbers::pi, &s2, &c2);
479
480 LVertex p(s1 * c2, s1 * s2, c1);
481 return p * sphere->get_radius() + sphere->get_center();
482}
483
484/**
485 * Returns a RenderState for rendering the outside surfaces of the bounding
486 * volume visualizations.
487 */
488CPT(RenderState) CullTraverser::
489get_bounds_outer_viz_state() {
490 // Once someone asks for this pointer, we hold its reference count and never
491 // free it.
492 static CPT(RenderState) state = nullptr;
493 if (state == nullptr) {
494 state = RenderState::make
495 (ColorAttrib::make_flat(LColor(0.3, 1.0f, 0.5f, 1.0f)),
496 RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
497 CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise));
498 }
499 return state;
500}
501
502/**
503 * Returns a RenderState for rendering the inside surfaces of the bounding
504 * volume visualizations.
505 */
506CPT(RenderState) CullTraverser::
507get_bounds_inner_viz_state() {
508 // Once someone asks for this pointer, we hold its reference count and never
509 // free it.
510 static CPT(RenderState) state = nullptr;
511 if (state == nullptr) {
512 state = RenderState::make
513 (ColorAttrib::make_flat(LColor(0.15f, 0.5f, 0.25f, 1.0f)),
514 RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
515 CullFaceAttrib::make(CullFaceAttrib::M_cull_counter_clockwise));
516 }
517 return state;
518}
519
520/**
521 * Returns a RenderState for increasing the DepthOffset by one.
522 */
523CPT(RenderState) CullTraverser::
524get_depth_offset_state() {
525 // Once someone asks for this pointer, we hold its reference count and never
526 // free it.
527 static CPT(RenderState) state = nullptr;
528 if (state == nullptr) {
529 state = RenderState::make
530 (DepthOffsetAttrib::make(1));
531 }
532 return state;
533}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static BitMask< uint32_t, nbits > all_on()
Returns a BitMask whose bits are all on.
Definition bitMask.I:32
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition boundingBox.h:29
get_point
Returns the nth vertex of the rectangular solid.
Definition boundingBox.h:51
This defines a bounding convex hexahedron.
get_point
Returns the nth vertex of the hexahedron.
This defines a bounding sphere, consisting of a center and a radius.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
bool is_empty() const
Any kind of volume might be empty.
bool is_infinite() const
The other side of the empty coin is an infinite volume.
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_camera_mask
Returns the set of bits that represent the subset of the scene graph the camera will render.
Definition camera.h:63
get_tag_state_key
Returns the tag key as set by a previous call to set_tag_state_key().
Definition camera.h:83
virtual void end_traverse()
This callback function is intended to be overridden by a derived class.
virtual void record_object(CullableObject *object, const CullTraverser *traverser)
This callback function is intended to be overridden by a derived class.
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,...
virtual void end_traverse()
Should be called when the traverser has finished traversing its scene, this gives it a chance to do a...
virtual void set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg, bool dr_incomplete_render)
Sets the SceneSetup object that indicates the initial camera position, etc.
void set_portal_clipper(PortalClipper *portal_clipper)
Specifies _portal_clipper object pointer that subsequent traverse() or traverse_below may use.
void draw_bounding_volume(const BoundingVolume *vol, const TransformState *internal_transform) const
Draws an appropriate visualization of the indicated bounding volume.
virtual void traverse_below(CullTraverserData &data)
Traverses all the children of the indicated node, with the given data, which has been converted into ...
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
The smallest atom of cull.
A special kind of GeometricBoundingVolume that is known to be finite.
Defines a series of disconnected line segments.
Definition geomLines.h:23
Defines a series of line strips.
A node that holds Geom objects, renderable pieces of geometry.
Definition geomNode.h:34
get_num_geoms
Returns the number of geoms in the node.
Definition geomNode.h:71
Defines a series of disconnected triangles.
Defines a series of triangle strips.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
static const GeomVertexFormat * get_v3()
Returns a standard vertex format with just a 3-component vertex position.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
void set_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.
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.
A container for geometry primitives.
Definition geom.h:54
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
virtual GeometricBoundingVolume * as_geometric_bounding_volume() final
Virtual downcast method.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node.
Definition nodePath.I:62
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition nodePath.cxx:794
A lightweight class that represents a single element that may be timed and/or counted via stats.
Encapsulates the data from a PandaNode, pre-fetched for one stage of the pipeline.
Definition pandaNode.h:840
void release()
Releases the lock on this object.
Definition pandaNode.I:1242
const RenderEffects * get_effects() const
Returns the complete RenderEffects that will be applied to this node.
Definition pandaNode.I:1431
PandaNode::Children get_children() const
Returns an object that can be used to walk through the list of children of the node.
Definition pandaNode.I:1569
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition pandaNode.I:962
size_t get_num_children() const
Returns the number of children of the node.
Definition pandaNode.I:953
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
virtual bool is_geom_node() const
A simple downcast check.
virtual int get_next_visible_child(int n) const
Returns the index number of the next visible child of this node following the indicated child,...
virtual int get_first_visible_child() const
Returns the index number of the first visible child of this node, or a number >= get_num_children() i...
virtual bool has_selective_visibility() const
Should be overridden by derived classes to return true if this kind of node has some restrictions on ...
virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data)
Adds the node's contents to the CullResult we are building up during the cull traversal,...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
void draw_lines()
Draw all the lines in the buffer Cyan portal is the original geometry of the portal Yellow portal is ...
void draw_camera_frustum()
Draw the current camera frustum in white color.
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
bool has_decal() const
This function is provided as an optimization, to speed up the render-time checking for the existance ...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition renderState.h:47
This object holds the camera position, etc., and other general setup information for rendering a part...
Definition sceneSetup.h:32
const RenderState * get_initial_state() const
Returns the initial state as set by a previous call to set_initial_state().
Definition sceneSetup.I:198
Camera * get_camera_node() const
Returns the camera used to render the scene.
Definition sceneSetup.I:115
A thread; that is, a lightweight process.
Definition thread.h:46
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition thread.h:109
Indicates a coordinate-system transform on vertices.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition typedObject.I:28
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.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.