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