1 #include "VoxelStepper.h" 2 3 4 5 using namespace SyntopiaCore::Math; 6 7 namespace SyntopiaCore { 8 namespace GLEngine { 9 VoxelStepper(Vector3f minPos,Vector3f maxPos,int steps)10 VoxelStepper::VoxelStepper(Vector3f minPos, Vector3f maxPos, int steps) 11 : steps(steps), minPos(minPos), maxPos(maxPos), size(( maxPos - minPos)/(double)steps) { 12 currentT = 0; 13 copy = false; 14 grid = new QList<Object3D*>[steps*steps*steps]; 15 for (int i = 0; i < steps*steps*steps; i++) grid[i] = QList<Object3D*>(); 16 }; 17 ~VoxelStepper()18 VoxelStepper::~VoxelStepper() { if (!copy) delete[] grid; }; 19 registerObject(Object3D * obj)20 void VoxelStepper::registerObject(Object3D* obj) { 21 // Simple method - check all cells intersecting the objects bounding boxes. 22 obj->prepareForRaytracing(); 23 Vector3f from; 24 Vector3f to; 25 obj->getBoundingBox(from,to); 26 from = from - minPos; 27 to = to - minPos; 28 29 int xStart = floor(from.x()/size.x()); 30 int xEnd = ceil(to.x()/size.x()); 31 int yStart = floor(from.y()/size.y()); 32 int yEnd = ceil(to.y()/size.y()); 33 int zStart = floor(from.z()/size.z()); 34 int zEnd = ceil(to.z()/size.z()); 35 if (xStart < 0) xStart = 0; 36 if (yStart < 0) yStart = 0; 37 if (zStart < 0) zStart = 0; 38 if (xEnd > (int)steps) xEnd = steps; 39 if (yEnd > (int)steps) yEnd = steps; 40 if (zEnd > (int)steps) zEnd = steps; 41 42 for (unsigned int x = xStart; x < (unsigned int)xEnd; x++) { 43 for (unsigned int y = yStart; y < (unsigned int)yEnd; y++) { 44 for (unsigned int z = zStart; z < (unsigned int)zEnd; z++) { 45 if (obj->intersectsAABB(minPos + Vector3f(size.x()*x,size.y()*y,size.z()*z),minPos + Vector3f(size.x()*(x+1),size.y()*(y+1),size.z()*(z+1)) )) { 46 grid[x+y*steps+z*steps*steps].append(obj); 47 } 48 } 49 } 50 } 51 52 } 53 setupRay(Vector3f pos,Vector3f dir,double & maxT)54 QList<Object3D*>* VoxelStepper::setupRay(Vector3f pos, Vector3f dir, double& maxT) { 55 this->pos = pos; 56 this->dir = dir; 57 58 currentT = 0; 59 60 const Vector3f ro = pos - minPos; 61 cx = floor(ro.x() / size.x()); 62 cy = floor(ro.y() / size.y()); 63 cz = floor(ro.z() / size.z()); 64 65 66 if ((cx < 0 || cx >= steps) || 67 (cy < 0 || cy >= steps) || 68 (cz < 0 || cz >= steps)) { 69 // we are outside grid. 70 // advance ray to inside grid. 71 bool found = false; 72 double p; 73 if (dir.x() > 0) { 74 p = (minPos.x()-pos.x())/dir.x(); 75 cx = 0; 76 } else { 77 p = (maxPos.x()-pos.x())/dir.x(); 78 cx = steps-1; 79 } 80 Vector3f v = pos + dir*p - minPos; 81 cy = floor(v.y() / size.y()); 82 cz = floor(v.z() / size.z()); 83 if ((cy >= 0 && cy < steps) && (cz >= 0 && cz < steps)) { 84 found = true; 85 pos = v+minPos; 86 } 87 88 if (!found) { 89 if (dir.y() > 0) { 90 p = (minPos.y()-pos.y())/dir.y(); 91 cy = 0; 92 } else { 93 p = (maxPos.y()-pos.y())/dir.y(); 94 cy = steps-1; 95 } 96 Vector3f v = pos + dir*p - minPos; 97 cx = floor(v.x() / size.x()); 98 cz = floor(v.z() / size.z()); 99 if ((cx >= 0 && cx < steps) && (cz >= 0 && cz < steps)) { 100 pos = v+minPos; 101 found = true; 102 } 103 } 104 105 if (!found) { 106 if (dir.z() > 0) { 107 p = (minPos.z()-pos.z())/dir.z(); 108 cz = 0; 109 } else { 110 p = (maxPos.z()-pos.z())/dir.z(); 111 cz = steps-1; 112 } 113 Vector3f v = pos + dir*p - minPos; 114 cx = floor(v.x() / size.x()); 115 cy = floor(v.y() / size.y()); 116 if ((cy >= 0 && cy < steps) && (cx >= 0 && cx < steps)) { 117 pos = v+minPos; 118 found = true; 119 } 120 } 121 122 currentT = p; 123 124 // We do not intersect grid. 125 if (!found) return nullptr; 126 } 127 128 stepX = (dir.x() > 0) ? 1 : -1; 129 stepY = (dir.y() > 0) ? 1 : -1; 130 stepZ = (dir.z() > 0) ? 1 : -1; 131 132 tDeltaX = stepX*size.x() / dir.x(); 133 tDeltaY = stepY*size.y() / dir.y(); 134 tDeltaZ = stepZ*size.z() / dir.z(); 135 136 Vector3f orv = pos- (minPos + Vector3f(size.x()*cx, size.y()*cy, size.z()*cz)); 137 tMaxX = stepX*orv.x()/dir.x(); 138 if (stepX>0) tMaxX = tDeltaX - tMaxX; 139 tMaxY = stepY*orv.y()/dir.y(); 140 if (stepY>0) tMaxY = tDeltaY - tMaxY; 141 tMaxZ = stepZ*orv.z()/dir.z(); 142 if (stepZ>0) tMaxZ = tDeltaZ - tMaxZ; 143 144 // Now pos is advanced properly. 145 // cx,cy,cz contains current cell. 146 QList<Object3D*>* list = &grid[cx+cy*steps+cz*steps*steps]; 147 148 if (list && (list->count() == 0)) { 149 list = advance(maxT); 150 } else { 151 maxT = currentT + minn(tMaxX, tMaxY, tMaxZ); 152 } 153 154 return list; 155 } 156 157 158 advance(double & maxT)159 QList<Object3D*>* VoxelStepper::advance(double& maxT) { 160 QList<Object3D*>* list = 0; 161 do { 162 if(tMaxX < tMaxY) { 163 if(tMaxX < tMaxZ) { 164 cx += stepX; 165 if (cx >= steps || cx < 0) return 0; 166 tMaxX = tMaxX + tDeltaX; 167 } else { 168 cz += stepZ; 169 if (cz >= steps || cz < 0) return 0; 170 tMaxZ = tMaxZ + tDeltaZ; 171 } 172 } else { 173 if(tMaxY < tMaxZ) { 174 cy += stepY; 175 if (cy >= steps || cy < 0) return 0; 176 tMaxY = tMaxY + tDeltaY; 177 } else { 178 cz += stepZ; 179 if (cz >= steps || cz < 0) return 0; 180 tMaxZ = tMaxZ + tDeltaZ; 181 } 182 } 183 list = &grid[cx+cy*steps+cz*steps*steps]; 184 185 if (list && (list->count() == 0)) list = 0; // Continue until we find an non-empty list. 186 } while(list == 0); 187 188 maxT = currentT + minn(tMaxX, tMaxY, tMaxZ); 189 return(list); 190 } 191 } 192 } 193 194