28 #include "pssmCameraRig.h"    30 #ifndef _USE_MATH_DEFINES    31 #define _USE_MATH_DEFINES    37 PStatCollector PSSMCameraRig::_update_collector(
"App:Show code:RP_PSSM_update");
    49   nassertv(num_splits > 0);
    50   _num_splits = num_splits;
    51   _pssm_distance = 100.0;
    52   _sun_distance = 500.0;
    53   _use_fixed_film_size = 
false;
    54   _use_stable_csm = 
true;
    55   _logarithmic_factor = 1.0;
    58   _camera_mvps = PTA_LMatrix4::empty_array(num_splits);
    59   _camera_nearfar = PTA_LVecBase2::empty_array(num_splits);
    77 void PSSMCameraRig::init_cam_nodes() {
    78   _cam_nodes.reserve(_num_splits);
    79   _max_film_sizes.resize(_num_splits);
    80   _cameras.resize(_num_splits);
    81   for (
size_t i = 0; i < _num_splits; ++i)
    89     _cameras[i] = 
new Camera(
"pssm-cam-" + format_string(i), lens);
    90     _cam_nodes.push_back(
NodePath(_cameras[i]));
    91     _max_film_sizes[i].fill(0);
   107   for (
size_t i = 0; i < _num_splits; ++i) {
   108     _cam_nodes[i].reparent_to(parent);
   121 LMatrix4 PSSMCameraRig::compute_mvp(
size_t split_index) {
   123   return transform * _cameras[split_index]->get_lens()->get_projection_mat();
   141 LVecBase3 PSSMCameraRig::get_snap_offset(
const LMatrix4& mat, 
size_t resolution) {
   143   LPoint4 base_point = mat.get_row(3) * 0.5 + 0.5;
   146   float texel_size = 1.0 / (float)(resolution);
   147   float offset_x = fmod(base_point.get_x(), texel_size);
   148   float offset_y = fmod(base_point.get_y(), texel_size);
   151   LMatrix4 inv_mat(mat);
   152   inv_mat.invert_in_place();
   153   LVecBase3 new_base_point = inv_mat.xform_point(LVecBase3(
   154       (base_point.get_x() - offset_x) * 2.0 - 1.0,
   155       (base_point.get_y() - offset_y) * 2.0 - 1.0,
   156       base_point.get_z() * 2.0 - 1.0
   158   return -new_base_point;
   174 LPoint3 get_average_of_points(LVecBase3 
const (&starts)[4], LVecBase3 
const (&ends)[4]) {
   175   LPoint3 mid_point(0, 0, 0);
   176   for (
size_t k = 0; k < 4; ++k) {
   177     mid_point += starts[k];
   178     mid_point += ends[k];
   180   return mid_point / 8.0;
   195 void find_min_max_extents(LVecBase3 &min_extent, LVecBase3 &max_extent, 
const LMatrix4 &transform, LVecBase3 
const (&proj_points)[8], 
Camera *cam) {
   197   min_extent.fill(1e10);
   198   max_extent.fill(-1e10);
   199   LPoint2 screen_points[8];
   203   for (
size_t k = 0; k < 8; ++k) {
   204     LVecBase4 point(proj_points[k], 1);
   205     LPoint4 proj_point = transform.xform(point);
   206     LPoint3 proj_point_3d(proj_point.get_x(), proj_point.get_y(), proj_point.get_z());
   210     if (screen_points[k].get_x() > max_extent.get_x()) max_extent.set_x(screen_points[k].get_x());
   211     if (screen_points[k].get_y() > max_extent.get_y()) max_extent.set_y(screen_points[k].get_y());
   213     if (screen_points[k].get_x() < min_extent.get_x()) min_extent.set_x(screen_points[k].get_x());
   214     if (screen_points[k].get_y() < min_extent.get_y()) min_extent.set_y(screen_points[k].get_y());
   217     if (proj_point.get_y() > max_extent.get_z()) max_extent.set_z(proj_point.get_y());
   218     if (proj_point.get_y() < min_extent.get_z()) min_extent.set_z(proj_point.get_y());
   232 inline void get_film_properties(LVecBase2 &film_size, LVecBase2 &film_offset, 
const LVecBase3 &min_extent, 
const LVecBase3 &max_extent) {
   233   float x_center = (min_extent.get_x() + max_extent.get_x()) * 0.5;
   234   float y_center = (min_extent.get_y() + max_extent.get_y()) * 0.5;
   235   float x_size = max_extent.get_x() - x_center;
   236   float y_size = max_extent.get_y() - y_center;
   237   film_size.set(x_size, y_size);
   238   film_offset.set(x_center * 0.5, y_center * 0.5);
   250 inline void merge_points_interleaved(LVecBase3 (&dest)[8], LVecBase3 
const (&array1)[4], LVecBase3 
const (&array2)[4]) {
   251   for (
size_t k = 0; k < 4; ++k) {
   253     dest[k+4] = array2[k];
   268 void PSSMCameraRig::compute_pssm_splits(
const LMatrix4& transform, 
float max_distance, 
const LVecBase3& light_vector) {
   272   nassertv(max_distance <= 1.0);
   274   float filmsize_bias = 1.0 + _border_bias;
   277   for (
size_t i = 0; i < _cam_nodes.size(); ++i) {
   278     float split_start = get_split_start(i) * max_distance;
   279     float split_end = get_split_start(i + 1) * max_distance;
   281     LVecBase3 start_points[4];
   282     LVecBase3 end_points[4];
   283     LVecBase3 proj_points[8];
   286     for (
size_t k = 0; k < 4; ++k) {
   287       start_points[k] = get_interpolated_point((CoordinateOrigin)k, split_start);
   288       end_points[k] = get_interpolated_point((CoordinateOrigin)k, split_end);
   289       proj_points[k] = start_points[k];
   290       proj_points[k + 4] = end_points[k];
   294     LPoint3 split_mid = get_average_of_points(start_points, end_points);
   295     LPoint3 cam_start = split_mid + light_vector * _sun_distance;
   304     _cam_nodes[i].set_pos(cam_start);
   305     _cam_nodes[i].look_at(split_mid);
   307     LVecBase3 best_min_extent, best_max_extent;
   311     find_min_max_extents(best_min_extent, best_max_extent, merged_transform, proj_points, cam);
   314     LVecBase2 film_size, film_offset;
   315     get_film_properties(film_size, film_offset, best_min_extent, best_max_extent);
   317     if (_use_fixed_film_size) {
   320       if (_max_film_sizes[i].get_x() < film_size.get_x()) _max_film_sizes[i].set_x(film_size.get_x());
   321       if (_max_film_sizes[i].get_y() < film_size.get_y()) _max_film_sizes[i].set_y(film_size.get_y());
   333     _camera_nearfar[i] = LVecBase2(10, best_max_extent.get_z());
   336     LMatrix4 mvp = compute_mvp(i);
   339     if (_use_stable_csm) {
   340       LPoint3 snap_offset = get_snap_offset(mvp, _resolution);
   341       _cam_nodes[i].set_pos(_cam_nodes[i].get_pos() + snap_offset);
   344       mvp = compute_mvp(i);
   347     _camera_mvps.set_element(i, mvp);
   366   _update_collector.start();
   373   nassertv(cam != 
nullptr);
   377   lens->
extrude(LPoint2(-1, 1),  _curr_near_points[UpperLeft],  _curr_far_points[UpperLeft]);
   378   lens->
extrude(LPoint2(1, 1),   _curr_near_points[UpperRight], _curr_far_points[UpperRight]);
   379   lens->
extrude(LPoint2(-1, -1), _curr_near_points[LowerLeft],  _curr_far_points[LowerLeft]);
   380   lens->
extrude(LPoint2(1, -1),  _curr_near_points[LowerRight], _curr_far_points[LowerRight]);
   386   for (
size_t i = 0; i < 4; ++i) {
   387     LPoint4 ws_near = mvp.xform(_curr_near_points[i]);
   388     LPoint4 ws_far = mvp.xform(_curr_far_points[i]);
   389     _curr_near_points[i].set(ws_near.get_x(), ws_near.get_y(), ws_near.get_z());
   390     _curr_far_points[i].set(ws_far.get_x(), ws_far.get_y(), ws_far.get_z());
   394   compute_pssm_splits( transform, _pssm_distance / lens->
get_far(), light_vector );
   396   _update_collector.stop();
 void update(NodePath cam_node, const LVecBase3 &light_vector)
Updates the PSSM camera rig.
void reparent_to(NodePath parent)
Reparents the camera rig.
A base class for any number of different kinds of lenses, linear and otherwise.
~PSSMCameraRig()
Destructs the camera rig.
bool is_empty() const
Returns true if the NodePath contains no nodes.
PSSMCameraRig(size_t num_splits)
Constructs a new PSSM camera rig.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Lens * get_lens(int index=0) const
Returns a pointer to the particular Lens associated with this LensNode, or NULL if there is not yet a...
void set_near_far(PN_stdfloat near_distance, PN_stdfloat far_distance)
Simultaneously changes the near and far planes.
bool project(const LPoint3 &point3d, LPoint3 &point2d) const
Given a 3-d point in space, determine the 2-d point this maps to, in the range (-1,...
A lightweight class that represents a single element that may be timed and/or counted via stats.
set_film_size
Sets the horizontal size of the film without changing its shape.
set_film_offset
Sets the horizontal and vertical offset amounts of this Lens.
get_view_mat
Returns the direction in which the lens is facing.
PandaNode * node() const
Returns the referenced node of the path.
bool extrude(const LPoint2 &point2d, LPoint3 &near_point, LPoint3 &far_point) const
Given a 2-d point in the range (-1,1) in both dimensions, where (0,0) is the center of the lens and (...
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
NodePath get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns a NodePath representing the nth child of the referenced node.
get_far
Returns the position of the far plane (or cylinder, sphere, whatever).