History

Ray tests for heightfield spanners.

Andrzej Kapolka committed 12 years ago

Commit b2ac33d1 parent 75e1cf86 files · +175 −184Browse files

Showing the changes to interface/src/MetavoxelSystem.cpp (1 of 6 files). Show all

Unified · Split

interface/src/MetavoxelSystem.cpp+3−179
@@ -171,185 +171,6 @@ void MetavoxelSystem::refreshVoxelData() { · 170 unmodified lines
171 }171 }
172}172}
173 173
174class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor {
175public:
176
177 float intersectionDistance;
178
179 RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod);
180
181 virtual int visit(MetavoxelInfo& info, float distance);
182};
183
184RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm::vec3& origin,
185 const glm::vec3& direction, const MetavoxelLOD& lod) :
186 RayIntersectionVisitor(origin, direction, QVector<AttributePointer>() <<
187 Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>(), lod),
188 intersectionDistance(FLT_MAX) {
189}
190
191static const int EIGHT_BIT_MAXIMUM = 255;
192static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM;
193
194int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
195 if (!info.isLeaf) {
196 return _order;
197 }
198 const HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(
199 info.inputValues.at(0).getInlineValue<BufferDataPointer>().data());
200 if (!buffer) {
201 return STOP_RECURSION;
202 }
203 const QByteArray& contents = buffer->getHeight();
204 const uchar* src = (const uchar*)contents.constData();
205 int size = glm::sqrt((float)contents.size());
206 int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION;
207 int highest = HeightfieldBuffer::HEIGHT_BORDER + unextendedSize;
208 float heightScale = unextendedSize * EIGHT_BIT_MAXIMUM_RECIPROCAL;
209
210 // find the initial location in heightfield coordinates
211 glm::vec3 entry = (_origin + distance * _direction - info.minimum) * (float)unextendedSize / info.size;
212 entry.x += HeightfieldBuffer::HEIGHT_BORDER;
213 entry.z += HeightfieldBuffer::HEIGHT_BORDER;
214 glm::vec3 floors = glm::floor(entry);
215 glm::vec3 ceils = glm::ceil(entry);
216 if (floors.x == ceils.x) {
217 if (_direction.x > 0.0f) {
218 ceils.x += 1.0f;
219 } else {
220 floors.x -= 1.0f;
221 }
222 }
223 if (floors.z == ceils.z) {
224 if (_direction.z > 0.0f) {
225 ceils.z += 1.0f;
226 } else {
227 floors.z -= 1.0f;
228 }
229 }
230
231 bool withinBounds = true;
232 float accumulatedDistance = 0.0f;
233 while (withinBounds) {
234 // find the heights at the corners of the current cell
235 int floorX = qMin(qMax((int)floors.x, HeightfieldBuffer::HEIGHT_BORDER), highest);
236 int floorZ = qMin(qMax((int)floors.z, HeightfieldBuffer::HEIGHT_BORDER), highest);
237 int ceilX = qMin(qMax((int)ceils.x, HeightfieldBuffer::HEIGHT_BORDER), highest);
238 int ceilZ = qMin(qMax((int)ceils.z, HeightfieldBuffer::HEIGHT_BORDER), highest);
239 float upperLeft = src[floorZ * size + floorX] * heightScale;
240 float upperRight = src[floorZ * size + ceilX] * heightScale;
241 float lowerLeft = src[ceilZ * size + floorX] * heightScale;
242 float lowerRight = src[ceilZ * size + ceilX] * heightScale;
243
244 // find the distance to the next x coordinate
245 float xDistance = FLT_MAX;
246 if (_direction.x > 0.0f) {
247 xDistance = (ceils.x - entry.x) / _direction.x;
248 } else if (_direction.x < 0.0f) {
249 xDistance = (floors.x - entry.x) / _direction.x;
250 }
251
252 // and the distance to the next z coordinate
253 float zDistance = FLT_MAX;
254 if (_direction.z > 0.0f) {
255 zDistance = (ceils.z - entry.z) / _direction.z;
256 } else if (_direction.z < 0.0f) {
257 zDistance = (floors.z - entry.z) / _direction.z;
258 }
259
260 // the exit distance is the lower of those two
261 float exitDistance = qMin(xDistance, zDistance);
262 glm::vec3 exit, nextFloors = floors, nextCeils = ceils;
263 if (exitDistance == FLT_MAX) {
264 if (_direction.y > 0.0f) {
265 return SHORT_CIRCUIT; // line points upwards; no collisions possible
266 }
267 withinBounds = false; // line points downwards; check this cell only
268
269 } else {
270 // find the exit point and the next cell, and determine whether it's still within the bounds
271 exit = entry + exitDistance * _direction;
272 withinBounds = (exit.y >= HeightfieldBuffer::HEIGHT_BORDER && exit.y <= highest);
273 if (exitDistance == xDistance) {
274 if (_direction.x > 0.0f) {
275 nextFloors.x += 1.0f;
276 withinBounds &= (nextCeils.x += 1.0f) <= highest;
277 } else {
278 withinBounds &= (nextFloors.x -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER;
279 nextCeils.x -= 1.0f;
280 }
281 }
282 if (exitDistance == zDistance) {
283 if (_direction.z > 0.0f) {
284 nextFloors.z += 1.0f;
285 withinBounds &= (nextCeils.z += 1.0f) <= highest;
286 } else {
287 withinBounds &= (nextFloors.z -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER;
288 nextCeils.z -= 1.0f;
289 }
290 }
291 // check the vertical range of the ray against the ranges of the cell heights
292 if (qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) ||
293 qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) {
294 entry = exit;
295 floors = nextFloors;
296 ceils = nextCeils;
297 accumulatedDistance += exitDistance;
298 continue;
299 }
300 }
301 // having passed the bounds check, we must check against the planes
302 glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z);
303
304 // first check the triangle including the Z+ segment
305 glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft);
306 float lowerProduct = glm::dot(lowerNormal, _direction);
307 if (lowerProduct < 0.0f) {
308 float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct;
309 glm::vec3 intersection = relativeEntry + planeDistance * _direction;
310 if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
311 intersection.z >= intersection.x) {
312 intersectionDistance = qMin(intersectionDistance, distance +
313 (accumulatedDistance + planeDistance) * (info.size / unextendedSize));
314 return SHORT_CIRCUIT;
315 }
316 }
317
318 // then the one with the X+ segment
319 glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight);
320 float upperProduct = glm::dot(upperNormal, _direction);
321 if (upperProduct < 0.0f) {
322 float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct;
323 glm::vec3 intersection = relativeEntry + planeDistance * _direction;
324 if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
325 intersection.x >= intersection.z) {
326 intersectionDistance = qMin(intersectionDistance, distance +
327 (accumulatedDistance + planeDistance) * (info.size / unextendedSize));
328 return SHORT_CIRCUIT;
329 }
330 }
331
332 // no joy; continue on our way
333 entry = exit;
334 floors = nextFloors;
335 ceils = nextCeils;
336 accumulatedDistance += exitDistance;
337 }
338
339 return STOP_RECURSION;
340}
341
342bool MetavoxelSystem::findFirstRayHeightfieldIntersection(const glm::vec3& origin,
343 const glm::vec3& direction, float& distance) {
344 RayHeightfieldIntersectionVisitor visitor(origin, direction, getLOD());
345 guideToAugmented(visitor);
346 if (visitor.intersectionDistance == FLT_MAX) {
347 return false;
348 }
349 distance = visitor.intersectionDistance;
350 return true;
351}
352
353class RayVoxelIntersectionVisitor : public RayIntersectionVisitor {174class RayVoxelIntersectionVisitor : public RayIntersectionVisitor {
354public:175public:
355 176
@@ -917,6 +738,9 @@ public: · 561 unmodified lines
917const int SPLAT_COUNT = 4;738const int SPLAT_COUNT = 4;
918const GLint SPLAT_TEXTURE_UNITS[] = { 3, 4, 5, 6 };739const GLint SPLAT_TEXTURE_UNITS[] = { 3, 4, 5, 6 };
919 740
741static const int EIGHT_BIT_MAXIMUM = 255;
742static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM;
743
920void HeightfieldBuffer::render(bool cursor) {744void HeightfieldBuffer::render(bool cursor) {
921 // initialize textures, etc. on first render745 // initialize textures, etc. on first render
922 if (_heightTextureID == 0) {746 if (_heightTextureID == 0) {