kick
|
00001 #include "kick/math/kd_tree.h" 00002 00003 #include <algorithm> 00004 #include <cmath> 00005 00006 using namespace std; 00007 using namespace glm; 00008 00009 namespace kick { 00010 KDTreeNodeRef::KDTreeNodeRef() 00011 :id(-1) { 00012 00013 } 00014 00015 KDTreeNodeRef::KDTreeNodeRef(const KDTreeNodeRef &other) 00016 :id(other.id){ 00017 for (int i=0;i<3;i++){ 00018 triangle[i] = other.triangle[i]; 00019 } 00020 } 00021 00022 AABB KDTreeNodeRef::getAABB() const { 00023 AABB res; 00024 for (int i=0;i<3;i++){ 00025 res.addPoint(triangle[i]); 00026 } 00027 return res; 00028 } 00029 00030 bool KDTreeNodeRef::intersectRay(const Ray &ray, KDTreeHitInfo &hit) const { 00031 vec3 intersectionPoint; 00032 bool res = ray.intersectTriangle(triangle[0], triangle[1], triangle[2], intersectionPoint); 00033 float len = length(intersectionPoint - ray.origin()); 00034 if (res && len < hit.distance){ 00035 hit.distance = len; 00036 hit.collisionPoint = intersectionPoint; 00037 hit.hit = this; 00038 } 00039 return res; 00040 } 00041 00042 00043 // ___________________________________________________ 00044 00045 KDTreeNode::KDTreeNode(const AABB &aabb) 00046 : leftChild(NULL), rightChild(NULL), aabb(aabb) { 00047 00048 } 00049 00050 bool KDTreeNode::isLeaf() { 00051 return leftChild == NULL && rightChild == NULL; 00052 } 00053 00054 // ___________________________________________________ 00055 00056 00057 KDTree::KDTree() 00058 : rootNode(NULL) { 00059 } 00060 00061 00062 KDTree::~KDTree(void) { 00063 } 00064 00065 void KDTree::init(std::vector<KDTreeNodeRef> &objectList, AABB &aabb) { 00066 this->objectList = objectList; 00067 this->aabb = aabb; 00068 this->rootNode = recursiveBuild(objectList, aabb, 0); 00069 } 00070 00071 bool KDTree::first_intersection(Ray &ray, KDTreeHitInfo& hit) { 00072 float tNear, tFar; 00073 int aNear, aFar; 00074 bool intersected = aabb.intersect(ray, tNear, tFar,aNear, aFar); 00075 if (!intersected) { 00076 return false; 00077 } 00078 00079 return intersect(this->rootNode, ray, hit, ray.origin()); 00080 00081 } 00082 00083 // returns true if it has collisions inside aabb 00084 bool KDTree::intersect(KDTreeNode *child, const Ray &ray, KDTreeHitInfo& hit, vec3 startPoint) { 00085 bool collision = false; 00086 if (child->isLeaf()) { 00087 for (auto& node : child->objects) { 00088 if (node.intersectRay(ray, hit)){ 00089 vec3 collisionPos = hit.collisionPoint; 00090 collision = child->aabb.contains(collisionPos); 00091 } 00092 } 00093 } else { 00094 float directionDelta = ray.direction()[child->splittingAxis]; 00095 00096 if (directionDelta < 0 && ray.origin()[child->splittingAxis] < child->splittingPlane) { 00097 // only consider left child 00098 collision = intersect(child->leftChild, ray, hit, startPoint); 00099 } else if (directionDelta > 0 && ray.origin()[child->splittingAxis] > child->splittingPlane) { 00100 // only consider right child 00101 collision = intersect(child->rightChild, ray, hit, startPoint); 00102 } else { 00103 // collision with splitting plane 00104 if (directionDelta > 0) { 00105 // if direction is from min to max (left to right) 00106 collision = intersect(child->leftChild, ray, hit, startPoint); 00107 if (!collision) { 00108 float fNear, fFar; 00109 int aNear, aFar; 00110 if (child->rightChild->aabb.intersect(ray, fNear, fFar,aNear, aFar)) { 00111 vec3 splitPlaneIntersect = ray.origin() + ray.direction() * fNear; 00112 Ray newRay{splitPlaneIntersect, ray.direction()}; 00113 collision = intersect(child->rightChild, newRay, hit, startPoint); 00114 } 00115 } 00116 } else { 00117 // if direction is from min to max (left to right) 00118 collision = intersect(child->rightChild, ray, hit, startPoint); 00119 if (!collision) { 00120 float fNear, fFar; 00121 int aNear, aFar; 00122 if (child->leftChild->aabb.intersect(ray, fNear, fFar,aNear, aFar)) { 00123 vec3 splitPlaneIntersect = ray.origin() + ray.direction() * fNear; 00124 Ray newRay{splitPlaneIntersect, ray.direction()}; 00125 collision = intersect(child->leftChild, newRay, hit, startPoint); 00126 } 00127 } 00128 } 00129 } 00130 } 00131 00132 return collision; 00133 } 00134 00135 KDTreeNode *KDTree::recursiveBuild(const std::vector<KDTreeNodeRef>& objectList, AABB &aabb, int currentDepth) { 00136 KDTreeNode *res = new KDTreeNode(aabb); 00137 if (terminateBuild(objectList, aabb, currentDepth)) { 00138 for (const KDTreeNodeRef & nodeRef : objectList) { 00139 res->objects.push_back(nodeRef); 00140 } 00141 return res; 00142 } 00143 findPlane(objectList, aabb, currentDepth, res); 00144 00145 // split aabb with splitting plane 00146 AABB leftAabb(aabb); 00147 leftAabb.max[res->splittingAxis] = res->splittingPlane; 00148 AABB rightAabb(aabb); 00149 rightAabb.min[res->splittingAxis] = res->splittingPlane; 00150 00151 vector < KDTreeNodeRef > leftObjects; 00152 vector < KDTreeNodeRef > rightObjects; 00153 for (const KDTreeNodeRef & nodeRef : objectList) { 00154 const AABB objectAABB = nodeRef.getAABB(); 00155 if (leftAabb.intersect(objectAABB)) { 00156 leftObjects.push_back(nodeRef); 00157 } 00158 if (rightAabb.intersect(objectAABB)) { 00159 rightObjects.push_back(nodeRef); 00160 } 00161 } 00162 currentDepth++; 00163 res->leftChild = recursiveBuild(leftObjects, leftAabb, currentDepth); 00164 res->rightChild = recursiveBuild(rightObjects, rightAabb, currentDepth); 00165 return res; 00166 } 00167 00168 KDTreeNaive::KDTreeNaive(int treeDepth, int minVoxelObjects) 00169 : KDTree(), treeDepth(treeDepth), minVoxelObjects(minVoxelObjects) { 00170 } 00171 00172 void KDTreeNaive::findPlane(const std::vector<KDTreeNodeRef>& objectList, AABB &aabb, int currentDepth, KDTreeNode *node) { 00173 int axis = 0; 00174 vec3 len = aabb.max - aabb.min; 00175 float maxLen = 0; 00176 for (int i = 0; i < 3; i++) { 00177 if (len[i] > maxLen) { 00178 maxLen = len[i]; 00179 axis = i; 00180 } 00181 } 00182 node->splittingAxis = axis; 00183 node->splittingPlane = 0.5f * (aabb.min[axis] + aabb.max[axis]); 00184 } 00185 00186 bool KDTreeNaive::terminateBuild(const std::vector<KDTreeNodeRef>& objectList, AABB &aabb, int currentDepth) { 00187 return currentDepth == this->treeDepth || objectList.size() < minVoxelObjects; 00188 } 00189 }