/* * Adapted from code copyright 2009-2010 NVIDIA Corporation * Modifications Copyright 2011, Blender Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __BVH_NODE_H__ #define __BVH_NODE_H__ #include "util/util_boundbox.h" #include "util/util_types.h" CCL_NAMESPACE_BEGIN enum BVH_STAT { BVH_STAT_NODE_COUNT, BVH_STAT_INNER_COUNT, BVH_STAT_LEAF_COUNT, BVH_STAT_TRIANGLE_COUNT, BVH_STAT_CHILDNODE_COUNT, BVH_STAT_ALIGNED_COUNT, BVH_STAT_UNALIGNED_COUNT, BVH_STAT_ALIGNED_INNER_COUNT, BVH_STAT_UNALIGNED_INNER_COUNT, BVH_STAT_ALIGNED_LEAF_COUNT, BVH_STAT_UNALIGNED_LEAF_COUNT, BVH_STAT_DEPTH, }; class BVHParams; class BVHNode { public: virtual ~BVHNode() { delete aligned_space; } virtual bool is_leaf() const = 0; virtual int num_children() const = 0; virtual BVHNode *get_child(int i) const = 0; virtual int num_triangles() const { return 0; } virtual void print(int depth = 0) const = 0; inline void set_aligned_space(const Transform &aligned_space) { is_unaligned = true; if (this->aligned_space == NULL) { this->aligned_space = new Transform(aligned_space); } else { *this->aligned_space = aligned_space; } } inline Transform get_aligned_space() const { if (aligned_space == NULL) { return transform_identity(); } return *aligned_space; } inline bool has_unaligned() const { if (is_leaf()) { return false; } for (int i = 0; i < num_children(); ++i) { if (get_child(i)->is_unaligned) { return true; } } return false; } // Subtree functions int getSubtreeSize(BVH_STAT stat = BVH_STAT_NODE_COUNT) const; float computeSubtreeSAHCost(const BVHParams &p, float probability = 1.0f) const; void deleteSubtree(); uint update_visibility(); void update_time(); /* Dump the content of the tree as a graphviz file. */ void dump_graph(const char *filename); // Properties. BoundBox bounds; uint visibility; bool is_unaligned; /* TODO(sergey): Can be stored as 3x3 matrix, but better to have some * utilities and type defines in util_transform first. */ Transform *aligned_space; float time_from, time_to; protected: explicit BVHNode(const BoundBox &bounds) : bounds(bounds), visibility(0), is_unaligned(false), aligned_space(NULL), time_from(0.0f), time_to(1.0f) { } explicit BVHNode(const BVHNode &other) : bounds(other.bounds), visibility(other.visibility), is_unaligned(other.is_unaligned), aligned_space(NULL), time_from(other.time_from), time_to(other.time_to) { if (other.aligned_space != NULL) { assert(other.is_unaligned); aligned_space = new Transform(); *aligned_space = *other.aligned_space; } else { assert(!other.is_unaligned); } } }; class InnerNode : public BVHNode { public: static constexpr int kNumMaxChildren = 8; InnerNode(const BoundBox &bounds, BVHNode *child0, BVHNode *child1) : BVHNode(bounds), num_children_(2) { children[0] = child0; children[1] = child1; reset_unused_children(); if (child0 && child1) { visibility = child0->visibility | child1->visibility; } else { /* Happens on build cancel. */ visibility = 0; } } InnerNode(const BoundBox &bounds, BVHNode **children, const int num_children) : BVHNode(bounds), num_children_(num_children) { visibility = 0; time_from = FLT_MAX; time_to = -FLT_MAX; for (int i = 0; i < num_children; ++i) { assert(children[i] != NULL); visibility |= children[i]->visibility; this->children[i] = children[i]; time_from = min(time_from, children[i]->time_from); time_to = max(time_to, children[i]->time_to); } reset_unused_children(); } /* NOTE: This function is only used during binary BVH builder, and it * supposed to be configured to have 2 children which will be filled-in in a * bit. But this is important to have children reset to NULL. */ explicit InnerNode(const BoundBox &bounds) : BVHNode(bounds), num_children_(0) { reset_unused_children(); visibility = 0; num_children_ = 2; } bool is_leaf() const { return false; } int num_children() const { return num_children_; } BVHNode *get_child(int i) const { assert(i >= 0 && i < num_children_); return children[i]; } void print(int depth) const; int num_children_; BVHNode *children[kNumMaxChildren]; protected: void reset_unused_children() { for (int i = num_children_; i < kNumMaxChildren; ++i) { children[i] = NULL; } } }; class LeafNode : public BVHNode { public: LeafNode(const BoundBox &bounds, uint visibility, int lo, int hi) : BVHNode(bounds), lo(lo), hi(hi) { this->bounds = bounds; this->visibility = visibility; } LeafNode(const LeafNode &other) : BVHNode(other), lo(other.lo), hi(other.hi) { } bool is_leaf() const { return true; } int num_children() const { return 0; } BVHNode *get_child(int) const { return NULL; } int num_triangles() const { return hi - lo; } void print(int depth) const; int lo; int hi; }; CCL_NAMESPACE_END #endif /* __BVH_NODE_H__ */